Skip to content

Latest commit

 

History

History
204 lines (167 loc) · 9.38 KB

File metadata and controls

204 lines (167 loc) · 9.38 KB

kwtech-software

Turborepo monorepo, pnpm workspaces. Toolchain and conventions follow ../masterdb-mgt-tool; the full plan lives in docs/PLAN.md, and the reasoning behind it in docs/DESIGN-NOTES.md. Building a feature? Start with CLAUDE.md: the working guide and checklist, which Claude Code also loads on its own.

Requirements

  • Node >= 22
  • pnpm >= 11 — corepack enable picks it up from the packageManager field. .npmrc sets engine-strict=true, so an older pnpm fails the install rather than producing a subtly different one.
  • Docker — pnpm dev runs the local Postgres in a container.
  • On Windows, WSL2.

New computer? Follow docs/SETUP.md, from git clone to signed in, with the database, seeding, optional services and troubleshooting.

Layout

apps/
  web-server/         NestJS — REST today, GraphQL + WS in Phase 3   :8080
  web-app/            Next.js — web frontend                         :8081
packages/
  web-ui/                 React + Tailwind 4 + AG Grid Community
  module-kit/             the module contract every app composes
  module-auth/            sign-in, sessions, MFA, password reset
  module-permissions/     organizations, workspaces, roles, features, plans, limits
  module-chat/            conversations and messages
  module-queuing-window/  walk-in queue: windows, lines, a live TV board
  module-notification/    system notifications: bell, toasts, an inbox
  module-jobs/            the background runner: queues and runs the processes modules declare; its admin page
  module-booking/         booking sub-app: services, resources and their hours, the day's bookings

No module imports another; only the apps depend on them. The map, and the ports modules use instead, are in docs/DEPENDENCIES.md, enforced by pnpm check:boundaries.

Feature modules ship as one package with a dependency-free core plus adapters behind subpath exports — @kwtech/module-permissions, .../server, .../react. Apps list their modules once and compose the rest:

export const WEB_MODULES = [permissionsWebModule, usersWebModule];
export const ROUTES = composeRoutes(WEB_MODULES);

See packages/module-kit/README.md for the contract and docs/PLAN.md §9 before adding a module.

Getting started

pnpm install
pnpm env:new local   # envs/local/, with fresh secrets
# fill in SEED_USER_* (your sign-in) in envs/local/web-server.env — BEFORE the first start
pnpm dev             # database created, migrated, filled and seeded; both apps running

Every step, and what each one does, is in docs/SETUP.md.

Environments: local, staging, production

Each environment is a profile: envs/<name>/web-server.env and envs/<name>/web-app.env, gitignored. The active one is symlinked to apps/web-server/.env.local and apps/web-app/.env.local (both apps use the same file name), so switching is one command and every tool (Nest, Next, Prisma, the seeders) follows it.

pnpm env:show            # active profile, its database and API (no secrets printed)
pnpm env:new staging     # create a profile from the templates, with fresh secrets
pnpm env:use staging     # switch both apps
pnpm db:deploy           # …now runs against staging
pnpm env:use local       # back
pnpm env:check           # templates hold no secrets; profiles lack no variable
  • Development defaults to local. pnpm dev activates it and creates it the first time. A non-local profile prints a warning banner on every pnpm dev.
  • APP_ENV in each profile says what it is, and the guards trust it: db:migrate and db:snapshot run only on local, and db:restore never touches production.
  • Deployed hosts don't use profile files. Set the same variables in the host (Vercel, the container host), including APP_ENV. A production build refuses to boot without it.
  • .env.example files are templates committed to a public repo. A value for any *_PASSWORD, *_SECRET, *_KEY or *_EMAIL fails the commit.
  • Keep each profile in a password manager too. That's how a new machine gets them.

On another machine, including one with an old apps/web-server/.env: git pull && pnpm install && pnpm env:show moves the old files into envs/local/ without losing anything, and pnpm env:check lists what's new. The full steps for each case are in envs/README.md → Setting up another machine.

pnpm dev starts everything — every package in watch mode plus both apps:

API http://localhost:8080/api/v1
API docs (Swagger) http://localhost:8080/api/v1/docs
Web http://localhost:8081
Sign in http://localhost:8081/auth/signin

