# Phase 0 — Foundation & Infrastructure

**Goal**: Repo scaffolding, Docker environment, and authentication. After this phase, a developer can clone the repo, run `docker compose up`, and see a working authenticated "Hello World" page.

---

## Deliverables

1. Monorepo initialized with Turborepo
2. NestJS API with health endpoint
3. Next.js web app with landing page
4. Shared types package building and importable
5. Docker Compose with all services running
6. Keycloak configured with realm, roles, and test users
7. Auth guard protecting API routes
8. User and Household schemas with basic CRUD
9. Dev seed script
10. Linting and formatting

---

## Tasks

### 0.1 — Monorepo Setup

- Initialize root `package.json` with workspaces: `packages/*`
- Add Turborepo config (`turbo.json`) with pipelines: `build`, `dev`, `lint`, `test`
- Create three packages:
  - `packages/shared` — TypeScript library, compiled with `tsc`
  - `packages/api` — NestJS app (`@nestjs/cli` scaffold)
  - `packages/web` — Next.js app (`create-next-app` with App Router, TypeScript, Tailwind CSS)
- Root `tsconfig.base.json` with strict settings, extended by each package
- Configure package references so `api` and `web` depend on `shared`

### 0.2 — Shared Types (Initial)

Define in `packages/shared/src/`:

```typescript
// enums/roles.ts
export enum HouseholdRole {
  OWNER = 'owner',
  ADMIN = 'admin',
  MEMBER = 'member',
}

// types/user.ts
export interface User {
  id: string;
  keycloakId: string;
  displayName: string;
  email: string;
  householdIds: string[];
  defaultHouseholdId: string;
  createdAt: Date;
  updatedAt: Date;
}

// types/household.ts
export interface Household {
  id: string;
  name: string;
  ownerUserId: string;
  members: HouseholdMember[];
  inviteCode: string;
  settings: HouseholdSettings;
  createdAt: Date;
  updatedAt: Date;
}

export interface HouseholdMember {
  userId: string;
  role: HouseholdRole;
  joinedAt: Date;
}

export interface HouseholdSettings {
  timezone: string;
  currency: string;
  language: string;
}
```

- Add Zod validation schemas for create/update DTOs
- Export everything from `index.ts`

### 0.3 — Docker Compose

Create `docker/docker-compose.yml`:

```yaml
services:
  mongodb:
    image: mongo:7
    ports: ['27017:27017']
    volumes: [mongo-data:/data/db]
    environment:
      MONGO_INITDB_ROOT_USERNAME: meshitrack
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD}

  keycloak:
    image: quay.io/keycloak/keycloak:24.0
    ports: ['8080:8080']
    environment:
      KC_DB: dev-mem # Dev mode, in-memory DB
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: ${KC_ADMIN_PASSWORD}
    command: start-dev --import-realm
    volumes:
      - ./keycloak/realm-export.json:/opt/keycloak/data/import/realm-export.json

  api:
    build:
      context: ..
      dockerfile: docker/Dockerfile.api
    ports: ['3001:3001']
    depends_on: [mongodb, keycloak]
    environment:
      MONGODB_URI: mongodb://meshitrack:${MONGO_PASSWORD}@mongodb:27017/meshitrack?authSource=admin
      KEYCLOAK_URL: http://keycloak:8080
      KEYCLOAK_REALM: meshitrack
      KEYCLOAK_CLIENT_ID: meshitrack-api

  web:
    build:
      context: ..
      dockerfile: docker/Dockerfile.web
    ports: ['3000:3000']
    depends_on: [api]
    environment:
      NEXT_PUBLIC_API_URL: http://localhost:3001/api/v1
      NEXT_PUBLIC_KEYCLOAK_URL: http://localhost:8080
      NEXT_PUBLIC_KEYCLOAK_REALM: meshitrack
      NEXT_PUBLIC_KEYCLOAK_CLIENT_ID: meshitrack-web

  mongo-express:
    image: mongo-express
    ports: ['8081:8081']
    depends_on: [mongodb]
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: meshitrack
      ME_CONFIG_MONGODB_ADMINPASSWORD: ${MONGO_PASSWORD}
      ME_CONFIG_MONGODB_URL: mongodb://meshitrack:${MONGO_PASSWORD}@mongodb:27017/
    profiles: [dev]

volumes:
  mongo-data:
```

