# ANTIGRAVITY.md

This file provides guidance to Antigravity (the Gemini-based coding assistant) 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
```

## Implementation Workflow (TDD-First)

Every feature or phase implementation MUST start with a rigorous planning and design phase:

0.  **Mandatory Planning (Grilling)**: Before starting any feature or bug fix, you MUST invoke the `grill-with-docs` skill.
    - Run the skill using: `view_file` on `.agents/skills/grill-with-docs/SKILL.md` and follow its instructions.
    - Stress-test your plan against the existing domain model, terminology, and documentation (`CONTEXT.md`, ADRs, `docs/tdd-transition-plan.md`).
    - Decisions must be crystallized and documentation updated before moving to implementation.

1.  **Strict TDD Cycle**: All code changes must strictly follow the Red-Green-Refactor loop as detailed in [TDD Guide](docs/instructions/tdd.md). Do not write any production code before writing its failing test.

2.  **Vertical Slice TDD Order**: Build each vertical slice following this exact test-first sequence:
    - **Shared Layer**: Write validation schema tests first in `packages/shared/tests/` -> Implement schemas in `packages/shared/src/`.
    - **Database Layer**: Write integration tests in `packages/api/tests/` using `mongodb-memory-server` -> Implement Mongoose schemas and Repository in `packages/api/src/`. All reads must use `.lean().exec()`.
    - **Service Layer**: Write unit tests in `packages/api/tests/` using `createMockRepository` -> Implement business logic Service class in `packages/api/src/` with Awilix constructor injection.
    - **Route Layer**: Write route tests in `packages/api/tests/` using `app.inject` -> Implement Fastify route plugin in `packages/api/src/`.
    - **Web API Client**: Write service unit tests in `packages/web/tests/` using MSW mocking -> Implement the service client in `packages/web/src/`.
    - **Web UI**: Write component tests in `packages/web/tests/` using React Testing Library -> Implement Next.js pages and components in `packages/web/src/`. Use Server Components by default.

**Verification Gate (Mandatory)**:
Before considering a task complete, run:
- `npm run build`
- `npm run test:cov` (must meet 100/100/100/90 for API/Shared and 90/85/75/85 for Web)
- `npm run lint`

## 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/`, `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
- 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
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 `view_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. **Never call tools in parallel** — always wait for one tool call to complete before calling the next. This applies to all tools: file reads, searches, and terminal commands.
13. **Every implementation task must end with `npm run build`, `npm run test:cov`, and `npm run lint` all passing.** Always use `test:cov` (not `test`) to enforce coverage thresholds. If coverage fails, write additional tests before considering the task done.
14. **No `.js` extensions on `@/` imports in `packages/web`** — Next.js resolves TypeScript files directly; `.js` extensions on `@/` path-alias imports break Turbopack and webpack. Only use `.js` extensions in `packages/api` and `packages/shared` (Node ESM).

## 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:
    - `packages/api` & `packages/shared`: 100% lines/functions/statements, 90% branches
    - `packages/web`: 90% lines, 85% functions, 75% branches, 85% statements
- 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`
