# Multi-Tenant API — Harness Engineering (Advanced)

A multi-tenant user management API demonstrating harness engineering at the **advanced** adoption level. Every advanced feature in action.

## What is this?

A REST API where all data is isolated per tenant. Every request requires an `X-Tenant-ID` header. The API layer, middleware, services, and types each live in their own architectural layer with enforced boundaries.

The interesting part: custom linter rules, boundary schema enforcement, cross-artifact validation, all three personas, and a full state management lifecycle.

## Quick Start

```bash
cd examples/multi-tenant-api
npm install
npm test          # Run tests (should pass)
npm run lint      # Check all constraints (should pass)
harness validate  # Validate configuration
```

## Architecture

Four layers, strict one-way dependencies:

```
┌──────────┐
│   api/    │  ← Express routes (top layer)
├──────────┤
│services/  │  ← Business logic + Zod validation (middle)
├──────────┤
│middleware/ │  ← Tenant context extraction
├──────────┤
│  types/   │  ← Interfaces (bottom layer)
└──────────┘
```

### Tenant Isolation

Every request must include `X-Tenant-ID`. Middleware validates it before any route handler runs. Services take `tenantId` as their first parameter. The data store is partitioned by tenant.

See `docs/changes/tenant-isolation/proposal.md` for the full specification.

## Custom Linter Rules

`harness-linter.yml` defines custom rules generated by `harness linter generate`:

```yaml
rules:
  - name: no-direct-db-access
    type: import-restriction
    config:
      source: 'src/api/**'
      forbiddenImports: ['pg', 'mysql2', 'mongodb']
      message: 'API layer must not access database directly'
```

This generates an ESLint rule that prevents the API layer from importing database drivers directly. All data access must go through the services layer.

## Boundary Schema Enforcement

The `require-boundary-schema` ESLint rule checks that exported service functions contain Zod validation. Open `src/services/user-service.ts` to see Zod schemas validating inputs at the service boundary:

```typescript
const CreateUserSchema = z.object({
  name: z.string().min(1),
  email: z.string().email(),
});
```

## Cross-Artifact Validation

```bash
harness validate --cross-check
```

Checks that specs in `docs/changes/` align with the implementation. If the spec says something the code doesn't do (or vice versa), you'll get a warning.

## All Three Personas

| Persona                      | What it checks                                     |
| ---------------------------- | -------------------------------------------------- |
| **Architecture Enforcer**    | Layer violations, circular deps, forbidden imports |
| **Documentation Maintainer** | Doc drift, missing JSDoc on exports                |
| **Entropy Cleaner**          | Dead code, stale patterns, unused deps             |

## Specs and Changes

This project uses the `docs/changes/` convention:

- `docs/changes/` — Specs and proposals organized by feature
- `docs/changes/` — Proposals for new features (empty now, ready for use)

When planning a new feature, create `docs/changes/<feature>/proposal.md` with your design.

## State Deep Dive

Check `.harness.example/` to see the full state lifecycle:

| File                             | What it shows                                                                  |
| -------------------------------- | ------------------------------------------------------------------------------ |
| `state.json`                     | Position, progress (7/8 tasks), decisions with rationale, enriched lastSession |
| `learnings.md`                   | 5 tagged entries across 4 different skills                                     |
| `failures.md`                    | 2 dead-ends (AsyncLocalStorage, shared DB pool)                                |
| `handoff.json`                   | Planning → execution context transfer                                          |
| `archive/failures-2026-03-01.md` | Archived failures from a previous milestone                                    |

## Try Breaking Constraints

See [VIOLATIONS.md](./VIOLATIONS.md) for 4 exercises covering boundary schemas, layer violations, cross-artifact staleness, and missing documentation.
