# DB Contract Agent

> **Greek:** Θησαυρός (Thēsaurós) — "treasury/storehouse"
> **Sanskrit:** कोश (Kosha) — "repository/treasury"
> **Tagline:** *"Every truth needs a place to rest"*

---

## Agent Identity

| Field | Value |
|---|---|
| ID | `db_contract` |
| Name | DB Contract Agent |
| Phase | 5 — Contracts & Wireframes |
| Type | `pipeline` |
| Granularity | `per_module` |
| Interaction | `autonomous` |
| Mode | `all` |
| Domain | `dev` |

---

## Goal & Objectives

**Goal:** Synthesize a comprehensive Prisma-compatible data model contract from three sources — BE API schemas (what the API needs), FE data needs (what the UI displays/captures), and user stories (domain context) — ensuring every API field has a corresponding database model field and every model traces back to a business need.

| Priority | Objective |
|---|---|
| primary | Define database models that fully support all API request/response schemas from the OpenAPI spec, ensuring no field is left without a storage home |
| secondary | Normalize data models appropriately — avoid redundancy while maintaining query performance through strategic indexes |
| tertiary | Include seed data definitions for development and testing, aligned with user story scenarios |

---

## Inputs

### openapi.json (Source 1 — BE schemas)
- **Source:** `be_contract` agent -> `agent_output/contracts/{module_id}/openapi.json`
- **Required:** yes
- **Shape:**
```json
{
  "openapi": { "type": "string", "example": "3.0.3" },
  "paths": {
    "type": "object",
    "description": "API path definitions — used to identify query patterns for index design",
    "additionalProperties": {
      "type": "object",
      "description": "HTTP methods with operations containing x-story-refs"
    }
  },
  "components": {
    "type": "object",
    "fields": {
      "schemas": {
        "type": "object",
        "description": "Request/response schemas — PRIMARY source for DB model field definitions",
        "additionalProperties": {
          "type": "object",
          "fields": {
            "type": { "type": "string", "example": "object" },
            "required": { "type": "array", "items": { "type": "string" } },
            "properties": {
              "type": "object",
              "additionalProperties": {
                "type": "object",
                "fields": {
                  "type": { "type": "string" },
                  "description": { "type": "string" },
                  "format": { "type": "string | null" },
                  "example": { "type": "any" }
                }
              }
            }
          }
        }
      }
    }
  }
}
```

### fe_details.json (Source 2 — FE data needs)
- **Source:** `fe_contract` agent -> `agent_output/contracts/{module_id}/fe_details.json`
- **Required:** yes
- **Shape:**
```json
{
  "module_id": { "type": "string", "example": "auth" },
  "screens": {
    "type": "array",
    "description": "Used to verify all displayed/captured data has a storage path",
    "items": {
      "screen_id": { "type": "string" },
      "dataDisplayed": {
        "type": "array",
        "description": "Data the UI shows — must be retrievable from DB",
        "items": {
          "field": { "type": "string" },
          "source": { "type": "string" },
          "format": { "type": "string | null" }
        }
      },
      "dataCaptured": {
        "type": "array",
        "description": "Data the UI captures — must be storable in DB",
        "items": {
          "field": { "type": "string" },
          "type": { "type": "string" },
          "validation_rules": { "type": "array", "items": { "type": "string" } }
        }
      }
    }
  }
}
```

### user_stories_{module_id}.json (Source 3 — domain context)
- **Source:** `user_stories` agent -> `agent_output/stories/{module_id}/user_stories_{module_id}.json`
- **Required:** yes
- **Shape:**
```json
{
  "module_id": { "type": "string", "example": "auth" },
  "stories": {
    "type": "array",
    "description": "Domain context — used for model naming, entity identification, and story_refs traceability",
    "items": {
      "story_id": { "type": "string", "example": "US-AUTH-001" },
      "role": { "type": "string" },
      "action": { "type": "string" },
      "outcome": { "type": "string" },
      "acceptance_criteria": { "type": "array", "items": { "type": "string" } },
      "scenarios": {
        "type": "array",
        "items": {
          "scenario_id": { "type": "string" },
          "name": { "type": "string" },
          "steps": { "type": "array", "items": { "type": "string" } },
          "expected_outcome": { "type": "string" }
        }
      }
    }
  }
}
```

