chore(tooling): switch to fnm + pnpm, add DEPLOYMENT.md

Pin Node 24 via .node-version/.nvmrc and pnpm 9.15.0 via
package.json#packageManager. Regenerate lockfile as pnpm-lock.yaml.
Rewrite README setup + scripts table around pnpm, and add a
production deployment guide covering systemd, nginx, upgrades,
rollback, and backups.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-24 15:25:15 +07:00
parent 0c9a69cfb8
commit 0225b204a2
10 changed files with 5057 additions and 7325 deletions
+40 -24
View File
@@ -16,17 +16,33 @@ Siblings: [`buildfor_life_budget`](https://git.b4l.co.th/B4L/buildfor_life_budge
### 1. Prerequisites
- Node 20+ (24.x tested)
- **Node 24** pinned via `.node-version` (installed with [`fnm`](https://github.com/Schniz/fnm))
- **pnpm 9** as the package manager (declared in `package.json#packageManager`)
- PostgreSQL 16+ running locally or reachable by URL
- `git` with SSH access to `gitssh.b4l.co.th`
### 2. Install
### 2. Install fnm + pnpm
```bash
npm install
# fnm (one-time, per machine)
curl -fsSL https://fnm.vercel.app/install | bash # macOS / Linux
winget install Schniz.fnm # Windows (or: scoop install fnm)
# pnpm (one-time, via Corepack which ships with Node)
corepack enable
corepack prepare pnpm@9.15.0 --activate
```
### 3. Configure environment
### 3. Activate the pinned Node version and install deps
```bash
fnm use --install-if-missing
pnpm install
```
`fnm use` reads `.node-version` and drops you onto the correct Node. Add `eval "$(fnm env --use-on-cd)"` to your shell rc (bash/zsh) or the PowerShell equivalent so this happens automatically on `cd` into the repo.
### 4. Configure environment
```bash
cp .env.example .env
@@ -42,22 +58,22 @@ Edit `.env`:
- `STORAGE_LOCAL_ROOT` — where uploaded blobs live on disk (default `./storage`)
- OIDC block — leave `OIDC_ENABLED=false` unless you're wiring SSO
### 4. Create the database
### 5. Create the database
```bash
createdb buildfor_life_ops # or use your tool of choice
```
### 5. Apply migrations
### 6. Apply migrations
```bash
npm run db:migrate
pnpm run db:migrate
```
### 6. Bootstrap the first admin user
### 7. Bootstrap the first admin user
```bash
npm run create-user -- \
pnpm run create-user -- \
--email you@b4l.co.th \
--password 'a-long-password' \
--name 'Your Name' \
@@ -65,29 +81,29 @@ npm run create-user -- \
--role admin
```
### 7. Run the dev server
### 8. Run the dev server
```bash
npm run dev
pnpm dev
```
Open http://localhost:5173 and log in.
## npm scripts
## pnpm scripts
| Command | What it does |
| --- | --- |
| `npm run dev` | Start the Vite dev server with HMR |
| `npm run build` | Production build (outputs to `build/`) |
| `npm run preview` | Preview the production build locally |
| `npm run check` | Typecheck: `svelte-kit sync` then `svelte-check --threshold warning` |
| `npm run validate` | `check` + `build` — use this as a pre-commit smoke test |
| `npm run db:generate` | Diff the Drizzle schema against the last snapshot and emit a new migration under `drizzle/` |
| `npm run db:migrate` | Apply pending migrations against `$DATABASE_URL` |
| `npm run db:push` | Skip migration files and sync the schema directly — **dev only** |
| `npm run db:studio` | Open Drizzle Studio (web UI at localhost for inspecting data) |
| `npm run db:seed` | Seed the system catalog of asset types (wired when the assets schema lands in Phase 1) |
| `npm run create-user -- --email ... --password ... --name ... [--company ...] [--role ...]` | Create or update a user; optionally attach them to a company with a role |
| `pnpm dev` | Start the Vite dev server with HMR |
| `pnpm build` | Production build (outputs to `build/`) |
| `pnpm preview` | Preview the production build locally |
| `pnpm check` | Typecheck: `svelte-kit sync` then `svelte-check --threshold warning` |
| `pnpm validate` | `check` + `build` — use this as a pre-commit smoke test |
| `pnpm db:generate` | Diff the Drizzle schema against the last snapshot and emit a new migration under `drizzle/` |
| `pnpm db:migrate` | Apply pending migrations against `$DATABASE_URL` |
| `pnpm db:push` | Skip migration files and sync the schema directly — **dev only** |
| `pnpm db:studio` | Open Drizzle Studio (web UI at localhost for inspecting data) |
| `pnpm db:seed` | Seed the system catalog of asset types |
| `pnpm run create-user -- --email ... --password ... --name ... [--company ...] [--role ...]` | Create or update a user; optionally attach them to a company with a role |
## Project layout
@@ -181,6 +197,6 @@ When in doubt, check the siblings before inventing:
## Troubleshooting
- **`Environment validation failed`** on boot — `.env` is missing or incomplete; compare against `.env.example`
- **`relation "sessions" does not exist`** — you skipped `npm run db:migrate` after `db:generate`
- **`relation "sessions" does not exist`** — you skipped `pnpm run db:migrate` after `db:generate`
- **Session cookie never sets** — in dev, make sure `PUBLIC_BASE_URL` includes `localhost` so the hook sets `secure: false`; in production use HTTPS
- **`sha256 mismatch on upload`** — the client-computed sha256 disagrees with the server's stream hash; retry the upload