173 lines
6.1 KiB
Markdown
173 lines
6.1 KiB
Markdown
# FieldOps
|
|
|
|
Modular industrial SaaS monorepo. **This is the scaffold phase** — no business
|
|
features yet. The goal of this branch is to prove the end-to-end wiring:
|
|
client → tRPC → Prisma → Postgres, with multi-tenancy enforced from day zero.
|
|
|
|
## What's here
|
|
|
|
```
|
|
apps/
|
|
operator-pwa/ Next 15 — operator console (port 3000)
|
|
admin-web/ Next 15 — backoffice placeholder (port 3001)
|
|
packages/
|
|
db/ Prisma 6 schema + tenant-scoping extension
|
|
api/ tRPC v11 routers
|
|
ui/ Shared shadcn-style components
|
|
domain/ Pure domain logic (empty in this phase)
|
|
config/ tsconfig / eslint / tailwind presets
|
|
e2e/ Playwright smoke test
|
|
```
|
|
|
|
## Prerequisites
|
|
|
|
- **Node.js 22+** (use `nvm use` or install matching `.nvmrc`)
|
|
- **pnpm 11+** (`corepack enable pnpm` or `npm i -g pnpm`)
|
|
- **Docker Desktop** with the engine running (provides Postgres)
|
|
- **Git**
|
|
|
|
## From-zero setup
|
|
|
|
These steps assume a fresh clone with no `node_modules`, no Docker volumes,
|
|
no `.env`. Run them in order from the repo root.
|
|
|
|
```sh
|
|
# 1. environment
|
|
cp .env.example .env
|
|
# Open .env and set AUTH_DEV_AUTOLOGIN="true" for local development.
|
|
# (Default is "false" on purpose — see "Auth" below.)
|
|
|
|
# 2. install
|
|
pnpm install
|
|
|
|
# 3. start Postgres
|
|
docker compose up -d
|
|
|
|
# 4. apply the schema
|
|
pnpm db:migrate
|
|
|
|
# 5. seed the demo tenant
|
|
pnpm db:seed
|
|
|
|
# 6. start the operator app
|
|
pnpm --filter @repo/operator-pwa dev
|
|
```
|
|
|
|
Open <http://localhost:3000> — you should see a **Connected** card with
|
|
`Tenant: Demo Factory`.
|
|
|
|
### Run the E2E
|
|
|
|
In a separate shell (with the dev server NOT running, or with
|
|
`reuseExistingServer` left on — Playwright handles either):
|
|
|
|
```sh
|
|
pnpm --filter @repo/e2e install-browsers # one-time, downloads Chromium
|
|
pnpm test:e2e
|
|
```
|
|
|
|
The Playwright config force-sets `AUTH_DEV_AUTOLOGIN=true` for the dev server
|
|
it launches, so the test does not depend on the developer's `.env`.
|
|
|
|
## Auth
|
|
|
|
This scaffold has **no real authentication**. Auth.js v5 is wired up with a
|
|
single Credentials provider that accepts any email present in the seeded
|
|
`User` table — no password check.
|
|
|
|
The `AUTH_DEV_AUTOLOGIN` env flag controls a server-side fallback:
|
|
|
|
- **`AUTH_DEV_AUTOLOGIN=false`** (default in `.env.example`) — requests with
|
|
no Auth.js session are unauthenticated. `protectedProcedure` returns 401.
|
|
- **`AUTH_DEV_AUTOLOGIN=true`** — requests with no session silently resolve
|
|
to the seeded `admin@demo.local` user, skipping the login UI.
|
|
|
|
> ⚠️ **Never set `AUTH_DEV_AUTOLOGIN=true` in production.** The fallback is a
|
|
> back door intended only for local dev and CI. The chokepoint is
|
|
> `apps/operator-pwa/lib/auth.ts → resolveUser()`. Replace it with real
|
|
> authentication before any non-dev deployment.
|
|
|
|
## Multi-tenancy
|
|
|
|
Every Prisma model except `Tenant` has a `tenantId` column. Tenant scoping is
|
|
enforced at runtime by an extension in
|
|
`packages/db/src/tenant-extension.ts` — read the header comment in that file
|
|
for the full list of operations it covers and the operations it does **not**
|
|
(`$queryRaw`, interactive `$transaction` with external clients, etc.).
|
|
|
|
Call sites get the scoped client from the tRPC context: `ctx.db.*`. The
|
|
unscoped root client (`ctx.prisma`) is available for the rare cross-tenant
|
|
case but should be a red flag at PR review.
|
|
|
|
## tRPC
|
|
|
|
The operator app uses both tRPC paths:
|
|
|
|
- **RSC caller** — `apps/operator-pwa/lib/trpc/server.ts` — direct in-process
|
|
invocation from Server Components. Default for reads.
|
|
- **Client hooks** — `apps/operator-pwa/lib/trpc/client.ts` —
|
|
`@trpc/react-query` against `/api/trpc`. Default for mutations and
|
|
client-rendered reads.
|
|
|
|
The home page exercises both: the `Connected` card is rendered server-side;
|
|
the `Client-side ping` card uses `useQuery`. Both must succeed for the
|
|
hybrid wiring to be considered green.
|
|
|
|
## Common commands
|
|
|
|
| Command | What it does |
|
|
| --- | --- |
|
|
| `pnpm install` | Install all workspace deps |
|
|
| `docker compose up -d` | Start Postgres |
|
|
| `docker compose down` | Stop Postgres (data persists) |
|
|
| `docker compose down -v` | Stop Postgres **and drop the volume** |
|
|
| `pnpm dev` | Run all dev tasks via Turbo |
|
|
| `pnpm --filter @repo/operator-pwa dev` | Operator app only |
|
|
| `pnpm --filter @repo/admin-web dev` | Admin app only (port 3001) |
|
|
| `pnpm db:migrate` | Apply pending Prisma migrations |
|
|
| `pnpm db:reset` | Drop, recreate, migrate, seed |
|
|
| `pnpm db:seed` | Re-seed the demo tenant (idempotent) |
|
|
| `pnpm db:studio` | Open Prisma Studio |
|
|
| `pnpm typecheck` | Typecheck every package |
|
|
| `pnpm test:e2e` | Run Playwright |
|
|
| `pnpm format` | Prettier write |
|
|
|
|
## Versions of note
|
|
|
|
| Package | Version | Why |
|
|
| --- | --- | --- |
|
|
| Node | 22 LTS | Required by Next 15 |
|
|
| pnpm | 11 | Workspace + `allowBuilds` security feature |
|
|
| Next.js | 15 | App Router, React 19 |
|
|
| React | 19 | |
|
|
| Prisma | 6 | Kept on 6.x — Prisma 7 mandates the new `prisma-client` ESM generator, which is a separate migration |
|
|
| Auth.js (next-auth) | 5.0 beta | v5 split-config pattern (edge-safe middleware + Node providers) |
|
|
| tRPC | 11 | Stable on the v11 series |
|
|
| Tailwind | 3 | Conservative choice; v4 swap is a separate spike |
|
|
| shadcn/ui | components inlined | Not the CLI scaffold — components live in `packages/ui/src/components` |
|
|
|
|
## Troubleshooting
|
|
|
|
**`ERR_PNPM_IGNORED_BUILDS` after adding a dep** — pnpm 11 blocks postinstall
|
|
scripts unless approved. Edit `pnpm-workspace.yaml` `allowBuilds:` and set
|
|
the offending package to `true` (or `false` if you don't want its
|
|
postinstall to run).
|
|
|
|
**Page loads but says `UNAUTHORIZED`** — your `.env` has
|
|
`AUTH_DEV_AUTOLOGIN=false` (the default). Flip it to `true` for local dev,
|
|
or sign in through Auth.js.
|
|
|
|
**Page errors with `Tenant not found`** — the seeded tenant was wiped.
|
|
Run `pnpm db:seed` again.
|
|
|
|
**Migration fails with `Environment variable not found: DATABASE_URL`** —
|
|
make sure `.env` exists at the repo root and Docker Postgres is running.
|
|
|
|
**Playwright complains the port is busy** — kill any leftover dev servers:
|
|
on Windows `Get-Process node | Stop-Process -Force`; macOS/Linux
|
|
`pkill -f 'next dev'`.
|
|
|
|
## License
|
|
|
|
Internal. All rights reserved.
|