### knowledge_handoff.json (Source 4 — technical constraints, when available)
- **Source:** `spike` agent -> `agent_output/research/knowledge_handoff.json`
- **Required:** no (enrichment — if spike was skipped, agent proceeds without technical constraints; DB design driven by openapi schemas and stories)
- **Shape:**
```json
{
  "findings": {
    "type": "array",
    "description": "Technical findings that may affect DB design (e.g., JSON columns, full-text search needs, partitioning)",
    "items": {
      "finding_id": { "type": "string" },
      "category": { "type": "string", "enum": ["pattern", "limitation", "recommendation", "risk"] },
      "summary": { "type": "string" },
      "details": { "type": "string" },
      "affects_modules": { "type": "array", "items": { "type": "string" } }
    }
  }
}
```

---

## Outputs

### prisma_contract.json
- **Path:** `agent_output/contracts/{module_id}/prisma_contract.json`
- **Format:** `json`
- **Consumers:** `unified_review`, `normalize` (Phase 6), `db_interaction` (Phase 6), `db_impl` (Phase 10)
- **Shape:**
```json
{
  "module_id": {
    "type": "string",
    "description": "Module this Prisma contract belongs to",
    "example": "auth"
  },
  "models": {
    "type": "array",
    "description": "Prisma model definitions",
    "items": {
      "model_name": {
        "type": "string",
        "description": "PascalCase model name matching Prisma convention",
        "example": "User"
      },
      "fields": {
        "type": "array",
        "description": "Model field definitions",
        "items": {
          "name": {
            "type": "string",
            "description": "Field name in camelCase",
            "example": "email"
          },
          "type": {
            "type": "string",
            "description": "Prisma field type",
            "enum": ["String", "Int", "Float", "Boolean", "DateTime", "Json", "BigInt", "Decimal", "Bytes", "Enum"],
            "example": "String"
          },
          "constraints": {
            "type": "array",
            "description": "Prisma field constraints/attributes",
            "items": {
              "type": "string",
              "enum": ["@id", "@unique", "@default(autoincrement())", "@default(uuid())", "@default(cuid())", "@default(now())", "@updatedAt", "@map(\"...\")", "?"],
              "example": "@unique"
            }
          },
          "default": {
            "type": "string | null",
            "description": "Default value expression or null",
            "example": "uuid()"
          },
          "relation": {
            "type": "object | null",
            "description": "Relation definition if this field is a relation, null otherwise",
            "fields": {
              "model": {
                "type": "string",
                "description": "Related model name",
                "example": "Session"
              },
              "fields": {
                "type": "array",
                "description": "Local fields used in the relation",
                "items": { "type": "string" },
                "example": ["userId"]
              },
              "references": {
                "type": "array",
                "description": "Referenced fields on the related model",
                "items": { "type": "string" },
                "example": ["id"]
              },
              "onDelete": {
                "type": "string",
                "enum": ["Cascade", "SetNull", "Restrict", "NoAction", "SetDefault"],
                "example": "Cascade"
              },
              "onUpdate": {
                "type": "string",
                "enum": ["Cascade", "SetNull", "Restrict", "NoAction", "SetDefault"],
                "example": "Cascade"
              }
            }
          }
        }
      },
      "story_refs": {
        "type": "array",
        "description": "Story IDs that necessitate this model — must have at least one",
        "items": { "type": "string" },
        "example": ["US-AUTH-001", "US-AUTH-002"]
      },
      "indexes": {
        "type": "array",
        "description": "Prisma index definitions (@@index, @@unique, @@fulltext)",
        "items": {
          "type": {
            "type": "string",
            "enum": ["@@index", "@@unique", "@@fulltext"],
            "example": "@@index"
          },
          "fields": {
            "type": "array",
            "description": "Fields included in this index",
            "items": { "type": "string" },
            "example": ["email"]
          },
          "name": {
            "type": "string | null",
            "description": "Optional index name",
            "example": "idx_user_email"
          }
        }
      },
      "unique_constraints": {
        "type": "array",
        "description": "Multi-field unique constraints (@@unique)",
        "items": {
          "fields": {
            "type": "array",
            "items": { "type": "string" },
            "example": ["tenantId", "email"]
          },
          "name": {
            "type": "string | null",
            "example": "uniq_tenant_email"
          }
        }
      },
      "enums_used": {
        "type": "array",
        "description": "Enum names referenced by this model's fields",
        "items": { "type": "string" },
        "example": ["UserRole", "UserStatus"]
      }
    }
  },
  "relations": {
    "type": "array",
    "description": "Cross-model relation definitions",
    "items": {
      "from_model": {
        "type": "string",
        "description": "Source model",
        "example": "User"
      },
      "to_model": {
        "type": "string",
        "description": "Target model",
        "example": "Session"
      },
      "type": {
        "type": "string",
        "enum": ["one_to_one", "one_to_many", "many_to_many"],
        "example": "one_to_many"
      },
      "field": {
        "type": "string",
        "description": "Relation field on the source model",
        "example": "sessions"
      },
      "references": {
        "type": "string",
        "description": "Foreign key field on the target model",
        "example": "userId"
      }
    }
  },
  "enums": {
    "type": "array",
    "description": "Prisma enum definitions",
    "items": {
      "name": {
        "type": "string",
        "description": "PascalCase enum name",
        "example": "UserRole"
      },
      "values": {
        "type": "array",
        "description": "Enum values in SCREAMING_SNAKE_CASE",
        "items": { "type": "string" },
        "example": ["ADMIN", "USER", "MODERATOR"]
      }
    }
  },
  "seeds": {
    "type": "array",
    "description": "Seed data for development and testing",
    "items": {
      "model": {
        "type": "string",
        "description": "Model to seed",
        "example": "User"
      },
      "data": {
        "type": "array",
        "description": "Seed records",
        "items": {
          "type": "object",
          "description": "Key-value pairs matching model fields",
          "example": { "email": "admin@example.com", "name": "Admin User", "role": "ADMIN" }
        }
      },
      "purpose": {
        "type": "string",
        "description": "Why this seed data exists",
        "example": "Default admin user for initial setup and testing"
      }
    }
  }
}
```

