Setup initial project
This commit is contained in:
commit
db79af06f7
119 changed files with 20761 additions and 0 deletions
124
CLAUDE.md
Normal file
124
CLAUDE.md
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
MeshiTrack is a self-hosted medicine & nutrition management platform. It is a TypeScript monorepo with three packages: `packages/api` (Fastify backend), `packages/web` (Next.js frontend), and `packages/shared` (types + Zod schemas used by both). Medicine tracking is implemented first (Phases 1-4), followed by food tracking (Phases 5-9).
|
||||
|
||||
## 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)
|
||||
npm run test # Run all tests
|
||||
npm run test:cov # Run all tests with coverage
|
||||
npm run lint # Lint all packages
|
||||
npm run lint-fix # Auto-fix lint issues
|
||||
npm run typecheck # Type-check all packages
|
||||
npm run clean # Remove build artifacts
|
||||
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
|
||||
npm run test -- --watch -w packages/api # Watch mode
|
||||
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
|
||||
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
|
||||
```
|
||||
|
||||
## 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`
|
||||
- Route plugins use `fastify-plugin` (`fp()`) to export routes and register Awilix dependencies
|
||||
- Services receive dependencies via destructured constructor: `constructor({ productsRepository }: { productsRepository: ProductsRepository })`
|
||||
- Resolve services per-request via `request.diScope.resolve<T>('serviceName')`
|
||||
- All Mongoose read queries must use `.lean().exec()`
|
||||
|
||||
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/`, `cabinet/`, `regimens/`, `organizer/`, `medicine-prices/`, `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
|
||||
- Every directory has a barrel `index.ts`
|
||||
- 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
|
||||
|
||||
1. **No `any` types** — use `unknown` + Zod validation at boundaries
|
||||
2. **ESM everywhere** — `"type": "module"`, `.js` extensions on all imports, `import type` for type-only
|
||||
3. **Cursor-based pagination only** — never `skip()` for large collections
|
||||
4. **Zod v4** — import from `'zod/v4'`
|
||||
5. **`.lean().exec()`** on all Mongoose read queries
|
||||
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
|
||||
|
||||
## Testing
|
||||
|
||||
- **Unit tests**: Vitest, co-located with source files as `*.routes.test.ts` / `*.service.test.ts`
|
||||
- **Integration tests**: Vitest + `mongodb-memory-server` (`*.integration.test.ts`)
|
||||
- **Component tests**: React Testing Library (`__tests__/*.test.tsx`)
|
||||
- **E2E**: Playwright (root-level `e2e/`)
|
||||
- **Use `ClassName.name` for `describe` labels** (not string literals)
|
||||
- Coverage targets: 100% lines/functions/statements for `packages/api` and `packages/shared`; 90% branches
|
||||
- Mark untestable lines with `/* v8 ignore */`
|
||||
|
||||
## 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
|
||||
- `docs/cross-cutting.md` — API versioning, pagination, security, audit trail
|
||||
|
||||
## Git Conventions
|
||||
|
||||
Branches: `feature/MESH-001-description`, `fix/MESH-042-description`, `chore/description`
|
||||
|
||||
Commits follow Conventional Commits: `feat(products): add barcode lookup`, `fix(pantry): correct freshness calc`
|
||||
Loading…
Add table
Add a link
Reference in a new issue