Skip to content
Draft
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
11c4561
wip #1 new app
k1eu Sep 12, 2025
c514bfc
init new fe
k1eu Sep 12, 2025
38c8eac
cleanup and move to betterauth
k1eu Sep 12, 2025
7cd41f5
move landing and deps to new react19 app
k1eu Sep 12, 2025
e11e175
--wip-- [skip ci]
k1eu Sep 12, 2025
be84bd9
remove old web
k1eu Sep 15, 2025
d06a1d1
auth pages
k1eu Sep 15, 2025
22accc7
add google workflow
k1eu Sep 15, 2025
86229e8
react mail integration
k1eu Sep 15, 2025
10b28bd
add vitest fe testing
k1eu Sep 15, 2025
5d10b9b
add logger
k1eu Sep 17, 2025
83f5166
email confirm
k1eu Sep 17, 2025
16470a9
setup vitest be
k1eu Sep 18, 2025
41f7d36
chore: remove jest remainings
k1eu Sep 18, 2025
aa5f068
add test setup scripts
k1eu Sep 18, 2025
23edc56
imoprt tests
k1eu Sep 18, 2025
7270040
rename web app directory
k1eu Sep 18, 2025
79ff49d
chore: move to single database instead of testcontainers
k1eu Sep 18, 2025
2281f1d
chore: update readme
k1eu Sep 18, 2025
5315bef
chore: add swagger generation types
k1eu Sep 18, 2025
f958f0f
init file structure
k1eu Sep 17, 2025
bd31c2e
file upload
k1eu Sep 17, 2025
9f4d2e2
file migration db
k1eu Sep 17, 2025
c1e55db
chore: update modules
k1eu Sep 18, 2025
56c7cf9
docs: update changelog
k1eu Sep 18, 2025
cc79c10
clean file api - no repo
k1eu Sep 19, 2025
7377f1f
add self better auth instance handling
k1eu Sep 19, 2025
320fede
setup landing
k1eu Sep 19, 2025
fb4367f
rename remix to react instances
k1eu Sep 19, 2025
0d881f3
add admin plguin and migration
k1eu Sep 19, 2025
642a96d
add admin users list
k1eu Sep 19, 2025
d09df84
bump vite
k1eu Sep 22, 2025
9a494e2
add missing env example
k1eu Sep 22, 2025
190b0b0
update readme
k1eu Sep 22, 2025
8bab0d3
update file adapter
k1eu Sep 22, 2025
de85dae
update eslint
k1eu Sep 23, 2025
d5d811f
setup actions
k1eu Sep 23, 2025
560421b
feat: forgot password mails
k1eu Sep 24, 2025
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
build/
ignore/
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
# Guidebook

This repository consists of docs available in `docs` folder and hosted below:

See https://guidebook.selleo.dev/.

This repository also contains project starters.


## Project starters