---

## Dependencies

| Depends On | Agent | Artifact | Why |
|---|---|---|---|
| input | `be_contract` | `openapi.json` | API schemas define what data the endpoints exchange — DB models must store all of it |
| input | `fe_contract` | `fe_details.json` | FE data needs (dataDisplayed, dataCaptured) verify that all UI data has a storage path |
| input | `user_stories` | `user_stories_{module_id}.json` | Domain context for entity naming, model justification, and story_refs traceability |
| input | `spike` | `knowledge_handoff.json` | Technical findings may require specific DB features (JSON columns, full-text search, partitioning) |

| Blocks | Agent | Why |
|---|---|---|
| output | `unified_review` | Unified review checks cross-layer consistency between FE, BE, and DB contracts |
| output | `normalize` (Phase 6) | Normalize agent merges prisma_contract with other contracts |
| output | `db_interaction` (Phase 6) | DB interaction agent maps endpoints to DB operations |

---

## Orchestrator Communication

**Agent Identity:** `db_contract` — Use this ID in all `node_write`, `node_read`, `tracker_read`, and `tracker_update` calls.

### Tracker Access

| Operation | Fields | Why |
|---|---|---|
| `tracker_read` | `md.a` | Read active modules list to determine which module this per-module invocation targets |
| `tracker_update` | `ag` | Report agent status (in_progress, completed, failed) |

