ThreadKeep is a web forum where people can create online forums. It's designed to be easy to use, and a special feature lets users easily pull out the most important information from other people's forums. This project was developed as a part of CVWO Assignment for the School of Computing, National University of Singapore (NUS).
This is the Go backend for ThreadKeep ⬢. For more information, please refer to this repository.
- Go server hosting
- PostgreSQL database management with go-prisma ORM.
- Docker and Google cloud for deployment
go
(This project is developed based ongo1.23.4 linux/amd64
.)PostgreSQL
database. For this project, you can host your PostgreSQL database locally (via docker) or using Neon database.Docker
(Optional) This is in case you want to build and run with docker. Make sure to add your.env
file before starting the server. Here is the example of.env
file.
PORT=8080
DATABASE_URL=[YOUR_POSTGRESQL_DB_URL]
JWT_SECRET_KEY=[YOUR_JWT_SECRET_KEY]
DATABASE_URL
: For this project, you can host your PostgreSQL database locally (via docker) or using Neon database.JWT_SECRET_KEY
: You can choose any string you wish to choose.
- Schema file prisma/schema.ts
- Generate database migration by running
go run github.com/steebchen/prisma-client-go db push
.
Make sure that you have created your .env
file before starting the server.
go mod download
go run cmd/tag/main.go // add tags to your database
go run cmd/server/main.go
To start the server, execute
docker build --network=host --tag thread-keep:latest .
To see a list of built containers, you can use the docker images
command. You would expect to see something like this.
REPOSITORY TAG IMAGE ID CREATED SIZE
thread-keep latest <id> i <time> <size>
To start the server, execute
docker run --env-file .env -d --name thread-keep -p 8080:8080 thread-keep:latest
If this server is settled properly, you would expect to find the message "Welcome to our api server!"
at http://localhost:8080/.
To see a list of running containers, you can use the docker ps
command. You would expect something like this.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
<id> thread-keep:latest "./main" 2 minutes ago Up 2 minutes 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp thread-keep
To stop the container, execute docker stop <id>
or docker stop thread-keep
. To remove the container, run docker rm thread-keep
.
This project used Google Cloud Platform (GCP) for deployment. Please follow the instruction from this link for more details. The current backend is deployed here.
This project use PostgreSQL database with Prisma ORM to simplify nitpicking database operation tasks such as database migration. The following ERD Diagram is generated by this link from this schema.
This database consists of mainly four tables: User
, Thread
, Tag
, and Comment
. The table below shows all relations between these tables.
Relationship | Type | Description |
---|---|---|
User and Thread |
One to Many | One user can post multiple threads |
User and Comment |
One to Many | One user can post multiple comments |
Thread and Comment |
One to Many | One thread consists of multiple comments |
Thread and Tag |
Many to Many | One thread consists of multiple tags, and one tag can be used in multiple threads. |
Likes |
One to One with User and Thread |
A table represents the Likes relation. |
Saved |
One to One with User and Thread |
A table represents the Saved relation. |
This project mainly use REST API to perform standard database functions. For GET endpoints, all input parameters are parsed as url parameters. For POST endpoints, the requests are handled based on JSON format. Make sure to include relevant headers: Content-Type: application/json
and Authorization: Bearer [JWT_TOKEN]
for protected endpoints.
All API responses are represented in the following format.
{
"payload": data | null (if error),
"messages": string,
"errorCode": int (refer to http.status)
}
- Handle all logics regarding user information.
- The
user
API endpoint does not require authorization header.
Method | Endpoint | Description | Input | data (If http.status = 200 ) |
---|---|---|---|---|
GET | /users |
List all users in this platform | None | []models.User with jwt_token set to "" |
POST | /users/create |
Create new user (Registeration) | name (string), password (string) |
[]models.User with generated token |
POST | /users/verify |
Handling user authentication (Sign in) | name (string), password (string) |
True | False |
- Handle all CRUD thread operations and thread reactions.
- Require JWT authorization header (
Authorization: Bearer [JWT_TOKEN]
)
Method | Endpoint | Description | Input | data (If http.status = 200 ) |
---|---|---|---|---|
GET | /threads |
List all threads based on user filter | (Optional) skip (int), max_per_page (int), name (string), tags (list of tagID ) |
[]models.Thread |
POST | /threads |
Obtain individual thread | threadID (string) |
models.Thread |
GET | /threads/count |
Count all threads | None | int |
POST | /threads/create |
Create new thread | title (string) content (string) user (models.User ) |
|
POST | /threads/update |
Update thread details | ThreadID (string) title (string) content (string) user (models.User ) |
models.Thread |
POST | /threads/delete |
delete individual thread | threadID (string) |
0 (Failed) | 1 (Success) |
GET | /threads/tags |
Get all tags | None | []models.Tag |
POST | /threads/tags |
Get all tags for individual thread | threadID |
[]models.Tag |
POST | /threads/reaction |
Handle all threads reaction | userID (string), threadID (string), reaction (ReactionType) |
0 (Failed) | 1 (Success) |
POST | /threads/reaction/isLike |
check if user with userID has liked the thread threadID or not. |
userID (string), threadID (string) |
True | False |
Thread reactions are handled with ReactionType
.
ReactionType | int |
---|---|
VIEW | 0 |
LIKE | 1 |
UNLIKE | 2 |
SAVED | 3 |
UNSAVE | 4 |
- Handle all CRUD comment operations.
- Require JWT authorization header (
Authorization: Bearer [JWT_TOKEN]
)
Method | Endpoint | Description | Input | data (If http.status = 200 ) |
---|---|---|---|---|
POST | /comments |
Obtain individual comment | commentID (string) |
models.Comment |
POST | /comments/create |
Create individual comment | content (string), user (models.User ) |
models.Comment |
POST | /comments/update |
Update individual comment | commentID (string), content (string), user (models.User ) |
models.Comment |
POST | /comments/delete |
Delete individual comment | commentID (string) |
0 (Failed) | 1 (Success) |