## Project starter
[NestJS + React](./examples/common_nestjs_remix) Starter
[NestJS + React + React Native (expo)](./examples/common_nestjs_remix) Starter (soon)
[Bun Script](#) Starter (soon)
[Bun Backend](#) Starter (soon)

This repo contains [project starter](./examples/common_nestjs_remix) that speeds up development.

## LICENSE

Expand Down
18 changes: 18 additions & 0 deletions docs/docs/release-notes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@

# Release Notes

## v1.1.0 2025-09
- Migrate to React Router 7 from Remix
- Upgrade to React 19
- Upgrade to React Email 4
- Upgrade to Tailwind v4
- Add login page
- Remove self written Auth
- Add Better Auth with social sign ins flow
- Upgrade to Node 24
- Switch to SWC in NestJS
- Switch from Jest to Vitest in NestJS
-

## v1.0.0 - 2024-09
- Release
- React Recipes
- Developer Recipes

## v0.0.1
- Create repository
2 changes: 1 addition & 1 deletion examples/common_nestjs_remix/.tool-versions
Original file line number Diff line number Diff line change
@@ -1 +1 @@
nodejs 20.15.0
nodejs 24.8.0
34 changes: 34 additions & 0 deletions examples/common_nestjs_remix/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Repository Guidelines

## Project Structure & Module Organization
- `apps/api`: NestJS backend; feature folders (e.g., `users`, `common`, `storage`) hold modules, DTOs, and shared helpers. `test/` contains Jest setups and factories for unit/e2e specs.
- `apps/web-app`: React Router 7 frontend; UI primitives in `app/components`, domain logic in `app/modules`, routes and layouts have `name.page.tsx` and `name.layout.tsx` convention in modules and API adapters in `app/api`.
- `apps/reverse-proxy`: Caddy config enabling HTTPS domains during local development.
- `packages/`: `email-templates` builds transactional mails, `eslint-config` centralizes lint rules, and `typescript-config` exposes reusable tsconfig bases.dist/`.

## Build, Test, and Development Commands
- Install deps: `pnpm install` (Node 22+, pnpm 10).
- Start everything: `pnpm dev`; build all workspaces: `pnpm build`.
- Focused dev: `pnpm --filter api dev` for the API, `pnpm --filter guidebook-web-app dev` for the frontend, `pnpm --filter reverse-proxy dev` when reloading Caddy.
- Database: `pnpm db:generate` then rename the migration and sync its `tag` in `apps/api/src/storage/migrations/meta/_journal.json`; apply with `pnpm db:migrate`.
- Tooling extras: `pnpm generate:client` refreshes the Swagger client, `pnpm lint` and `pnpm format` keep standards aligned.

## Coding Style & Naming Conventions
- TypeScript with 2-space indentation everywhere; Prettier governs formatting and ESLint extends `@repo/eslint-config` plus NestJS/React best practices.
- Nest classes (`UsersService`, `AuthModule`) use PascalCase filenames; utilities and constants stay camelCase.
- Frontend components exported from `app/components` and `app/modules` use PascalCase; hooks live under `hooks` with `useX` naming.
- Never commit `.env` files; derive them from each app’s `.env.example`.

## Testing Guidelines
- API unit tests: `pnpm test:api`; coverage: `pnpm --filter api test:cov`. Prefer colocated `*.spec.ts` inside feature folders.
- API e2e: `pnpm test:api:e2e` (uses the Testcontainers helpers in `apps/api/test`).
- Frontend unit tests: `pnpm test:web`; browser-style e2e via `pnpm test:web:e2e`. Snapshot assertions belong under `app/tests`.

## Commit & Pull Request Guidelines
- Commits stay small, imperative, and scoped using conventional commits format (e.g., `feat: add logger transport`); include migration or config notes in the body when relevant.
- Reference tickets with `Refs #123` or link to Notion tasks in the PR description.
- PRs must outline the change, list executed commands, attach UI/API screenshots when behavior shifts, and flag new env vars or migrations.

## Environment & Security Tips
- Initialize services with `docker-compose up -d` before running migrations; seed data through `pnpm --filter api db:seed` when needed.
- Store secrets in untracked `.env.local` files
22 changes: 9 additions & 13 deletions examples/common_nestjs_remix/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

- apps
- `api`: a NestJS backend application working as API
- `web`: a Vite Remix SPA
- `web`: React Router SPA on Vite
- `reverse-proxy`: for domains and https during development
- packages
- `email-templates`: a package for email templates
Expand All @@ -12,7 +12,7 @@
### Install

To start with the setup make sure you have the correct NodeJS version stated in [.tool-versions](./.tool-versions).
For the node versioning we recommend [asdf](https://asdf-vm.com/). At the time of writing this readme the version is `20.15.0`
For the node versioning we recommend [asdf](https://asdf-vm.com/). At the time of writing this readme the version is `24.8.0`

After these steps, run the following command

Expand All @@ -38,17 +38,17 @@ After running caddy proceed with the on screen instructions.

The final setup step is to configure both the `api` and `web` applications.

First, from the `examples/common_nestjs_remix` directory, navigate to `apps/api` and run the following to set up the backend:
To set up the backend envs and database:

```sh
cp .env.example .env
docker-compose up -d
cp ./apps/api/.env.example ./apps/api/.env
docker-compose up
```

Next, navigate to `apps/web` and copy the environment variables for the frontend:
Next, setup the env variables for frontend:

```sh
cp .env.example .env
cp ./apps/web/.env.example ./apps/web/.env
```

### Migrations
Expand Down Expand Up @@ -77,7 +77,7 @@ You should be able to access your app at the following addresses:
- generate migration

```sh
pnpm db:generate
pnpm db:generate -- --name your_migration_name
```

- run migrations
Expand All @@ -86,10 +86,6 @@ You should be able to access your app at the following addresses:
pnpm db:migrate
```

> [!IMPORTANT]
> Once migration is generated chagne its name to something more descriptive.
> Also make sure to change the migration name in [\_journal.json](apps/api/src/storage/migrations/meta/_journal.json) file under the `tag` key.

- #### HTTP Client

To generate the http client run the following command.
Expand Down Expand Up @@ -128,4 +124,4 @@ You should be able to access your app at the following addresses:

## Legal notice

This project was generated using [Selleo Guidebook](https://github.com/Selleo/guidebook) which is licensed under the MIT license.
This project was generated using [Selleo Guidebook](https://github.com/Selleo/guidebook) which is licensed under the MIT license.
24 changes: 21 additions & 3 deletions examples/common_nestjs_remix/apps/api/.env.example
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# GENERAL
NODE_ENV=development
LOG_LEVEL=debug
CORS_ORIGIN="https://app.guidebook.localhost"
EMAIL_ADAPTER="mailhog"

# DATABASE
DATABASE_URL="postgres://postgres:guidebook@localhost:5432/guidebook"
DATABASE_TEST_URL="postgres://postgres:guidebook@localhost:5432/guidebook_test"

# JWT
JWT_SECRET="secret99"
Expand All @@ -17,6 +20,21 @@ SMTP_USER=
SMTP_PASSWORD=

# AWS
AWS_REGION=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=eu-central-1
AWS_ACCESS_KEY_ID=AKIAV2CD6JAAAAAAAA
AWS_SECRET_ACCESS_KEY=SECREETTTTTTTTTTTTTTTTTTT

FILE_STORAGE_ADAPTER=dev
S3_DEV_BUCKET=2m3d-boilerplate-dev
S3_BUCKET=2m3d-boilerplate-prod


# AUTH

BETTER_AUTH_SECRET="secret999"
BETTER_AUTH_URL=http://localhost:3000

GOOGLE_CLIENT_ID=1111111111111-example.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-example123


1 change: 1 addition & 0 deletions examples/common_nestjs_remix/apps/api/drizzle.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export default defineConfig({
dbCredentials: {
url: "postgres://postgres:guidebook@localhost:5432/guidebook",
},
casing: "snake_case",
verbose: true,
strict: true,
});
20 changes: 0 additions & 20 deletions examples/common_nestjs_remix/apps/api/jest.config.ts

This file was deleted.

4 changes: 3 additions & 1 deletion examples/common_nestjs_remix/apps/api/nest-cli.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true
"deleteOutDir": true,
"builder": "swc",
"typeCheck": true
}
}
125 changes: 65 additions & 60 deletions examples/common_nestjs_remix/apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,90 +11,95 @@
"start": "nest start",
"start:dev": "nest start --watch",
"dev": "nest start --watch",
"dev-social": "DEV_SOCIAL=true nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/src/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json",
"test:e2e:watch": "jest --config ./test/jest-e2e.json --watch",
"test": "NODE_ENV=test vitest run",
"test:watch": "NODE_ENV=test vitest",
"test:cov": "NODE_ENV=test vitest run --coverage",
"test:debug": "NODE_ENV=test vitest --inspect-brk --inspect --logHeapUsage --threads=false",
"test:e2e": "NODE_ENV=test vitest run --config ./vitest.config.e2e.ts",
"test:e2e:watch": "NODE_ENV=test vitest --config ./vitest.config.e2e.ts",
"db:migrate": "drizzle-kit migrate",
"db:generate": "drizzle-kit generate",
"db:seed": "ts-node -r tsconfig-paths/register ./src/seed.ts"
"db:seed": "ts-node -r tsconfig-paths/register ./src/seed.ts",
"db:studio": "drizzle-kit studio"
},
"dependencies": {
"@aws-sdk/client-ses": "^3.616.0",
"@aws-sdk/client-s3": "^3.890.0",
"@aws-sdk/client-ses": "^3.887.0",
"@knaadh/nestjs-drizzle-postgres": "^1.0.0",
"@nestjs/axios": "^3.0.3",
"@nestjs/common": "^10.0.0",
"@nestjs/config": "^3.2.3",
"@nestjs/core": "^10.0.0",
"@nestjs/cqrs": "^10.2.7",
"@nestjs/jwt": "^10.2.0",
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/swagger": "^7.4.0",
"@nestjs/terminus": "^10.2.3",
"@nestjs/axios": "^4.0.1",
"@nestjs/common": "^11.1.6",
"@nestjs/config": "^4.0.2",
"@nestjs/core": "^11.1.6",
"@nestjs/cqrs": "^11.0.3",
"@nestjs/jwt": "^11.0.0",
"@nestjs/passport": "^11.0.5",
"@nestjs/platform-express": "^11.1.6",
"@nestjs/swagger": "^11.2.0",
"@nestjs/terminus": "^11.0.0",
"@repo/email-templates": "workspace:*",
"@sinclair/typebox": "^0.32.34",
"@sinclair/typebox": "^0.34.41",
"add": "^2.0.6",
"bcrypt": "^5.1.1",
"cookie": "^0.6.0",
"bcrypt": "^6.0.0",
"better-auth": "^1.3.9",
"cookie": "^1.0.2",
"cookie-parser": "^1.4.6",
"drizzle-kit": "^0.22.8",
"drizzle-orm": "^0.31.2",
"drizzle-typebox": "^0.1.1",
"drizzle-kit": "^0.31.4",
"drizzle-orm": "^0.44.5",
"drizzle-typebox": "^0.3.3",
"lodash": "^4.17.21",
"nestjs-pino": "^4.1.0",
"nestjs-typebox": "3.0.0-next.8",
"nodemailer": "^6.9.14",
"multer": "^2.0.2",
"nestjs-typebox": "4.0.0",
"nodemailer": "^7.0.6",
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
"passport-local": "^1.0.0",
"pino": "^9.4.0",
"postgres": "^3.4.4",
"postgres": "^3.4.7",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1",
"ts-pattern": "^5.2.0",
"uuid": "^10.0.0"
"rxjs": "^7.8.2",
"ts-pattern": "^5.8.0",
"uuid": "^9.0.1"
},
"devDependencies": {
"@faker-js/faker": "^8.4.1",
"@nestjs/cli": "^10.0.0",
"@nestjs/schematics": "^10.0.0",
"@nestjs/testing": "^10.0.0",
"@types/bcrypt": "^5.0.2",
"@types/cookie": "^0.6.0",
"@types/cookie-parser": "^1.4.7",
"@types/express": "^4.17.17",
"@types/jest": "^29.5.2",
"@types/lodash": "^4.17.6",
"@types/node": "^20.3.1",
"@types/nodemailer": "^6.4.15",
"@faker-js/faker": "^10.0.0",
"@nestjs/cli": "^11.0.10",
"@nestjs/schematics": "^11.0.7",
"@nestjs/testing": "^11.1.6",
"@swc/cli": "^0.7.8",
"@swc/core": "^1.13.5",
"@types/bcrypt": "^6.0.0",
"@types/cookie": "^1.0.0",
"@types/cookie-parser": "^1.4.9",
"@types/express": "^5.0.3",
"@types/lodash": "^4.17.20",
"@types/multer": "^2.0.0",
"@types/node": "^24.3.1",
"@types/nodemailer": "^7.0.1",
"@types/passport-jwt": "^4.0.1",
"@types/passport-local": "^1.0.38",
"@types/supertest": "^6.0.0",
"@types/supertest": "^6.0.3",
"@types/uuid": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"dotenv": "^16.4.5",
"eslint": "^8.42.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
"@typescript-eslint/eslint-plugin": "^8.43.0",
"@typescript-eslint/parser": "^8.43.0",
"@vitest/coverage-v8": "^3.2.4",
"dotenv": "^17.2.2",
"eslint": "^9.35.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.4",
"faker": "link:@types/@faker-js/faker",
"fishery": "^2.2.2",
"jest": "^29.5.0",
"pino-pretty": "^11.2.2",
"prettier": "^3.0.0",
"fishery": "^2.3.1",
"prettier": "^3.6.2",
"source-map-support": "^0.5.21",
"supertest": "^6.3.3",
"testcontainers": "^10.10.3",
"ts-jest": "^29.1.0",
"ts-loader": "^9.4.3",
"supertest": "^7.1.4",
"testcontainers": "^11.5.1",
"ts-loader": "^9.5.4",
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.1.3"
"typescript": "^5.9.2",
"unplugin-swc": "^1.5.7",
"vitest": "^3.2.4"
}
}
Loading