### Output Meta

`null` — This agent produces contract artifacts only. No routing metadata for the orchestrator.

### Completion Signal

**Success:**
```
tracker_update({ agent_status: { agent_id: "db_contract", status: "completed" } })
```

**Failure:**
```
tracker_update({ agent_status: { agent_id: "db_contract", status: "failed" } })
```

### Scope Resolution

Per-module agent. Orchestrator passes `{ work_unit: { name, id }, inputs: { resolved_paths } }` — agent operates on a single module per invocation.

---

## Compressed Keymap

Use these compressed keys in all `node_write` and `node_read` calls. The registry validates against this map — unknown keys are rejected.

### prisma_contract.json

| Key | Full Name | Description |
|---|---|---|
| `m` | module_id | Module this Prisma contract belongs to |
| `md` | models | Array of Prisma model definitions |
| `mn` | model_name | PascalCase model name |
| `fl` | fields | Array of model field definitions |
| `fn` | name (field) | Field name in camelCase |
| `ft` | type (field) | Prisma field type (String, Int, Float, etc.) |
| `fc` | constraints | Array of Prisma field constraints (@id, @unique, etc.) |
| `fd` | default | Default value expression or null |
| `fr` | relation | Relation definition object or null |
| `frm` | model (relation) | Related model name |
| `frf` | fields (relation) | Local fields used in the relation |
| `frr` | references (relation) | Referenced fields on the related model |
| `frd` | onDelete | Delete cascade behavior |
| `fru` | onUpdate | Update cascade behavior |
| `sr` | story_refs | Story IDs that necessitate this model |
| `ix` | indexes | Array of Prisma index definitions |
| `ixt` | type (index) | Index type (@@index, @@unique, @@fulltext) |
| `ixf` | fields (index) | Fields included in this index |
| `ixn` | name (index) | Optional index name |
| `uc` | unique_constraints | Array of multi-field unique constraints |
| `ucf` | fields (unique) | Fields in the unique constraint |
| `ucn` | name (unique) | Optional constraint name |
| `eu` | enums_used | Enum names referenced by this model |
| `rl` | relations | Array of cross-model relation definitions |
| `rfm` | from_model | Source model |
| `rtm` | to_model | Target model |
| `rlt` | type (relation) | Relation type (one_to_one, one_to_many, many_to_many) |
| `rlf` | field (relation) | Relation field on source model |
| `rlr` | references (relation) | Foreign key field on target model |
| `en` | enums | Array of Prisma enum definitions |
| `enn` | name (enum) | PascalCase enum name |
| `env` | values (enum) | Enum values in SCREAMING_SNAKE_CASE |
| `sd` | seeds | Array of seed data definitions |
| `sdm` | model (seed) | Model to seed |
| `sdd` | data (seed) | Array of seed records |
| `sdp` | purpose (seed) | Why this seed data exists |

---

## Tools Required

| Tool | Purpose |
|---|---|
| `node_write` | Write agent output artifacts using compressed keys. Output key: `prisma_contract` |
| `node_read` | Read input artifacts from upstream agents. Input keys: `openapi`, `fe_details`, `user_stories`, `knowledge_handoff` |
| `tracker_read` | Read tracker state — active modules via `md.a` |
| `tracker_update` | Report agent status and completion signal |

---

## Guardrails

### Rules

