Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
254 changes: 254 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
# Contributing to Readr

Thank you for contributing to the project!
We appreciate all issues, pull requests and other comments regarding the project.

Use this document as a reference when writing code, opening issues and pull requests and otherwise contributing to Readr.

The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY" and "OPTIONAL" in this document are to be interpreted as in [RFC 2119](https://www.rfc-editor.org/info/rfc2119/). (This may be somewhat unknown or obscure to some, however, we think it makes the guidelines very clear.)

## Git usage

### Commits

Commits MUST use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/).
This makes the git history easier to search through and makes the purpose of each commit clearer.
If you're not sure which commit type fits best, you MUST pick one instead of leaving it completely empty. Trust your gut feeling.

Some of the commit tags we use:

- `feat`: Introduces a new feature
- `fix`: Fixes a bug or other smaller issue
- `refactor`: Code change that neither adds nor removes a feature, but cleans up the code in some way
- `style`: Adjusts formatting of code, but does not change it as substantially as a refactor, e.g. whitespace changes, missing semicolons, etc.
- `chore`: Smaller change that "just needs to be done", usually some routine task
- `build`: Something changed in the build system, e.g. package installed with `pnpm`, `package.json` or `vite.config.ts` changed
- `test`: Adding or modifying tests
- `docs`: Changes in documentation like Markdown files and similar
- `perf`: Code change that improves the performance of the app

If you performed a breaking change, especially if this means other changes are required to make the app function as expected, mark the commit.
This is done by appending an exclamation mark (`!`) after the commit type and adding `BREAKING CHANGE` with a description in the commit footer.

Example of a commit introducing a breaking change:

```
feat!: enforce stricter search rules
BREAKING CHANGE: Old search needs to be updated.
We must adjust it so...
```

### Branches

Branch names MUST use a conventional commit type, followed by a short name of the branch content.

Example: `feat/new-book-search`

## Creating issues

All GitHub issues:

- MUST have a description with enough explanations to understand the purpose of the issue and how to resolve it, but they do not need to be extremely detailed or long
- We want to state explicitly that issues MUST NOT be empty, i.e., have no description
- MUST have a fitting type ("Bug", "Feature" or "Task")
- MUST be connected to a milestone, if a fitting one is available. Otherwise, this is OPTIONAL
- MUST be assigned to the person(s) working on the issue as soon as you being work
- This helps us avoid duplicate work being done
- MUST be connected to a pull request as soon as a PR that will resolve this issue is opened
- SHOULD have a fitting label, but it MAY be skipped in some rare cases

Checklists or TODO lists are RECOMMENDED for large issues that require multiple tasks to be done.

## Code style

Code MUST be readable and maintainable. If you see you are writing spaghetti, it's time to refactor - preferably immediately.

