Skip to content

Commit

Permalink
docs: update readmes (bloom-housing#4410)
Browse files Browse the repository at this point in the history
  • Loading branch information
emilyjablonski committed Dec 2, 2024
1 parent 0fb58bd commit 9a6ffb5
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 179 deletions.
90 changes: 43 additions & 47 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion api/.env.template
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ GOOGLE_API_KEY=
# cloudinary secret
CLOUDINARY_SECRET=
# app secret
APP_SECRET=
APP_SECRET="some-long-secret-key"
# url for the proxy
PROXY_URL=
# the node env the app should be running as
Expand Down
183 changes: 102 additions & 81 deletions api/README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,59 @@
# Setup
# Bloom Backend

![TypeScript](https://img.shields.io/badge/typescript-%23007ACC.svg?style=for-the-badge&logo=typescript&logoColor=white) ![NestJS](https://img.shields.io/badge/nestjs-%23E0234E.svg?style=for-the-badge&logo=nestjs&logoColor=white) ![Prisma](https://img.shields.io/badge/Prisma-3982CE?style=for-the-badge&logo=Prisma&logoColor=white) ![Postgres](https://img.shields.io/badge/postgres-%23316192.svg?style=for-the-badge&logo=postgresql&logoColor=white)

## Overview

This is the backend services container. Data is stored in a [Postgres](https://www.postgresql.org/) database and served over HTTPS to the frontend (either at build time for things that can be server-rendered, otherwise at run time). Most services are part of a [NestJS](https://nestjs.com/) application. [Prisma](https://www.prisma.io/) is the application's ORM. [OpenAPI Swagger](https://swagger.io/tools/swagger-ui/) documentation is automatically generated by the server at http://localhost:3100/api/ in local development environments, or in any other environment by adding `/api` to the api URL. This can be helpful to get a more visual overview of all available endpoints.

## Installation
Make sure the .env file's db placement is what works for your set up, Then run the following:

```bash
$ yarn install
$ yarn prisma generate
$ yarn build
$ yarn db:setup:staging
```
The following commands are for macOS / Linux, but you can find equivalent instructions for Windows machines online.

### Environment Variables

Configuration of the backend is pulled from environment variables defined in an `.env` file in the api directory. Copy the `.env.template` file in api into a `.env` file. Some keys are secret and are internally available. The template file includes default values and descriptions of each variable.

### Dependencies

If you don't have yarn installed, you can install homebrew with [these instructions](https://brew.sh/) and then do so with `brew install yarn`.

#### Installing Node

We are currently using Node version 18. You can install Node using homebrew with the following command: `brew install node@18`.

If you have multiple versions of Node installed, you can use [nvm](https://github.com/nvm-sh/nvm) (node version manager), or other similar tools, to switch between them. Ensure you're on the right version by checking with `node -v`.

If along the way you get `env: node: No such file or directory`, inspect the output from installing node for instructions on if you might need to add node to certain terminal paths.

#### Installing Postgresql

You can install Postgres using homebrew with the following command: `brew install postgresql@15`. You then start it with `brew services start postgresql@15`.

#### Project dependencies

Install project dependencies with `yarn install` from within the api directory.

## Starting locally

These commands are also encapsulated in:
```bash
$ yarn setup
```
The following command will generate and build the Prisma schema and setup the database with seeded data: `yarn setup:dev`.

If you would prefer to have it setup with more realistic data you can instead run: `yarn setup`.

If you would prefer to have it setup with more realistic data you can run `yarn db:setup:staging` instead of `yarn db:setup`.
If this is your first time running this command and you see `psql: error: FATAL: database "<username>" does not exist` you may need to run `createdb <username>` first.

## Starting the application
In order to run the application you can run :
```bash
$ yarn start
```
You will also need to update the `DATABASE_URL` environment variable to include your username.

or to run in watch mode run:
```bash
$ yarn dev
```
If you're using VSCode, you can install [the Postgres explorer extension](https://marketplace.visualstudio.com/items?itemName=ckolkman.vscode-postgres) to inspect your local database. When you click on the + to create a new connection, you can use the following inputs to each question to create a connection to the newly created database: `localhost`, `<username>`, hit enter for password, `5432`, standard, `bloom_prisma`, and a descriptive name like `local-bloom`. Once the connection is established, you can inspect the database.

# Modifying the Schema
To start the application run: `yarn dev`.

## Modifying the Schema

If you're using VSCode, you can install the [Prisma extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) to add syntax highlighting and formatting to Prisma schema files.

To modify the Prisma schema you will need to work with the <b>schema.prisma</b> file. This file controls the following:

We use [Prisma](https://www.prisma.io/) as the ORM. To modify the schema you will need to work with the <b>schema.prisma</b> file. This file controls the following:
<ol>
<li> The Structure of each model (entity if you are more familiar with TypeORM) </li>
<li> The Relationships between models </li>
Expand All @@ -39,131 +62,129 @@ We use [Prisma](https://www.prisma.io/) as the ORM. To modify the schema you wil
</ol>

You will need to:

1. Add the field in the DTO
2. Run `yarn generate:client` to add the type to the swagger file
3. Manually add the field to `schema.prisma`
4. Run `yarn prisma migrate dev --name <name of migration>` to create the migration file

### Conventions

## Conventions
We use the following conventions:

<ul>
<li> model and enum names are capitalized camelcased (e.g. HelloWorld) </li>
<li> model and enum names are <b>@@map()</b>ed to lowercase snakecased (e.g. hello_world) </li>
<li> a model's fields are lowercase camelcased (e.g. helloWorld) </li>
<li> a model's fields are <b>@map()</b>ed to lowercase snackcased (e.g. hello_world) </li>
<li> model and enum names are capitalized camel case (e.g. HelloWorld) </li>
<li> model and enum names are <b>@@map()</b>ed to lowercase snake case (e.g. hello_world) </li>
<li> a model's fields are lowercase camel case (e.g. helloWorld) </li>
<li> a model's fields are <b>@map()</b>ed to lowercase snake case (e.g. hello_world) </li>
</ul>
This is to make the api easier to work with, and to respect postgres's name space conventions.
<p></p>

# Controllers
Controllers are where backend endpoints are housed. They follow the [Nestjs standards](https://docs.nestjs.com/controllers)
## Controllers

They are housed under `/src/controllers`.
Backend endpoints live in controllers under `src/controllers`. They follow the [NestJs standards](https://docs.nestjs.com/controllers)

## Conventions
Controllers are given the extension `.contoller.ts` and the model name (listing, application, etc) is singular. So for example `listing.controller.ts`.
### Conventions

The exported class should be in capitalized camelcase (e.g. `ListingController`).
Controllers are given the extension `.controller.ts` and the model name (listing, application, etc) is singular. So for example `listing.controller.ts`.

# DTOs
Data Transfer Objects. These are how we flag what fields endpoints will take in, and what the form of the response from the backend will be.
The exported class should be in capitalized camel case (e.g. `ListingController`).

## DTOs

DTOs (Data Transfer Objects) are how we flag what fields endpoints will take in, and what the form of the response from the backend will be.

We use the packages [class-transformer](https://www.npmjs.com/package/class-transformer) & [class-validator](https://www.npmjs.com/package/class-validator) for this.

They are housed under `src/dtos`, and are broken up by what model they are related too. There are also shared DTOs which are housed under the shared sub-directory.
DTOs are stored under `src/dtos`, and are broken up by what model they are related to. There are also shared DTOs which are stored under the shared sub-directory.

## Conventions
DTOs are given the extension `.dto.ts` and the file name is lowercase kebabcase.
### Conventions

So for example `listings-filter-params.dto.ts`.
DTOs are given the extension `.dto.ts` and the file name is lowercase kebab case (e.g. `listings-filter-params.dto.ts`).

The exported class should be in capitalized camelcase (e.g. `ListingFilterParams`) and does not include the DTO as a suffix.
The exported class should be in capitalized camel case (e.g. `ListingFilterParams`) and does not include the DTO as a suffix.

# Enums
These are enums used by NestJs primarily for either taking in a request or sending out a response. Database enums (enums from Prisma) are part of the primsa schema and are not housed here.
## Enums

They are housed under `src/enums` and the file name is lowercase kebabcase and end with `-enum.ts`.
These are enums used by NestJs primarily for either taking in a request or sending out a response. Database enums (enums from Prisma) are part of the Prisma schema and are not housed here.

They are housed under `src/enums` and the file name is lowercase kebab case and end with `-enum.ts`.

So for example `filter-key-enum.ts`.

## Conventions
The exported enum should be in capitalized camelcase (e.g. `ListingFilterKeys`).
### Conventions

The exported enum should be in capitalized camel case (e.g. `ListingFilterKeys`).

## Modules

# Modules
Modules connect the controllers to services and follow [NestJS standards](https://docs.nestjs.com/modules).

## Conventions
### Conventions

Modules are housed under `src/modules` and are given the extension `.module.ts`. The model name (listing, application, etc) is singular. So for example `listing.module.ts`.

The exported class should be in capitalized camelcase (e.g. `ListingModule`).
The exported class should be in capitalized camel case (e.g. `ListingModule`).

# Services
Services are where business logic is performed as well as interfacing with the database.
## Services

Services are where business logic is performed as well as interfacing with the database.

Controllers should be calling functions in services in order to do their work.

The follow the [NestJS standards](https://docs.nestjs.com/providers).

## Conventions
### Conventions

Services are housed under `src/services` and are given the extension `.services.ts`. The model name (listing, application, etc) is singular. So for example `listing.service.ts`.

The exported class should be in capitalized camelcase (e.g. `ListingService`).
The exported class should be in capitalized camel case (e.g. `ListingService`).

## Guards & Passport Strategies

# Guards & Passport Strategies
We currently use guards for 2 purposes. Passport guards and Permissioning guards.

Passport guards (jwt.guard.ts, mfa.guard.ts, and optional.guard.ts) verify that the request is from a legitimate user. JwtAuthGuard does this by verifying the incoming jwt token (off the request's cookies) matches a user. MfaAuthGuard does this by verifying the incoming login information (email, password, mfaCode) matches a user's information. OptionalAuthGuard is used to allow requests from users not logged in through. It will still verify the user through the JwtAuthGuard if a user was logged in.

Passport guards are paired with a passport strategy (jwt.strategy.ts, and mfa.strategy.ts), this is where the code to actually verify the requester lives.
Passport guards are paired with a passport strategy (jwt.strategy.ts, and mfa.strategy.ts), this is where the code to actually verify the requester lives.

Hopefully that makes sense, if not think of guards as customs agents, and the passport strategy is what the guards look for in a request to allow entry to a requester. Allowing them access the endpoint that the guard protects.
Hopefully that makes sense, if not think of guards as customs agents, and the passport strategy is what the guards look for in a request to allow entry to a requester. Allowing them access the endpoint that the guard protects.

[NestJS passport docs](https://docs.nestjs.com/recipes/passport)
[NestJS guards docs](https://docs.nestjs.com/guards)

Permissioning guards (permission.guard.ts, and user-profile-permission-guard.ts) verify that the requester has access to the resource and action they are trying to perform. For example a user that is not logged in (anonymous user) can submit applications, but cannot create listings. We leverage [Casbin](https://www.npmjs.com/package/casbin) to do user verification.
Permissioning guards (permission.guard.ts, and user-profile-permission-guard.ts) verify that the requester has access to the resource and action they are trying to perform. For example a user that is not logged in (anonymous user) can submit applications, but cannot create listings. We leverage [Casbin](https://www.npmjs.com/package/casbin) to do user verification.

## Testing

# Testing
There are 2 different kinds of tests that the backend supports: Integration tests and Unit tests.

Integration Tests are tests that DO interface with the database, reading/writing/updating/deleting data from that database.
Integration Tests are tests that DO interface with the database, reading/writing/updating/deleting data from that database.

Unit Tests are tests that MOCK interaction with the database, or test functionality directly that does not interact with the database.

### Integration Testing

## Integration Testing
Integration Tests are housed under `test/integration`, and files are given the extension `.e2e-spec.ts`.

These tests will generally test going through the controller's endpoints and will mock as little as possible. When testing the database should start off as empty and should be reset to empty once tests are completed (i.e. data is cleaned up).

## How to run integration tests
Running the following will run all integration tests:
```bash
$ yarn test:e2e
```
#### How to run integration tests

Running the following will run all integration tests `yarn test:e2e`.

### Unit Testing

## Unit Testing
Unit Tests are housed under `test/unit`, and files are given the extension `.spec.ts`.

These tests will generally test the functions of a service, or helper functions.
These tests will mock Prisma and therefore will not interface directly with the database. This allows for verifying the correct business logic is performed without having to set up the database.

## How to run unit tests
Running the following will run all unit tests:
```bash
$ yarn test
```

#### How to run unit tests

## Testing with code coverage
We have set up both code coverage and code coverage benchmarks. These benchmarks must be met for your PR to pass CI checks. Test coverage is calculated against both the integration and unit test runs. You can run test coverage with the followig:
```bash
$ yarn test:cov
```
Running the following will run all unit tests: `yarn test`

### Testing with code coverage

# Considerations For Detroit
As it stands right now `core` uses the AmiChart items column and `detroit` uses the AmiChartItem table.
As we move through converting detroit over to prisma we will unify those and choose one of the two approaches.
We have set up both code coverage and code coverage benchmarks. These benchmarks must be met for your PR to pass CI checks. Test coverage is calculated against both the integration and unit test runs. You can run test coverage with the following: `yarn test:cov`
14 changes: 4 additions & 10 deletions shared-helpers/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
# Bloom Shared Helpers

This package is the home of types and functions intended for shared use between the Next.js sites within the Bloom monorepo. In certain instances there is also some commonality between the frontend plus the backend (not implemented currently).
![TypeScript](https://img.shields.io/badge/typescript-%23007ACC.svg?style=for-the-badge&logo=typescript&logoColor=white) ![React](https://img.shields.io/badge/react-%2320232a.svg?style=for-the-badge&logo=react&logoColor=%2361DAFB) ![SASS](https://img.shields.io/badge/SASS-hotpink.svg?style=for-the-badge&logo=SASS&logoColor=white) ![Testing-Library](https://img.shields.io/badge/-TestingLibrary-%23E33332?style=for-the-badge&logo=testing-library&logoColor=white) ![Jest](https://img.shields.io/badge/-jest-%23C21325?style=for-the-badge&logo=jest&logoColor=white)

## CLI
This package includes types, functions, and components shared between the public and partners sites within Bloom.

To run the test suite which is built with Jest run:
## Tests

```
yarn test
# or
yarn test:coverage # generates local coverage reports, useful as you are writing tests
```
You can run the unit test suite with `yarn test`, or with `yarn test:coverage` to generate coverage reports.
Loading

0 comments on commit 9a6ffb5

Please sign in to comment.