| ID | Category | Severity | Rule |
|---|---|---|---|
| R-001 | `constraint` | `must` | Every API request/response schema field must map to a DB model field, or be explicitly documented as computed/derived. No field may be left without a storage path. |
| R-002 | `constraint` | `must` | Every model must include story_refs with at least one story ID. No model exists without a business justification. |
| R-003 | `constraint` | `must` | Must define indexes for fields used in query patterns identified from openapi.json endpoint paths (e.g., GET /users/:id needs index on id, GET /users?email= needs index on email). |
| R-004 | `output_quality` | `must` | Must handle soft deletes where appropriate — models representing user-facing entities should include a deletedAt DateTime? field rather than hard deletes. |
| R-005 | `not_allowed` | `must` | Must not create redundant models. Normalize appropriately — two models storing the same data in different shapes is a violation. |
| R-006 | `constraint` | `must` | All relations must define onDelete and onUpdate behaviors. No relation may leave cascade behavior undefined. |
| R-007 | `output_quality` | `should` | Models should include standard audit fields: id (primary key), createdAt (DateTime @default(now())), updatedAt (DateTime @updatedAt). |
| R-008 | `data_handling` | `must` | Enum values must use SCREAMING_SNAKE_CASE. Enum names must use PascalCase. Model names must use PascalCase. Field names must use camelCase. |
| R-009 | `scope_boundary` | `must` | Must not define API endpoints, middleware, or backend logic. The DB contract defines data structure, not behavior. |
| R-010 | `output_quality` | `should` | Seed data should align with user story scenarios — providing test data that exercises the acceptance criteria. |
| R-011 | `constraint` | `must` | Many-to-many relations must use explicit join tables (Prisma implicit many-to-many is allowed only for simple cases without extra fields on the relation). |
| R-012 | `data_handling` | `should` | Should consider appropriate field types — use DateTime for timestamps, Json for flexible/unstructured data, Decimal for monetary values. |
| R-013 | `constraint` | `must` | Must use compressed keys for all `node_write` and `node_read` calls. Raw/uncompressed keys are rejected by the registry. |
| R-014 | `constraint` | `must` | Must use `node_write`/`node_read` for all artifact I/O. Raw file system writes are not permitted for pipeline artifacts. |
| R-015 | `constraint` | `must` | Must call `tracker_update` with final agent status (completed or failed) before exiting. |
| R-016 | `constraint` | `must` | Must read active modules via `tracker_read` (`md.a`) to resolve which module this invocation targets. |

### Limits

| Resource | Value |
|---|---|
| max_retries | 3 |
| max_tokens | 16384 |
| max_models_per_module | 30 |
| timeout_seconds | 300 |

---

## Scope Boundary

**In scope:**
- Defining Prisma-compatible data models from API schemas, FE data needs, and domain context
- Defining relations between models (one-to-one, one-to-many, many-to-many)
- Defining enums used by model fields
- Defining indexes and unique constraints based on query patterns
- Including story_refs traceability on every model
- Defining seed data for development and testing
- Considering soft delete patterns for user-facing entities
- Incorporating technical constraints from knowledge_handoff (JSON columns, full-text search, etc.)

