Development -- uses nodemon to automatically restart the server when changes are made
# copy `.env.example` to `.env` and change values accordingly
$ cp .env.example .env
# start the app
$ pnpm dev
# to stop everything, ctrl+c then run:
$ docker compose down
Production
# copy `.env.example` to `.env` and change values accordingly
$ cp .env.example .env
# start everything
$ docker compose up -d
# stop everything
$ docker compose down
# copy `.env.example` to `.env` and change values accordingly
$ cp .env.example .env
# install external dependencies
$ pnpm install
# run database migrations
$ dbmate up
# run app
$ node src/index.js # runs the app on default port (3000)
$ PORT=8000 node src/index.js # runs the app on port 8000
Important
The following constraints exist and are enforced on various fields:
User:
- password MUST be AT LEAST 5 characters
- email MUST be AT MOST 255 characters
- first, last name MUST be AT MOST 80 characters each
Club Day:
- starts_at MUST COME BEFORE ends_at
- ends_at MUST come AFTER the current time
- the range from starts_at to ends_at MUST NOT OVERLP with another range
requests
- Anywhere "Authorization" is present it refers to the http header of the same name
- Omit<A, '',...> submit the object of the corresponding type but leave out specified information
type ISOTimestamp = string;
type Token = string;
type QRToken = string;
type User = {
id: number;
firstName: string;
lastName: string;
email: string;
isAdmin: boolean; // default false
}
type ClubDay = {
id: number;
startsAt: ISOTimestamp;
endsAt: ISOTimestamp;
clubId: number;
}
type CheckIn = {
id: number;
userID: number;
clubDayID: number;
checkedInAt: ISOString;
}
Request
POST /sign-up
Content-Type: application/json
{
fisetName: string.
lastName: string,
email: string,
password: string
}
Response
200 OK
Content-Type: application/json
{token: Token}
Request
POST /login
Content-Type: application/json
{email: string; password: string}
Response
200 OK
Content-Type: application/json
{token: Token}
Note
All of these routes require authentication, and the user to be a service admin (isAdmin=true
) or and admin of the club.
Request
GET /clubs/<id>/club-days
Authorization: Token
parameter
Response
200 OK
Content-Type: application/json
ClubDay[]
Request
POST /clubs/<id>/club-days
Authorization: Token
Content-Type: application/json
Omit<ClubDay, 'id'>
Response
200 OK
Content-Type: application/json
ClubDay
Request
GET /clubs/<club id>/club-days/<club day id>
Authorization: Token
Response
200 OK
Content-Type: application/json
ClubDay
Request
GET /clubs/<club id>/club-days/<club day id/attendees
Authorization: Token
Response
200 OK
Content-Type: application/json
User[]
Request
DELETE /clubs/<club id>/club-days/<club day id>
Authorization: Token
Response
200 OK
Content-Type: application/json
ClubDay
Request
GET /clubs/<club id>/club-days/<club day id>/qr-token
Authorization: Token
Response
200 OK
Content-Type: application/json
{token: QRToken}
Request
GET /clubs/<club id>/club-days/<club day id>/qr-token.png
Authorization: Token
Response
200 OK
Content-Type: image/png
NOTE: this is currently broken
Request
GET /clubs/<club id>/club-days/<club day id>/qr-token.svg
Authorization: Token
Response
200 OK
Content-Type: image/svg+xml
Request
POST /check-in
Authorization: Token
Content-Type: application/json
{code: QRToken}
Response
204 No Content
Request
GET /check-code/<QRToken>
Response
200 OK
Content-Type: application/json
{name: string}
Request
POST /check-code/<QRToken>
Authorization: Token
Response
200 OK
Content-Type: application/json
{checkedIn: boolean}
Request
GET /user
Authorization: Token
Response
200 OK
Content-Type: application/json
User
Request
GET /users
Authorization: Token (requires isAdmin=true)
Response
200 OK
Content-Type: application/json
[User]
Request
POST /users/search
Authorization: Token
Content-Type: application/json
{querey: string} (space seperated list of words to search)
Response
200 OK
Content-Type: application/json
[User]
Request
PATCH /users/<id>
Authorization: Token (requires isAdmin=true)
Content-Type: application/json
{service_admin: boolean}
Response
204 No Content
Content-Type: application/json
User
Note
All of these routes require authentication, and the user to be a service admin (isAdmin=true
) or and admin of the club.
note: service admins are automaticly admin of all clubs Request
GET /clubs
Authorization: Token
Response
200 OK
Content-Type: application/json
[{id:number , name: string}]
note: service admins are automaticly admin of all clubs Request
GET /clubs/<id>/admins
Authorization: Token
Response
200 OK
Content-Type: application/json
[Users]
Request
POST /clubs/<id>/admins
Authorization: Token
Content-Type: application/json
{userId: number, clubId: number}
Response
200 OK
Content-Type: application/json
{userId: number, clubId: number, isAdmin: boolean}
Request
DELETE /clubs/<club id>/admins/<user id>
Authorization: Token
Content-Type: application/json
{userId: number, clubId: number}
Response
200 OK
Content-Type: application/json
{userId: number, clubId: number, isAdmin: boolean}
Request
POST /clubs
Authorization: Token
Content-Type: application/json
{name: string}
Note: the user must be a service admin
Response
200 OK
Content-Type: application/json
{id: number, name: string}
Request
DELETE /clubs/<id>
Authorization: Token
Note: user must be a service admin
Response
200 OK
Content-Type: application/json
{id: number, name: string}
A 200 error is the success code. This means the request completed successfully.
204 is another success code. It is used when the operation was successful, but there is no data to be returned.
A 400 error means bad the server received bad input. The error format will be one of the following:
// Form validation error (ex: login, sign up, create club day)
{
type: 'validation_arror',
issues: [
name: string[], // which form field the error came from
errors: string[] // the reason validation failed
]
}
// Non validation error
{
message: string // the error message
}
401 unauthorized is given when the supplied token is invalid. If you receive a 401 status code from any request, assume your token expired, and force the user to log back in (through a request to log in).
Getting a 403 forbidden status code means the user tried to access a resource they don't have access to. This is most likely a result of a non-admin user trying to access an admin-only resource.
A 404 status code means the resource does not exist.
A 409 error means the resource already exists. An example of this being used is trying to register an account for an email that already has an account.
500 errors should not happen. If one happens, that means there is an unhandled error somewhere in the API.