SavePoints is a social platform for gamers to share reviews and ratings on their favorite games while discovering new games through community recommendations.
Before you can start developing with SavePoints, you'll need to make sure you have the following installed on your system:
To get starting with development, follow these steps:
1. Clone the repository using Git:
git clone https://github.com/Save-Points/SavePoints.gitYou may need to generate a personal access token through GitHub to clone via HTTPS.
2. Navigate to the root of the project and install the required dependencies:
npm install3. Configure .env file:
Copy the .env.sample file into a new file called .env and configure the variables as needed
4. Setup the PostgreSQL database:
npm run setup5. Running the server:
After you are ready to run the server to test your code, run the command:
npm run startDescription: Create new user account. On success, logs the user in to the newly created account and sets auth token in their cookies.
Request Body:
{
"username": "user",
"password": "password"
}Responses:
201 Created
No body is returned, generated auth token is set in user's cookies.
400 Bad Request - Input validation failed.
{
"error": "Invalid input.",
"fields": {
"email": "Invalid email format.",
"username": "Username must be 4-20 characters. Allowed characters are letters, numbers, dots, underscores, and hyphens.",
"password": "Password must be at least 8 characters.",
"birthdate": "You must be at least 13 years old to create an account."
}
}500 Internal Server Error - Server failure (hashing, insert to database, or auth token creation)
{
"error": "Internal server error."
}Description: Log in to an existing user account. On success, sets auth token in the user's cookies.
Body:
{
"username": "user",
"password": "password"
}Responses:
200 OK
No body is returned, generated auth token is set in user's cookies.
400 Bad Request - Input validation failed.
{
"error": "Invalid input."
}401 Unauthorized - Invalid credentials provided.
{
"error": "Invalid username or password."
}500 Internal Server Error - Server failure (querying database or auth token creation)
{
"error": "Internal server error."
}Description: Log out of current authorized user account. On success, revokes the auth token in server database and clears the token from user's cookies.
Request Body:
None
Request Cookies::
token - authentication token
Responses:
200 OK
No body is returned, auth token is cleared in user's cookies and revoked in server database.
401 Unauthorized - No auth token found.
{
"error": "No token provided."
}403 Forbidden - Auth token is invalid or expired.
{
"error": "Forbidden."
}
**500 Internal Server Error** - Server failure (revoking token)
```json
{
"error": "Internal server error."
}Description: Searches IGDB for games based on the provided search term.
Body:
{
"searchTerm": "miku"
}Responses:
200 OK
{
"id": 202864,
"cover": {
"id": 223804,
"url": "//images.igdb.com/igdb/image/upload/t_thumb/co4sos.jpg"
},
"name": "Hatsune Miku: Project Diva Mega Mix+"
}400 Bad Request - Missing search term.
{
"error": "Search term is required"
}500 Internal Server Error - Server failure (querying IGDB)
{
"error": "Error querying IGDB"
}503 Service Unvailable - Access token expiration
{
"error": "Please try again"
}Description: Queries IGDB for specific based on the queried game ID.
Path Parameters:
id - The ID of the game to fetch.
Body:
None
Responses:
200 OK
{
"id": 202864,
"aggregated_rating": 80,
"cover": {
"id": 223804,
"url": "//images.igdb.com/igdb/image/upload/t_thumb/co4sos.jpg"
},
"first_release_date": 1653523200,
"genres": [
{
"id": 7,
"name": "Music"
},
{
"id": 33,
"name": "Arcade"
}
],
"name": "Hatsune Miku: Project Diva Mega Mix+",
"platforms": [
{
"id": 6,
"name": "PC (Microsoft Windows)"
}
],
"summary": "Take center stage in Hatsune Miku’s premier rhythm game starring the world’s #1 virtual pop star herself. From a stunner setlist of songs to an enormous wardrobe to style, it’s the ultimate tour with Miku and friends—all it needs is you."
}500 Internal Server Error - Server failure (querying IGDB)
{
"error": "Error querying IGDB"
}503 Service Unvailable - Access token expiration
{
"error": "Please try again"
}Description: Searches for users whose usernames that start with provided search term. The search is case-insensitive and returns up to 50 results.
Query Parameters:
term - The term to search for.
Body:
None
Responses:
200 OK
{
"body": [
{
"id": 1,
"username": "test",
"profile_pic_url": null
},
{
"id": 2,
"username": "test2",
"profile_pic_url": null
}
]
}400 Bad Request - Missing search term.
{
"error": "No search term provided."
}500 Internal Server Error - Server failure (querying databases)
{
"error": "Internal server error."
}Description: Updates the profile picture and bio for the currently logged-in user.
Auth: Required (Cookie)
Request Body:
{
"profile_pic_url": "/images/default_profile_pic.jpg",
"bio": "My new bio."
}Responses:
200 OK
{
"username": "test",
"profile_pic_url": null
}500 Internal Server Error
{
"error": "Internal server error."
}Description: Get current authenticated user.
Request Cookies::
token - authentication token
Responses:
200 OK
{
"username": "test",
"profile_pic_url": null
}401 Unauthorized - No auth token found.
{
"error": "No token provided."
}403 Forbidden - Auth token is invalid or expired.
{
"error": "Forbidden."
}
**404 Not Found**
```json
{
"error": "User not found."
}500 Internal Server Error
{
"error": "Internal server error."
}Description: Add a game to the authenticated user's game list.
Request Cookies::
token - authentication token
Body:
{
"gameId": 120278,
"rating": 10,
"status": "playing",
"favorited": true,
"hoursPlayed": 50
}Responses:
201 Created
No body is returned, game is added to user list.
400 Bad Request - Game already in user list.
{
"error": "Game already in list."
}401 Unauthorized - No auth token found.
{
"error": "No token provided."
}403 Forbidden - Auth token is invalid or expired.
{
"error": "Forbidden."
}500 Internal Server Error
{
"error": "Internal server error."
}Description: Get the game list for a specific user.
Path Parameters:
username - The username of the user whose game list to fetch.
Body:
None
Responses:
200 OK
{
[
{
"game_id": 120278,
"rating": 10,
"status": "playing",
"favorited": true,
"hours_played": 50
}
]
}404 Not Found - User not found.
{
"error": "User not found."
}500 Internal Server Error
{
"error": "Internal server error."
}| Column | Type | Default | Nullable | Description |
|---|---|---|---|---|
| id | SERIAL PK | No | User ID | |
| username | VARCHAR(20) | No | Unique username | |
| password | VARCHAR(255) | No | Hashed password | |
| VARCHAR(255) | No | Unique email | ||
| created_at | TIMESTAMP | CURRENT_TIMESTAMP | No | Created at timestamp |
| updated_at | TIMESTAMP | CURRENT_TIMESTAMP | No | Last updated timestamp |
| birthdate | DATE | NULL | Yes | User birthdate |
| bio | TEXT | NULL | Yes | User biography |
| privacy | privacy_type | 'public' | No | User privacy setting |
| profile_pic_url | TEXT | NULL | Yes | URL of profile picture |
| verified | BOOLEAN | false | No | Email verification status |
| is_admin | BOOLEAN | false | No | Admin flag |
| Column | Type | Default | Nullable | Description |
|---|---|---|---|---|
| id | SERIAL PK | No | Token ID | |
| user_id | INT | No | Owner of token, references users(id) |
|
| token | VARCHAR(64) | No | Auth token | |
| created_at | TIMESTAMP | CURRENT_TIMESTAMP | No | Created at timestamp |
| expires_at | TIMESTAMP | CURRENT_TIMESTAMP + INTERVAL '7 days' | No | Expires at timestamp (created_at + 7 days) |
| revoked | BOOLEAN | false | No | Revoked status of token |
| Column | Type | Default | Nullable | Description |
|---|---|---|---|---|
| user_id | INT PK | No | User ID, references users(id) |
|
| game_id | INT PK | No | IGDB Game ID | |
| rating | NUMERIC(4, 2) | NULL | Yes | User rating of the game |
| created_at | TIMESTAMP | CURRENT_TIMESTAMP + INTERVAL '7 days' | No | Created at timestamp |
| updated_at | TIMESTAMP | NULL | Yes | Updated at timestamp |
| status | user_game_status | 'planned' | No | User game status |
| favorited | BOOLEAN | false | No | Whether the game is favorited by the user |
| hours_played | INT | 0 | No | Number of hours played |
sequenceDiagram
participant U as User
participant S as Server
participant DB as Database
U->>S: POST /auth/create (username, password)
S->>S: Validate inputs, hash password with argon2
S->>DB: INSERT INTO users (username, password) RETURNING id
DB->>S: id
S->>S: Generate authentication token
S->>DB: INSERT INTO auth_tokens (user_id, token)
DB-->>S: INSERT successful
S-->>U: Set authentication token in cookies
sequenceDiagram
participant U as User
participant S as Server
participant DB as Database
U->>S: POST /auth/login (username, password)
S->>S: Validate inputs
S->>DB: SELECT id, password FROM users WHERE username = ?
DB->>S: id, password
S->>S: Verify input password to actual password with argon2
alt password correct
S->>S: Generate authentication token
S->>DB: INSERT INTO auth_tokens (user_id, token)
DB-->>S: INSERT successful
S-->>U: Set authentication token in cookies\
else password incorrect
S-->>U: 401 Unauthorized
end