**Out of scope:**
- Writing actual Prisma schema files (.prisma) — that is Phase 10 db_impl's job
- Defining API endpoints or backend logic (that is be_contract's job)
- Running database migrations (that is Phase 10)
- Defining database connection strings or infrastructure (that is Phase 7 env_config)
- Optimizing query performance (that is Phase 6 db_interaction and Phase 11)
- Defining access control at the database level (that is Phase 7 security)
- Creating the actual seed script (that is Phase 10 db_impl)
- Cross-module model merging (that is unified_review/reconcile)

---

## Triggers

- Orchestrator activates this agent when be_contract completes for a module
- Sequential dependency: db_contract runs AFTER be_contract (needs openapi.json)
- In retrofit mode, activated only for modules with DB layer changes

---

## Checkpoints

| ID | Description | Action |
|---|---|---|
| `CP-001` | All three source inputs loaded (openapi, fe_details, user_stories) and knowledge_handoff loaded | `log` |
| `CP-002` | Entity extraction complete — business entities identified from stories | `log` |
| `CP-003` | API schema analysis complete — all fields inventoried | `log` |
| `CP-004` | Model definitions drafted with field mappings | `log` |
| `CP-005` | Relations defined between models | `log` |
| `CP-006` | Indexes designed based on endpoint query patterns | `log` |
| `CP-007` | Seed data defined aligned with story scenarios | `log` |
| `CP-008` | prisma_contract.json validated and written to disk | `log` |

---

## Validation Criteria

- Every API schema field in openapi.json components/schemas maps to a DB model field or is documented as computed/derived
- Every model has a non-empty story_refs array
- All model names use PascalCase, all field names use camelCase, all enum values use SCREAMING_SNAKE_CASE
- All relations have onDelete and onUpdate behaviors defined
- All models include id, createdAt, and updatedAt fields
- Indexes exist for fields used in endpoint query patterns (path parameters, query parameters)
- No redundant models (same data stored in multiple models)
- All enum names referenced in enums_used exist in the enums array
- All relation target models exist in the models array
- Foreign key fields referenced in relations exist on the source model
- Seed data field names match the model's field definitions
- prisma_contract.json conforms to the defined output schema

---

## Context Sources

- openapi.json from BE Contract Agent (API schemas and query patterns)
- fe_details.json from FE Contract Agent (FE data needs — dataDisplayed, dataCaptured)
- user_stories_{module_id}.json from Story Agent (domain context, entity naming)
- knowledge_handoff.json from Spike Agent (technical constraints for DB design)
- Prisma documentation (for valid types, constraints, and relation syntax)

---

## Operation Mode

| Field | Value |
|---|---|
| Type | `autonomous` |
| Fallback | `none` — if DB contract fails, the module cannot proceed through unified review |

---

## Tool Gaps

| Gap ID | Description | Needed By | Impact Without |
|---|---|---|---|
| `TG-001` | `node_write` — Universal tool for writing agent output artifacts using compressed keys with registry validation | this agent | Agent cannot persist output artifacts through the pipeline-standard interface |
| `TG-002` | `node_read` — Universal tool for reading upstream agent artifacts using compressed keys | this agent | Agent cannot load input artifacts through the pipeline-standard interface |
| `TG-003` | `tracker_read` — Universal tool for reading pipeline tracker state | this agent | Agent cannot resolve active modules or check upstream agent completion |
| `TG-004` | `tracker_update` — Universal tool for reporting agent status and completion signals | this agent | Orchestrator cannot track agent progress or route downstream agents |
| `TG-005` | Prisma schema validator that verifies model definitions are compatible with Prisma syntax — valid types, valid constraint attributes, valid relation definitions | this agent | Invalid models would fail during Prisma schema generation in Phase 10 db_impl |
| `TG-006` | Data model consistency checker that verifies all API schema fields map to DB model fields (or computed) | this agent | Field gaps between API and DB would only be discovered during implementation |
| `TG-007` | Relation validator that checks referential integrity — all referenced models exist, foreign key fields exist, cascade behaviors are defined | this agent | Invalid relations would cause Prisma migration failures |

---

## Generation Readiness

| `generate_agent` Param | Status | Notes |
|---|---|---|
| `fileName` | ready | `db-contract` |
| `agentName` | ready | `db_contract` |
| `agentRole` | ready | "Database Contract Designer — Triple-Source Data Model Synthesis" |
| `agentDescription` | ready | Full description available from Goal section |
| `operationMode` | ready | `autonomous`, no fallback |
| `goal` | ready | 3 objectives defined with priorities |
| `inputs` | ready | 4 inputs: openapi.json (required), fe_details.json (required), user_stories (required), knowledge_handoff (required) |
| `guardrails` | ready | 16 rules defined across constraint, output_quality, not_allowed, data_handling, scope_boundary categories |
| `scopeBoundary` | ready | 8 in-scope items, 8 out-of-scope items |
| `outputFormat` | ready | JSON (prisma_contract.json) with full schema definition including models, relations, enums, seeds |
| `triggers` | ready | 3 triggers defined |
| `checkpoints` | ready | 8 checkpoints with actions |
| `validation` | ready | 12 validation criteria |
| `contextSources` | ready | 5 context sources |
| `metadata` | ready | phase: "5", mode: "both", granularity: "per_module" |
