Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
12 changes: 6 additions & 6 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,10 @@ FREENARY_VERSION=latest
# --- Development only ---

# The API server hostname. It fills `BETTER_AUTH_URL`.
# SERVER_HOST=server.freenary.orb.local
# SERVER_HOST=server.freenary.localhost
# The web app hostname. It fills `CORS_ORIGIN`.
# WEB_HOST=web.freenary.orb.local
# The documentation hostname, in the OrbStack label alone.
# DOCS_HOST=docs.freenary.orb.local
# The Mailpit inbox hostname, in the OrbStack label alone. It applies to `bun run dev:mail`.
# MAIL_HOST=mail.freenary.orb.local
# WEB_HOST=web.freenary.localhost
# The documentation hostname, in the Traefik route alone.
# DOCS_HOST=docs.freenary.localhost
# The Mailpit inbox hostname, in the Traefik route alone. It applies to `bun run dev:mail`.
# MAIL_HOST=mail.freenary.localhost
6 changes: 3 additions & 3 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ Thanks for contributing to Freenary.

## Local Setup

Containerised stack (needs [OrbStack](https://orbstack.dev), applies the migrations for you):
Containerised stack (needs Docker and a free port 80, applies the migrations for you):

```bash
bun install
bun run dev:up # PostgreSQL, migrations, API server, web app, docs site
```

Local stack, without OrbStack:
Local stack, with the applications on your host:

```bash
bun install
Expand Down Expand Up @@ -56,7 +56,7 @@ bun run build # every app

Most lint/format issues are auto-fixable with `bun run fix`.

CI runs one more job that no root script covers: it parses both Compose files with `docker compose config --quiet`, and it asserts that `docker-compose.yml` still refuses an empty `POSTGRES_PASSWORD` and `BETTER_AUTH_SECRET`. Reproduce it before you change either file.
CI runs one more job that no root script covers: it parses every Compose file with `docker compose config --quiet`, and it asserts that `docker-compose.yml` still refuses an empty `POSTGRES_PASSWORD` and `BETTER_AUTH_SECRET`. Reproduce it before you change either file.

CI runs no tests, and there is no root `test` script. Run the test files your change touches by hand with `bun test <path>`.

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ jobs:
run: |
docker compose -f docker-compose.dev.yml config --quiet
docker compose -f docker-compose.dev.yml -f docker-compose.mail.yml config --quiet
docker compose -f docker-compose.proxy.yml config --quiet
printf 'POSTGRES_PASSWORD=x\nBETTER_AUTH_SECRET=y\n' > .env
docker compose -f docker-compose.yml config --quiet
: > .env
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ bun install
bun run dev:up # PostgreSQL, migrations, API server, web app, docs site
```

`dev:up` runs `docker-compose.dev.yml` under a per-worktree Compose project and prints the URLs it serves. No dev service publishes a host port: the stack reaches you through OrbStack hostnames (`web.<slug>.freenary.orb.local`, `server.<slug>.freenary.orb.local`, `docs.<slug>.freenary.orb.local`), and the slug comes from the git branch. Without OrbStack, use the local path instead:
`dev:up` runs `docker-compose.dev.yml` under a per-worktree Compose project and prints the URLs it serves. No dev service publishes a host port: one shared Traefik on port 80 routes plain-HTTP hostnames (`web.<slug>.freenary.localhost`, `server.<slug>.freenary.localhost`, `docs.<slug>.freenary.localhost`) to the containers, and the slug comes from the git branch. `scripts/dev.ts` reuses a Traefik already on the `devproxy` network, or starts `docker-compose.proxy.yml`; the self-hosting `docker-compose.yml` never involves it. Use Chrome or Firefox, which treat `*.localhost` as a secure context. Without Docker for the apps, use the local path instead:

```bash
bun run db:start # PostgreSQL container from docker-compose.yml (needs the root .env: cp .env.example .env)
bun run db:push # apply the Prisma schema
bun run dev # web 3001, server 3000, docs 4000
```

The dev stack needs no `.env`: the `server` service declares `env_file` with `required: false`, so an optional root `.env` reaches the container line by line, and `environment` carries only the six values the stack derives from the worktree — `DATABASE_URL`, `BETTER_AUTH_SECRET`, `BETTER_AUTH_URL`, `CORS_ORIGIN`, `AUTH_COOKIE_DOMAIN` and `NODE_ENV` (Compose gives `environment` precedence over `env_file`). It configures no email provider, so the one-time-code flows are off. `bun run dev:mail` layers `docker-compose.mail.yml` over it: that file starts `axllent/mailpit:v1.28` and points the server at it with `EMAIL_PROVIDER=smtp`, `SMTP_HOST=mailpit`, `SMTP_PORT=1025` and `EMAIL_FROM=Freenary <no-reply@freenary.test>`, and the inbox is a web page at `https://mail.<slug>.freenary.orb.local`. `bun run dev:reset` destroys the volumes and starts over. The `bootstrap` service runs `prisma migrate deploy` before the API server starts.
The dev stack needs no `.env`: the `server` service declares `env_file` with `required: false`, so an optional root `.env` reaches the container line by line, and `environment` carries only the six values the stack derives from the worktree — `DATABASE_URL`, `BETTER_AUTH_SECRET`, `BETTER_AUTH_URL`, `CORS_ORIGIN`, `AUTH_COOKIE_DOMAIN` and `NODE_ENV` (Compose gives `environment` precedence over `env_file`). It configures no email provider, so the one-time-code flows are off. `bun run dev:mail` layers `docker-compose.mail.yml` over it: that file starts `axllent/mailpit:v1.28` and points the server at it with `EMAIL_PROVIDER=smtp`, `SMTP_HOST=freenary-mailpit`, `SMTP_PORT=1025` and `EMAIL_FROM=Freenary <no-reply@freenary.test>`, and the inbox is a web page at `http://mail.<slug>.freenary.localhost`. `bun run dev:reset` destroys the volumes and starts over. The `bootstrap` service runs `prisma migrate deploy` before the API server starts.

**There is no seed script.** Create an account through the sign-in screen. Neither `bun run dev:up` nor `bun run dev` configures an email provider, so `requireEmailVerification` stays off, sign-up returns a session at once, and the interface shows no **Forgot password?** link. To work on the one-time-code flows, start the stack with `bun run dev:mail` and read the code in the Mailpit inbox. Bank data needs real bank-provider credentials (`BANKING_PROVIDER`, `POWENS_*` or `ENABLE_BANKING_*`); with none, the bank list reports that bank linking is unavailable and onboarding skips the connect step.

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ bun install
bun run dev:up
```

`dev:up` runs the full stack in Docker behind [OrbStack](https://orbstack.dev) hostnames. Without OrbStack:
`dev:up` runs the full stack in Docker, one stack per worktree, at `http://web.<slug>.freenary.localhost` and its siblings. A shared [Traefik](https://traefik.io) proxy on port 80 routes every name. Without Docker for the apps:

```bash
cp .env.example .env
Expand Down
2 changes: 1 addition & 1 deletion apps/fumadocs/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The public documentation website.
- **Fumadocs** (`fumadocs-core`, `fumadocs-mdx`, `fumadocs-ui` aliased to `@fumadocs/base-ui`) — page tree, MDX pipeline, local search, and the theme's components.
- **TanStack Start** on **Vite** — same toolchain as `apps/web`, with SSR plus build-time prerendering. Nitro preset `vercel`; there is no Dockerfile for this app, and `docker-compose.yml` has no `docs` service.
- **Tailwind v4** via `@tailwindcss/vite`. `src/app/styles/app.css` imports `tailwindcss`, then Fumadocs' `neutral` and `preset` stylesheets. It does **not** import `@freenary/ui/globals.css`, so the docs palette is Fumadocs' own and does not follow `apps/web`.
- `bun run dev` serves on port **4000**, hardcoded in the `dev` script. `DOCS_PORT` is set by `docker-compose.dev.yml` and read by nothing; `DOCS_HOST` is only an OrbStack domain label.
- `bun run dev` serves on port **4000**, hardcoded in the `dev` script. `DOCS_PORT` is set by `docker-compose.dev.yml` and read by nothing; `DOCS_HOST` is only the Traefik route of the dev stack.

## Layout

Expand Down
9 changes: 5 additions & 4 deletions apps/fumadocs/content/docs/next/contributing/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Three moves take you from a clone to a merged change. Set up the repository, run
| --- | --- | --- |
| Bun | `1.3.14` | The runtime, the package manager and the test runner. `packageManager` in the root `package.json` pins it. |
| Docker | Any current release | Both stack paths run PostgreSQL in a container. |
| OrbStack | Any current release | The containerised path only. No development service publishes a host port. |
| Port `80` | Free, or held by a Traefik on the `devproxy` network | The containerised path only. One shared proxy on that port serves every stack. |
| PostgreSQL | `18` | The image `bun run db:start` starts for you. You install nothing by hand. |

The repository holds a `.nvmrc` file with the content `v25.6.1`. No script and no workflow reads it. Bun runs everything here.
Expand Down Expand Up @@ -59,11 +59,11 @@ Pick one of the two paths below. Then create your account in the browser.

## The two ways to run the stack

One line separates them. The containerised path runs every part in Docker, behind OrbStack hostnames. The local path runs the three applications on your host.
One line separates them. The containerised path runs every part in Docker, behind one hostname per application under `freenary.localhost`. The local path runs the three applications on your host.

| Path | Command | What you get |
| --- | --- | --- |
| Containerised | `bun run dev:up` | Five services, one HTTPS hostname per application and per worktree, no host port |
| Containerised | `bun run dev:up` | Five services, one hostname per application and per worktree, and no host port but the shared proxy on `80` |
| Local | `bun run db:start`, then `bun run dev` | Three host processes on ports `3000`, `3001` and `4000`, with PostgreSQL on `127.0.0.1:5432` |

[Local development stack](/docs/contributing/local-stack) holds the services, the hostnames, the database commands and the first account.
Expand Down Expand Up @@ -94,10 +94,11 @@ bun run build
| 6 | Environment | `bun run env:check` | `scripts/env-sync.ts --check`, which compares `.env.example` and the configuration reference against `packages/env/src/schema.ts` |
| 7 | Build | `bun run build` | `turbo run build`, which builds the three applications |

The `compose` job needs no Bun and no install. It checks four things:
The `compose` job needs no Bun and no install. It checks five things:

- `docker compose -f docker-compose.dev.yml config --quiet` parses the development stack.
- The same command with `-f docker-compose.mail.yml` added parses the Mailpit layer over it.
- The same command against `docker-compose.proxy.yml` parses the development proxy.
- The same command against `docker-compose.yml` parses the production stack, with a temporary `.env` that sets `POSTGRES_PASSWORD` and `BETTER_AUTH_SECRET`.
- The same command with an empty `.env` must fail. A pass means the production file accepted two empty secrets, so the job fails.

Expand Down
Loading
Loading