Editing a packages/* file rebuilds it and the running apps pick the change up; there is no separate build step while developing.

That is one tsc --watch per package, about 300 MB each, which is heavy on a machine with little memory: on WSL at its default size it runs out and WSL goes down (docs/SETUP.md, Troubleshooting, has the fix). When the work is in one or two packages, pnpm dev:focus module-task (add more names, or --api / --web) runs the apps and watches only those. Every other package is still built once at the start, but an edit to one of them does not show up until you name it too or go back to pnpm dev.

apps/print-agent is left out of all of them, by a filter in the dev script: it is developed on its own, against a server that is already running, and a watcher for it would only cost memory here. Run it in a second terminal with pnpm dev:print-agent (see apps/print-agent/README.md). pnpm start leaves it out the same way, and pnpm start:print-agent runs the built one.

Commands

pnpm dev              # everything but the print agent: package watchers + both apps
pnpm dev:api          # just the API, and the packages it needs
pnpm dev:web          # just the frontend, and the packages it needs
pnpm dev:focus module-task   # both apps, watching ONLY the packages named (lighter)
pnpm dev:print-agent        # the print agent alone, rebuilt and restarted on edit (not part of pnpm dev)

pnpm build            # everything, in dependency order
pnpm start            # run the built apps (not the print agent)
pnpm start:print-agent      # build the print agent, then run it
pnpm typecheck
pnpm test
pnpm lint             # biome — one tool, no eslint, no prettier
pnpm check:fix        # lint + format, writing fixes

Database (all scoped to apps/web-server, which owns the schema — PLAN §12.2):

pnpm --filter @kwtech/web-server db:compose    # copy module prisma fragments in
pnpm --filter @kwtech/web-server db:generate   # compose + generate the client
pnpm --filter @kwtech/web-server db:migrate    # compose + migrate dev
pnpm --filter @kwtech/web-server db:seed       # idempotent first user
pnpm --filter @kwtech/web-server db:snapshot   # dev data → seed-data/snapshot.json
pnpm --filter @kwtech/web-server db:restore    # seed-data/snapshot.json → empty database
pnpm --filter @kwtech/web-server db:studio

Postgres is expected where DATABASE_URL points, localhost:5432 by default. pnpm dev and pnpm dev:api run scripts/dev-db.mjs first: if nothing answers on that port it starts a kwtech-postgres Docker container (creating it the first time, with its data in the kwtech-pgdata volume), and on a brand-new volume applies the migrations and seeds. A native Postgres already on the port is used as-is.

pnpm db:up            # start (or create) the container without starting the apps
pnpm db:down          # stop it; the data stays in the volume

Shared dev data. apps/web-server/seed-data/snapshot.json is a committed copy of a dev database's rows, so a second machine starts where the first left off. A brand-new container restores it automatically; against a native Postgres, or to catch up with a newer snapshot, run it yourself:

pnpm db:snapshot          # this database → snapshot.json (commit it)
pnpm db:restore           # snapshot.json → an empty, migrated database, then db:seed
pnpm db:restore --force   # the same, emptying the database first

The repository is public, so the snapshot carries no credentials: no password hashes, MFA secrets, sessions or reset tokens. After a restore the SEED_USER_* and SEED_DEMO_USER_* accounts sign in with the passwords in your .env; any other account uses forgot-password, whose link is printed in the API console while SMTP_URL is unset. Everything else in it — names, emails, chat messages — is readable by anyone, so keep real customer data out of dev.

Docker Engine inside WSL2, once (/etc/wsl.conf needs systemd=true):

sudo apt update && sudo apt install -y docker.io
sudo usermod -aG docker $USER && sudo systemctl enable --now docker
# then open a new terminal so the group membership applies

Conventions

  • Biome is the only linter/formatter — no ESLint, no Prettier.
  • Packages extend the root tsconfig.base.json directly; there is no typescript-config package.
  • Shared dependency versions go in the pnpm catalog: in pnpm-workspace.yaml.
  • turbo.json and biome.jsonc are JSONC — comment anything non-obvious.
  • Conventional commits, enforced by lefthook + commitlint.