This is the Chingu Dashboard backend project. You can run the project locally or using Docker. Once you have cloned the repo locally, be sure to set your .env environment variables files
- if using the docker databases, and an external terminal, use these DATABASE_URL
# .env
DATABASE_URL=postgresql://chingu:chingu@localhost:5433/dashboard?schema=public
# .env.test
DATABASE_URL=postgresql://chingu:chingu@localhost:5434/dashboard?schema=public
# .env
DATABASE_URL={your database url}
PORT=8000
JWT_SECRET={can be any string}
AT_SECRET={can be any string}
RT_SECRET={can be any string}
BCRYPT_HASHING_ROUNDS=10
MJ_APIKEY_PRIVATE={check Important Resources page}
MJ_APIKEY_PUBLIC={check Important Resources page}
NODE_ENV=development
FRONTEND_URL=https://chingu-dashboard-git-dev-chingu-dashboard.vercel.app/
DISCORD_CLIENT_ID={check Important Resources page}
DISCORD_CLIENT_SECRET={check Important Resources page}
DISCORD_CALLBACK_URL=http://localhost:8000/api/v1/auth/discord/redirect
# .env.test
DATABASE_URL={your test database connection string}
NODE_ENV=test
If you don't have yarn installed, make sure to install it first. Some useful steps are available in the official Yarn documentation.
To install all the project's dependencies run the following command in the project root:
$ yarn install
Prisma IMPORTANT: If you're using the docker setup in this project, go to the docker section
To prepare the DB
# migrate db schema
$ yarn migrate
# seed db
$ yarn seed
# run Prisma Studio
$ yarn studio
Tip
It is recommended to use db push
to prototype your schema
# development
$ yarn start
# watch mode
$ yarn start:dev
# production mode
$ yarn start:prod
Important
To prepare the test database, run yarn push:test
or yarn push:test:docker
# all tests (unit and e2e for now)
$ yarn test
# unit tests
$ yarn test:unit
# e2e tests
$ yarn test:e2e
# integration tests
$ yarn test:int
# test coverage
$ yarn test:cov
If using the docker terminal the commands would be
# all tests (unit and e2e for now)
$ yarn test:docker
# unit tests
$ yarn test:unit:docker
# e2e tests
$ yarn test:e2e:docker
# integration tests
$ yarn test:int:docker
# test coverage
$ yarn test:cov:docker
By using Docker you can: spin up Postgres, the API & PGAdmin, as well as run prisma Studio and even tests. Start by installing Docker if you don't have it already (it may require a machine restart in order to finalize installation).
Open the Docker app and from the project's root you can run Docker in dev or testing mode using commands below:
# spin up dev Docker services (API, PGAdmin, Postgres DB)
$ yarn docker
Docker will run in detached mode, meaning it's effectively running in the background, however, you will need to use the various scripts inside the docker cli.
Once the services are spun up, go to your docker desktop, chingu-dashboard-be container, click into it and then locate the chingu-dashboard-be_api container.
Using the container actions, select 'Open in terminal'.
From here, type all the commands above.
Login with
chinguadmin@chingu.com
chingu5432
Right click Servers -> Register -> Server...
dev database
hostname: postgres
port: 5433
maintenance database: dashboard
username: chingu
password: chingu
test database
hostname: postgres-test
port: 5434
maintenance database: dashboard
username: chingu
password: chingu
Having spun up your Docker services and migrated + seeded your DB your services will be running on the following default ports:
- API:
8000
- Postgres:
5433
- PGAdmin:
4000
- Prisma Studio:
5555
If you want to manually check that the API is receiving incoming requests, you can perform a GET request on the health endpoint using a tool like Postman (or another tool of your choice).
To stop and tear down the Docker services:
# tear down all Docker services but retain volumes
$ yarn docker:down
# tear down Docker services and remove all volumes
$ yarn docker:clean
For use with form responses, this pipe validates that the responses or response (array) values include a questionId and at least one input value of any type.
Example: @Body(new FormInputValidationPipe())
It checks the voyageTeamMemberId in the request body and validates if the logged in user belongs to that team.
Example: @Body(VoyageTeamMemberValidationPipe)
Marks the route as public, bypassing the JWT auth guard (jwtAuthGuard
)
Examples:
@Public()
Marks the route as accessible to users that have not verified thier account by email
This accepts 2 arguments -
action: Manage, Create, Read, Update, Delete, etc
subject: 'User', 'Voyage' - these are prisma models
- Actions, and abilites are defined in the CASL factory
src/ability/ability.factory/ability.factory.ts
, where the subjects are defined inprisma-generated-types.ts
- Manage, and 'all' are wildcards
- They also accept arrays like
action: [Action.Read, Action.Update]
Examples:
@CheckAbilities({ action: Action.Manage, subject: "all" })
- when a route is marked with this,
only users with the ability to manage 'all' subjects are allowed to access to route,
otherwise, a 403 forbidden error is returned.
@CheckAbilities({ action: Action.Read, subject: "VoyageTeam" })
- users with Read ability for VoyageTeam
subject can access this route.
Note: A try-catch block is not required to catch these exceptions
This filter catches all prisma generated exceptions with type PrismaClientKnownRequestError
and handle them
This filter catches all ForbiddenError
from @casl/ability
These guards are applied to every route in the app
This guard checks user access based on the passport strategy 'jwt-at', which extracts cookies from the request body, validates the user in the database and attaches additional user information in req.user
It also checks if the @public()
is applied to the route, if yes, user access check is bypassed
This guard defines and checks required permissions to access the route, it checks if the user has the required permission based on user roles.
Permissions based on roles are defined in the CASL ability factory (ability.factory.ts
)
This guard is only used for the refresh access token route, /refresh
, using passport 'jwt-refresh' strategy
This guard is only used for the /login
route, using the passport 'local' strategy