diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..a2cbd6b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,280 @@ +# 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. + +### Lucide icons + +Icons from [Lucide](https://lucide.dev/) are great, and we use them actively in the project. + +However, they provide at least two exports for each of their icons, namely the components `Name` and `NameIcon`, e.g. `Sun` and `SunIcon`. +The component name `Sun` does not make it immediately clear what it is. + +Therefore, code that uses Lucide icons MUST import and use components with their full name, ending with `Icon`, e.g. `SunIcon`. + +### SQL Code + +[Drizzle ORM](https://orm.drizzle.team/) provides a lot of utilities for writing SQL queries, but for some advanced ones, we still write a little bit of raw SQL code. +This is done using the `sql` function so the parameters are parsed in a safe way. + +Raw SQL, both in code and SQL migration, MUST be written in UPPERCASE: + +```ts +sql`${books.rating} ASC NULLS LAST` +``` + +Avoid the following: + +```ts +sql`${books.rating} asc nulls last` +``` + +## 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 ( + + ); +} + +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. diff --git a/README.md b/README.md index f498f9f..626c1df 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/backend/src/auth/index.ts b/backend/src/auth/index.ts index 0ed79a6..4050d6f 100644 --- a/backend/src/auth/index.ts +++ b/backend/src/auth/index.ts @@ -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, @@ -32,3 +32,5 @@ export const auth = betterAuth({ }, trustedOrigins: [process.env.FRONTEND_URL ?? "http://localhost:5173"], }); + +export { auth }; diff --git a/backend/src/schema/books/schema.mappers.ts b/backend/src/schema/books/schema.mappers.ts index 3987890..4f49314 100644 --- a/backend/src/schema/books/schema.mappers.ts +++ b/backend/src/schema/books/schema.mappers.ts @@ -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 }; diff --git a/frontend/app/api/types/index.ts b/frontend/app/api/types/index.ts index b19b812..d5b21d0 100644 --- a/frontend/app/api/types/index.ts +++ b/frontend/app/api/types/index.ts @@ -1,6 +1,8 @@ -export interface BookFilters { +interface BookFilters { genres?: string[]; language?: string; bookFormat?: string; pages?: { min?: number; max?: number }; } + +export { type BookFilters }; diff --git a/frontend/app/hooks/formContext.ts b/frontend/app/hooks/formContext.ts index 8ac038f..9e18575 100644 --- a/frontend/app/hooks/formContext.ts +++ b/frontend/app/hooks/formContext.ts @@ -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 }; diff --git a/frontend/app/hooks/useAppForm.ts b/frontend/app/hooks/useAppForm.ts index b9bba60..7ca75ec 100644 --- a/frontend/app/hooks/useAppForm.ts +++ b/frontend/app/hooks/useAppForm.ts @@ -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: { @@ -15,3 +15,5 @@ export const { useAppForm } = createFormHook({ SubmitButton, }, }); + +export { useAppForm };