Phase 5 cleanup

This commit is contained in:
Aerilyn Weber 2026-04-26 18:44:59 +09:00
parent 5536acd67d
commit 76a516a417
136 changed files with 6322 additions and 1985 deletions

View file

@ -9,6 +9,7 @@ MeshiTrack is a self-hosted medicine & nutrition management platform. It is a Ty
## Commands
### Root (all packages via Turborepo)
```bash
npm run dev # Start all services in dev mode
npm run build # Build all packages (shared → api/web)
@ -22,6 +23,7 @@ npm run seed # Seed the database (delegates to packages/api)
```
### Single package
```bash
npm run test -w packages/api # Run API tests
npm run test:cov -w packages/api # API tests with coverage
@ -30,6 +32,7 @@ npm run dev -w packages/api # API dev server only
```
### API package (packages/api)
```bash
npm run dev # tsx watch src/main.ts
npm run build # tsc
@ -37,6 +40,7 @@ npm run seed # tsx src/scripts/seed.ts
```
### Docker
```bash
docker compose -f docker/docker-compose.yml up -d # Start all services
docker compose -f docker/docker-compose.yml down # Stop all services
@ -45,11 +49,13 @@ docker compose -f docker/docker-compose.yml down # Stop all services
## Architecture
### Monorepo Structure
- **`packages/shared`** — Single source of truth for all domain types, enums, and Zod v4 schemas. Consumed by both `api` and `web`. Must be pure TypeScript with no Node.js, browser, or framework dependencies.
- **`packages/api`** — Fastify 5 backend. ESM-only, TypeScript strict. Uses Awilix for DI, Mongoose 9 for MongoDB, jose 6 for JWT verification.
- **`packages/web`** — Next.js 16 (React 19) frontend. App Router, Tailwind CSS 4.
### API Layer Architecture (Fastify + Awilix)
The API follows a **routes → services → repositories** pattern with Awilix constructor-injection DI:
- Each domain feature lives in `src/modules/<feature>/` with files: `*.routes.ts`, `*.service.ts`, `*.repository.ts`
@ -61,19 +67,23 @@ The API follows a **routes → services → repositories** pattern with Awilix c
Plugin registration order in `main.ts`: security → compression → swagger → DI container → database → auth → household guard → route modules.
### Domain Modules
**Medicine domain** (Phases 1-4): `medicines/`, `medicine-products/`, `cabinet/`, `regimens/`, `organizer/`, `medicine-prices/`, `purchases/`, `refills/`
**Food domain** (Phases 5-9): `products/`, `recipes/`, `pantry/`, `meal-plans/`, `grocery/`
**Shared**: `health/`, `users/`, `households/`, `stores/`, `llm/`
### Multi-tenancy
Every domain document is scoped to a `householdId`. A Fastify `preHandler` hook validates the `householdId` from the URI against the user's `householdIds[]` JWT claim. **Every data query must filter by `householdId`.**
Routes can opt out with `config: { public: true }` (skips auth) or `config: { skipHousehold: true }` (skips household validation).
### Auth
Keycloak is the OIDC provider. The API verifies JWTs via `jose`. The custom Keycloak protocol mapper injects `householdIds[]` into the JWT claims.
### Shared Package Rules
- All domain types and Zod schemas live here — never duplicate types across packages
- Import from `'zod/v4'` (not `'zod'`)
- Use `z.enum()` for enums, `z.email()` / `z.url()` as top-level calls
@ -81,12 +91,15 @@ Keycloak is the OIDC provider. The API verifies JWTs via `jose`. The custom Keyc
- Use `import type` for type-only imports
### Pagination
All list endpoints use cursor-based pagination. **Never use `skip()`** on MongoDB queries. Response shape:
```typescript
{ data: T[], pagination: { cursor: string | null, hasMore: boolean, total?: number } }
```
### Error Handling
Services throw `AppError` subclasses (`NotFoundError`, `ConflictError`, `ForbiddenError`, etc.). The global Fastify error handler maps them to the standard `ApiError` response shape (`statusCode`, `error`, `message`, `timestamp`, `path`).
## Key Rules
@ -99,6 +112,10 @@ Services throw `AppError` subclasses (`NotFoundError`, `ConflictError`, `Forbidd
6. **`householdId` filter** on every domain query — this is the multi-tenancy boundary
7. **No emojis** — never use emoji characters in source code, UI text, console output, or documentation
8. **`npx` is banned** — never run `npx` for any reason. Use `npm run <script>` for all test, lint, build, and tool invocations. No exceptions.
9. **Never pipe or redirect `npm run` commands** — run `npm run <script>` exactly as written; never append `2>&1`, `|`, `Select-Object`, `Select-String`, or any other shell constructs to it.
10. **Never use shell commands to read files** — always use `read_file` tool. Commands like `Get-Content`, `cat`, `head`, `tail` will be denied.
11. **Never use shell commands to search** — always use `grep_search` or `file_search`. Commands like `Select-String`, `grep`, `rg`, `find` will be denied.
12. **Every implementation task must end with `npm run build`, `npm run test`, and `npm run lint` all passing.**
## Testing
@ -113,6 +130,7 @@ Services throw `AppError` subclasses (`NotFoundError`, `ConflictError`, `Forbidd
## Documentation
Before writing code, consult the relevant docs:
- `docs/instructions/` — coding conventions, Fastify patterns, Next.js patterns, MongoDB, Zod/TypeScript, testing, Docker, Keycloak, Turborepo
- `docs/phases/` — per-phase specs with schemas, endpoints, and business logic
- `docs/architecture.md` — ADRs explaining key technology choices