- Create `.env.example` with all required variables
- Create `Dockerfile.api` and `Dockerfile.web` (multi-stage builds)

### 0.4 — Keycloak Configuration

- Export a Keycloak realm JSON (`docker/keycloak/realm-export.json`) with:
  - Realm: `meshitrack`
  - Client: `meshitrack-web` (public, PKCE) for frontend
  - Client: `meshitrack-api` (bearer-only) for backend validation
  - Realm roles: `admin`, `member`
  - Custom protocol mapper: `household-mapper` that maps user attribute `householdIds` to JWT claim
  - Test users: `testuser1` / `testuser2` with passwords

### 0.5 — NestJS API Bootstrap

- `packages/api/src/main.ts`: bootstrap NestJS with:
  - Global prefix `/api/v1`
  - CORS configured for `http://localhost:3000`
  - Swagger/OpenAPI docs at `/api/docs`
  - Validation pipe (class-validator + class-transformer)
- Modules:
  - `AuthModule`: Keycloak strategy (`passport-openidconnect` or `nest-keycloak-connect`), `@AuthGuard` decorator, extract user + householdId from JWT
  - `UsersModule`: `User` Mongoose schema, sync user on first login (upsert from Keycloak token)
  - `HouseholdsModule`: `Household` Mongoose schema, CRUD endpoints
    - `POST /households` — create (creator becomes owner)
    - `GET /households/:householdId` — get (members only)
    - `POST /households/:householdId/invite` — generate invite code
    - `POST /households/join` — join via invite code
    - `PATCH /households/:householdId` — update settings (admin/owner)
  - `HealthModule`: `GET /api/v1/health` — returns `{ status: 'ok', version, uptime }`
- Common:
  - `HouseholdPlugin`: Fastify preHandler hook that reads `:householdId` from the URI, validates it against the user's `householdIds[]` JWT claim, and injects it into `request.householdId`
  - `CurrentUser` param decorator
  - `CurrentHousehold` param decorator
  - Global exception filter with consistent error response shape

### 0.6 — Next.js Web Bootstrap

- Configure `next-auth` or `keycloak-js` for OIDC login flow
- Pages:
  - `/login` — redirects to Keycloak
  - `/` — dashboard (protected, shows "Welcome, {name}" + household selector)
  - `/settings` — household management (create, invite, switch)
- Layout: navigation sidebar (placeholder links for future phases), top bar with user avatar + household switcher
- API client service (`packages/web/src/services/api-client.ts`): fetch wrapper that attaches the JWT `Authorization` header; household context is passed via URL (e.g. `/api/v1/households/:householdId/products`)

### 0.7 — Dev Seed Script

- `packages/api/src/scripts/seed.ts`:
  - Create 2 test users (matching Keycloak test users)
  - Create 1 household with both users as members
  - Log credentials and household ID to console

---

## Acceptance Criteria

- [ ] `docker compose up` starts all services without errors
- [ ] Navigating to `http://localhost:3000` redirects to Keycloak login
- [ ] After login, dashboard shows user name and household
- [ ] `GET /api/v1/health` returns 200
- [ ] `GET /api/v1/households/:id` returns 401 without token, 200 with valid token
- [ ] `packages/shared` types are importable from both `api` and `web`

---

## Dependencies

None — this is the foundation phase.

## Estimated Effort

Medium-large. Mostly boilerplate and configuration, but Keycloak setup requires careful attention.