We use [Prettier](https://prettier.io/) as our code formatter. It is strongly RECOMMENDED to add it to your IDE so the code is formatted on save.
Please see the [VS Code Extensions](#vs-code-extensions) section for details.

### Function definitions

Arrow functions SHOULD be used for situations where it saves space and is more readable.
For larger, stand-alone functions with multiple lines of code (approximately 10+), the code MUST use the standard function syntax:

```ts
// Prefer this:
function handleCalculations(arg1: string, arg2: number) {
// ...
}

// Over this:
const handleCalculations = (arg1: string, arg2: number) => {
// ...
}
```

Helper functions inside components MUST also use the standard function syntax.

### Exports

Variables, functions and other objects that will be exported, MUST be exported at the end of the file:

```ts
function func() {
// ...
}

const SOMETHING_IMPORTANT = "value";

type Computer = {
name: string;
model: string;
ram: number;
}

export {
func,
SOMETHING_IMPORTANT,
type Computer
}
```

The code MUST NOT export immediately:

```ts
export function ...

export const ...

export type ...
```

Exceptions:

- React Router routes need default export for the route itself and functions like `meta`
- Generated GraphQL resolver files (`backend/src/schema/[name]/resolvers/...`)
- Generated GraphQL type files (`*.generated.*`)

### Generated files

Files that are generated by Apollo Codegen or other tools, i.e. all `*.generated.*` files, MUST NOT be edited manually.
Any manual changes in these files will be overwritten the next time `pnpm codegen` is run.

## Components

### Folder structure

Each component lives in its own folder to allow for a test file.

Components which are used on multiple pages MUST use the following folder structure:

`frontend/app/components/ComponentName/ComponentName.tsx`

Components which are used on one page only MUST use the following folder structure:

`frontend/app/components/pageName/ComponentName/ComponentName.tsx`

The `pageName` SHOULD match the route file name, i.e. `frontend/app/routes/pageName.tsx`.

> [!NOTE]
> Please note the casing of these folders and files.
> We use `camelCase` for page names and `PascalCase` for component names.
Exceptions:

- The `frontend/app/components/ui/` folder includes only files from [shadcn/ui](https://ui.shadcn.com/) that have been modified to fit our project where needed.
These do not need tests, and therefore they are not placed in their own folders.
- The components in `frontend/app/components/forms/` are grouped together because they are a part of forms used in the app.

### Definitions

All components MUST be defined as functions, and they MUST NOT use the arrow function syntax.

A separate `ComponentNameProps` type SHOULD be used when the component uses many props, or if they have an advanced type.
Otherwise, using such a type is OPTIONAL.

Example:

```tsx
interface FavoriteButtonProps {
book: SearchBook;
}

function FavoriteButton({ book }: FavoriteButtonProps) {
// Some data and calculations...

return (
<Button type="button" variant="outline">
<HeartIcon />
</Button>
);
}

export { FavoriteButton };
```

## VS Code Extensions

We have added an [.vscode/extensions.json](./.vscode/extensions.json) file to suggest great Visual Studio Code extensions that are useful for contributing to this project.
It's completely OPTIONAL to install these.

Recommended extensions (in alphabetical order):

- [Auto Rename Tag](https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag)
- [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker)
- [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)
- [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
- [Pretty TypeScript Errors](https://marketplace.visualstudio.com/items?itemName=yoavbls.pretty-ts-errors)
- [Tailwind CSS IntelliSense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)

## Pull requests

### Checklist beforehand

The app MUST be in a buildable state with no TypeScript and ESLint errors.

Before opening a pull request, these commands MUST NOT report any issues:

```sh
# For the frontend:
cd frontend
pnpm lint
pnpm typecheck
pnpm test
pnpm build

# And the backend:
cd ../backend
pnpm typecheck
pnpm build
```

### Creating a pull request

All pull requests (PRs):

- MUST have a description. Again, it does not need to be extremely detailed, but it MUST explain what has been done
- MUST be assigned to the main contributor(s) of the commits in the PR
- MUST be connected to a milestone, if a fitting one is available. Otherwise, this is OPTIONAL
- MUST be connected to an issue
- SHOULD have a fitting label, but it MAY be skipped in some rare cases

For pull requests which change multiple aspects of the app, it is RECOMMENDED to use lists in order to provide explanations in a compact manner.

## Working in this repository

`main` is protected — you cannot push to it directly. Work on a branch and
open a pull request:

```bash
git checkout -b feat/my-feature
git push -u origin feat/my-feature
```

Before a pull request can be merged:

1. **A member of IT2810-H26-T37 MUST approve it.** You cannot approve your own pull
request, and approvals from staff do not count — you review each other's
code.
2. **Every review comment MUST be marked resolved.** Reply to each one, fix it
or explain why not, then click _Resolve conversation_.
3. **Pushing new commits dismisses the approval**, so if you change something
after being approved, ask for another review. This is deliberate: what was
approved is what gets merged.
62 changes: 18 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,47 +14,21 @@ In order to get started with the project, check the READMEs for the respective p
- [Frontend README.md](./frontend/README.md)
- [Backend README.md](./backend/README.md)

## Project choices and reasoning

For more information about our project choices and reasoning for these, please see the [Project choices and reasoning documentation](./docs/choices-and-reasoning.md).

## Infrastructure

For a full walkthrough of the project's infrastructure and an example of how it's used in practice, please see our [Infrastructure documentation](./docs/infrastructure.md).

## Deployment

For more details on deploying the solution on a VM, see the [deployment documentation](/docs/deployment.md).

## Sustainability

Details about how we have developed the project with sustainability in mind can be found in the [sustainability documentation](/docs/sustainability.md).

## Accessibility

Details about how we have worked with accessibility can be found in the [accessibility documentation](/docs/accessibility.md).

## Use of AI in this project

Details about how we have used AI during development can be found in the [AI documentation](/docs/ai-documentation.md).

## Working in this repository

`main` is protected — you cannot push to it directly. Work on a branch and
open a pull request:

```bash
git checkout -b my-feature
git push -u origin my-feature
```

Before a pull request can be merged:

1. **A member of IT2810-H26-T37 must approve it.** You cannot approve your own pull
request, and approvals from staff do not count — you review each other's
code.
2. **Every review comment must be marked resolved.** Reply to each one, fix it
or explain why not, then click _Resolve conversation_.
3. **Pushing new commits dismisses the approval**, so if you change something
after being approved, ask for another review. This is deliberate: what was
approved is what gets merged.
## Contributing to the project

Check out [CONTRIBUTING.md](./CONTRIBUTING.md) for further details regarding code style, standards regarding git usage, commits, issues, pull requests and more.

## Other documentation

- [Project choices and reasoning](./docs/choices-and-reasoning.md)
- Tech stack and tool choices, discussions and reasoning behind the decisions
- [Infrastructure](./docs/infrastructure.md)
- Describes our infrastructure and how it works in practice
- [Deployment](/docs/deployment.md)
- How the app is deployed on the provided VM
- [Sustainability](/docs/sustainability.md)
- More about how we've kept sustainability in mind when developing the application
- [Accessibility](/docs/accessibility.md)
- What steps we've taken to make the app accessible to everyone
- [AI documentation](/docs/ai-documentation.md)
- How AI was used during development
4 changes: 3 additions & 1 deletion backend/src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { drizzleAdapter } from "@better-auth/drizzle-adapter/relations-v2";
import { db } from "~/db";
import * as schema from "~/db/schema";

export const auth = betterAuth({
const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
schema,
Expand Down Expand Up @@ -32,3 +32,5 @@ export const auth = betterAuth({
},
trustedOrigins: [process.env.FRONTEND_URL ?? "http://localhost:5173"],
});

export { auth };
4 changes: 3 additions & 1 deletion backend/src/schema/books/schema.mappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ import type { SelectBook } from "~/db/schema/books";

// Resolvers return the DB row for a book.
// The genres are resolved by the Book field resolver instead
export type BookMapper = SelectBook;
type BookMapper = SelectBook;

export { type BookMapper };
4 changes: 3 additions & 1 deletion frontend/app/api/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export interface BookFilters {
interface BookFilters {
genres?: string[];
language?: string;
bookFormat?: string;
pages?: { min?: number; max?: number };
}

export { type BookFilters };
4 changes: 3 additions & 1 deletion frontend/app/hooks/formContext.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { createFormHookContexts } from "@tanstack/react-form";

export const { fieldContext, formContext, useFormContext, useFieldContext } =
const { fieldContext, formContext, useFormContext, useFieldContext } =
createFormHookContexts();

export { fieldContext, formContext, useFormContext, useFieldContext };
4 changes: 3 additions & 1 deletion frontend/app/hooks/useAppForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { TextareaField } from "~/components/forms/TextareaField/TextareaField";
import { TextField } from "~/components/forms/TextField/TextField";
import { fieldContext, formContext } from "~/hooks/formContext";

export const { useAppForm } = createFormHook({
const { useAppForm } = createFormHook({
fieldContext,
formContext,
fieldComponents: {
Expand All @@ -15,3 +15,5 @@ export const { useAppForm } = createFormHook({
SubmitButton,
},
});

export { useAppForm };