|
| 1 | +--- |
| 2 | +description: "Generate the HackOps API contract — TypeScript types and Markdown reference — from the technical plan. Output: packages/shared/types/api-contract.ts + docs/api-contract.md" |
| 3 | +agent: agent |
| 4 | +tools: |
| 5 | + [ |
| 6 | + "read/readFile", |
| 7 | + "edit/editFiles", |
| 8 | + "edit/createFile", |
| 9 | + "search/textSearch", |
| 10 | + "search/fileSearch", |
| 11 | + "execute/runInTerminal", |
| 12 | + ] |
| 13 | +--- |
| 14 | + |
| 15 | +# Generate HackOps API Contract |
| 16 | + |
| 17 | +Generate the TypeScript API contract types and a human-readable reference document |
| 18 | +from the HackOps technical plan. |
| 19 | + |
| 20 | +## Mission |
| 21 | + |
| 22 | +Read the technical plan and produce two outputs: |
| 23 | + |
| 24 | +1. `packages/shared/types/api-contract.ts` — TypeScript interfaces (source of truth) |
| 25 | +2. `docs/api-contract.md` — human-readable endpoint reference |
| 26 | + |
| 27 | +The TypeScript types are imported by BOTH route handlers and frontend code. |
| 28 | +Type errors at compile time catch contract drift (Golden Principle 10). |
| 29 | + |
| 30 | +## Scope & Preconditions |
| 31 | + |
| 32 | +- Source: `.github/prompts/plan-hackOps.prompt.md` — read sections: |
| 33 | + - `Application Summary` (API surface: ~16 REST endpoints) |
| 34 | + - `Key Invariants` (auth and role rules) |
| 35 | + - `Phase 6` — Hackathon & Team Management endpoints |
| 36 | + - `Phase 7` — Scoring Engine & Submission endpoints |
| 37 | + - `Phase 8` — Leaderboard endpoint |
| 38 | + - `Phase 9` — Challenge Progression endpoints |
| 39 | + - `Phase 10` — Admin & Operational endpoints |
| 40 | + - `Phase 5` — authentication middleware (Easy Auth header contract) |
| 41 | +- Non-negotiable: `/api/health` is unauthenticated; all others require GitHub OAuth |
| 42 | + |
| 43 | +## Workflow |
| 44 | + |
| 45 | +### Step 1 — Read source material |
| 46 | + |
| 47 | +Read `.github/prompts/plan-hackOps.prompt.md` in full. Extract every endpoint |
| 48 | +mentioned across Phases 5-10 with: |
| 49 | + |
| 50 | +- HTTP method and path |
| 51 | +- Required role (Admin / Coach / Hacker / none) |
| 52 | +- Request body shape |
| 53 | +- Response shape |
| 54 | +- Possible error codes |
| 55 | + |
| 56 | +Group endpoints into these API groups: |
| 57 | + |
| 58 | +| Group | Prefix | Phase | |
| 59 | +| ----------- | ------------------ | ----- | |
| 60 | +| Health | `/api/health` | — | |
| 61 | +| Hackathons | `/api/hackathons` | 6 | |
| 62 | +| Teams | `/api/teams` | 6 | |
| 63 | +| Hackers | `/api/hackers` | 6 | |
| 64 | +| Submissions | `/api/submissions` | 7 | |
| 65 | +| Scores | `/api/scores` | 7 | |
| 66 | +| Rubrics | `/api/rubrics` | 7 | |
| 67 | +| Leaderboard | `/api/leaderboard` | 8 | |
| 68 | +| Challenges | `/api/challenges` | 9 | |
| 69 | +| Progression | `/api/progression` | 9 | |
| 70 | +| Roles | `/api/roles` | 10 | |
| 71 | +| Audit | `/api/audit` | 10 | |
| 72 | +| Config | `/api/config` | 10 | |
| 73 | + |
| 74 | +### Step 2 — Define shared types |
| 75 | + |
| 76 | +Before endpoint-specific types, define the shared building blocks: |
| 77 | + |
| 78 | +```typescript |
| 79 | +// Common response wrapper |
| 80 | +type ApiResponse<T> = { data: T; ok: true } | { error: string; ok: false }; |
| 81 | + |
| 82 | +// Role enum matching Easy Auth claims |
| 83 | +type UserRole = "admin" | "coach" | "hacker"; |
| 84 | + |
| 85 | +// Pagination |
| 86 | +type PageRequest = { continuationToken?: string; pageSize?: number }; |
| 87 | +type PageResponse<T> = { items: T[]; continuationToken?: string | null }; |
| 88 | +``` |
| 89 | + |
| 90 | +Derive all other shared types (e.g., `HackathonStatus`, `SubmissionState`) from |
| 91 | +the plan's invariants and phase descriptions. |
| 92 | + |
| 93 | +### Step 3 — Write TypeScript contract |
| 94 | + |
| 95 | +For each API group, write a TypeScript namespace containing: |
| 96 | + |
| 97 | +- Request type(s) |
| 98 | +- Response type(s) |
| 99 | +- Path constants |
| 100 | + |
| 101 | +Example structure: |
| 102 | + |
| 103 | +```typescript |
| 104 | +export namespace HackathonsAPI { |
| 105 | + export interface CreateRequest { |
| 106 | + name: string; |
| 107 | + eventCode: string; |
| 108 | + } |
| 109 | + export interface HackathonSummary { |
| 110 | + id: string; |
| 111 | + name: string; |
| 112 | + status: HackathonStatus; |
| 113 | + teamCount: number; |
| 114 | + } |
| 115 | + export const PATHS = { |
| 116 | + base: "/api/hackathons", |
| 117 | + byId: (id: string) => `/api/hackathons/${id}`, |
| 118 | + } as const; |
| 119 | +} |
| 120 | +``` |
| 121 | + |
| 122 | +Ensure: |
| 123 | + |
| 124 | +- All types are `export`ed |
| 125 | +- Event codes are `string` only (never expose the hash mechanism in types) |
| 126 | +- Submission states reflect the staging/approval invariant: `'pending' | 'approved' | 'rejected'` |
| 127 | +- Score types enforce rubric-driven structure (no free-form numeric fields) |
| 128 | + |
| 129 | +### Step 4 — Create the TypeScript file |
| 130 | + |
| 131 | +1. Create directory `packages/shared/types/` if it does not exist. |
| 132 | +2. Write `packages/shared/types/api-contract.ts` with the following JSDoc header: |
| 133 | + |
| 134 | +```typescript |
| 135 | +/** |
| 136 | + * HackOps API Contract |
| 137 | + * |
| 138 | + * Source of truth for all API request/response shapes. |
| 139 | + * Import from this file in route handlers and frontend components. |
| 140 | + * Do NOT duplicate these types elsewhere — let the compiler enforce the contract. |
| 141 | + * |
| 142 | + * Generated from: .github/prompts/plan-hackOps.prompt.md |
| 143 | + */ |
| 144 | +``` |
| 145 | + |
| 146 | +Run the type check below and fix any errors before proceeding: |
| 147 | + |
| 148 | +```bash |
| 149 | +npx tsc --noEmit --strict packages/shared/types/api-contract.ts 2>&1 || true |
| 150 | +``` |
| 151 | + |
| 152 | +### Step 5 — Write Markdown reference |
| 153 | + |
| 154 | +For each endpoint, write a reference block in `docs/api-contract.md`: |
| 155 | + |
| 156 | +```markdown |
| 157 | +### POST /api/submissions |
| 158 | + |
| 159 | +| Field | Value | |
| 160 | +| ---------- | ------------------------------------- | |
| 161 | +| Auth | Required (GitHub OAuth via Easy Auth) | |
| 162 | +| Role | Hacker | |
| 163 | +| Rate limit | 10 req/min per team | |
| 164 | + |
| 165 | +**Request body**: `SubmissionsAPI.CreateRequest` |
| 166 | + |
| 167 | +**Response 201**: `ApiResponse<SubmissionsAPI.SubmissionRecord>` |
| 168 | + |
| 169 | +**Error responses**: |
| 170 | + |
| 171 | +- `400` — Invalid rubric field or missing required answer |
| 172 | +- `403` — Cross-team submission attempt |
| 173 | +- `409` — Duplicate submission for same challenge |
| 174 | +``` |
| 175 | + |
| 176 | +### Step 6 — Create docs/api-contract.md |
| 177 | + |
| 178 | +Write the complete reference to `docs/api-contract.md` with: |
| 179 | + |
| 180 | +- Intro section explaining the TypeScript-first contract approach |
| 181 | +- Easy Auth header parsing section (how role is determined from headers) |
| 182 | +- All endpoint reference blocks grouped by API group |
| 183 | +- Error code catalogue at the end |
| 184 | + |
| 185 | +## Output Expectations |
| 186 | + |
| 187 | +- `packages/shared/types/api-contract.ts` — valid TypeScript, no type errors |
| 188 | +- `docs/api-contract.md` — every endpoint documented |
| 189 | +- All ~16 plan endpoints accounted for (plus `/api/health`) |
| 190 | +- TypeScript file has a JSDoc header linking back to the plan |
| 191 | + |
| 192 | +## Quality Assurance |
| 193 | + |
| 194 | +- [ ] `packages/shared/types/api-contract.ts` exists and is valid TypeScript |
| 195 | +- [ ] `docs/api-contract.md` exists |
| 196 | +- [ ] Every API group from Step 1 has at least one endpoint documented |
| 197 | +- [ ] `ApiResponse<T>` wrapper used consistently |
| 198 | +- [ ] `SubmissionState` type enforces `'pending' | 'approved' | 'rejected'` |
| 199 | +- [ ] `/api/health` documented as unauthenticated |
| 200 | +- [ ] `npm run lint:md` passes |
0 commit comments