|
| 1 | +# Interview Lab — Remediation Plan & Handoff |
| 2 | + |
| 3 | +**Date:** 2026-07-17 |
| 4 | +**PR #4 merged at:** 2026-07-17T05:33:17Z (commit `190b3be`) |
| 5 | + |
| 6 | +--- |
| 7 | + |
| 8 | +## Product context |
| 9 | + |
| 10 | +Interview Lab is a **free companion** to [Project Amazon PH Academy](https://projectamazon.ph). All features are available to all users — no paid tiers, no subscription gating. |
| 11 | + |
| 12 | +--- |
| 13 | + |
| 14 | +## ✅ Completed (PR #4 + follow-up) |
| 15 | + |
| 16 | +| Finding | Fix | |
| 17 | +|---|---| |
| 18 | +| FieldButton missing `outline` variant | Added outline variant to `fieldButtonVariants` | |
| 19 | +| Subscription checkout bypass | Removed subscription API endpoints entirely | |
| 20 | +| Subscription manage `change` action | Removed subscription API endpoints entirely | |
| 21 | +| JWT fallback secret | Requires 32+ char `JWT_SECRET` at startup | |
| 22 | +| Questions API unauthenticated | Server-side auth + tier checks; strips premium fields for free tier | |
| 23 | +| Guides API unauthenticated | Server-side auth + tier checks; locks content behind entitlement | |
| 24 | +| Verification token logged | Removed `console.log`; async/await DB calls | |
| 25 | +| Rate limiter non-atomic | Wrapped in `db.$transaction`; fail-closed | |
| 26 | +| Fabricated aggregate rating | Removed from structured data | |
| 27 | +| Pre-existing FieldBadge/Button type errors | Added missing variants | |
| 28 | +| Subscription tier gating | `subscription-guard.ts` always returns `allowed: true` | |
| 29 | +| Subscription endpoints | Removed `src/app/api/subscription/` entirely | |
| 30 | +| Pricing page / UpgradeModal / SubscriptionBanner | Stubbed to no-op (kept imports compiling) | |
| 31 | +| README pricing table | Replaced with "Free, always" notice | |
| 32 | + |
| 33 | +--- |
| 34 | + |
| 35 | +## 🔴 Phase 1 — Must fix before public launch |
| 36 | + |
| 37 | +### P1.1 — Server AI adapter |
| 38 | +**Files:** `src/lib/browser-llm-integration.ts`, `src/app/api/ai/*/route.ts` (4 routes) |
| 39 | +**Problem:** The `BrowserLLMIntegration` module is marked `"use client"` and depends on `window.ai`. Server routes import it and silently fall back to rule-based templates that fabricate experience claims. |
| 40 | +**Fix:** |
| 41 | +- Create `src/lib/server-ai.ts` with: |
| 42 | + - Schema-validated structured output (zod) |
| 43 | + - Explicit provider configuration (OpenAI/Anthropic) |
| 44 | + - Timeouts and abort handling |
| 45 | + - Input length limits |
| 46 | + - Per-user quota enforcement |
| 47 | + - Truthfulness checks |
| 48 | +- Replace all `BrowserLLMIntegration` imports in API routes |
| 49 | +- Add privacy/provider disclosure to UI |
| 50 | + |
| 51 | +### P1.2 — Client auth from server session |
| 52 | +**Files:** `src/lib/auth-context.tsx` |
| 53 | +**Problem:** Auth state restored from `localStorage` (modifiable); no server validation on startup. |
| 54 | +**Fix:** |
| 55 | +- Add `GET /api/auth/session` endpoint returning authenticated user from cookie |
| 56 | +- On app mount, validate session via server endpoint instead of reading localStorage |
| 57 | +- Keep localStorage as a cache layer with server re-validation |
| 58 | +- Ensure logout clears both cookie and localStorage atomically |
| 59 | + |
| 60 | +### P1.3 — ESLint fixes & re-enablement |
| 61 | +**Files:** `eslint.config.mjs`, `src/app/page.tsx`, `src/components/interview-lab/AdminPanel.tsx`, `PricingPage.tsx`, `QuestionBank.tsx` |
| 62 | +**Problem:** 35 rules disabled; 9 pre-existing ESLint errors block CI. |
| 63 | +**Fix:** |
| 64 | +- Fix the 9 ESLint errors across 4 files (setState in effects, hoisting, const reassignment) |
| 65 | +- Re-enable important rules incrementally: `no-unused-vars`, `no-console`, `react-hooks/exhaustive-deps`, `no-fallthrough` |
| 66 | +- Remove blanket `off` overrides |
| 67 | +- Add `lint-staged` pre-commit hook |
| 68 | + |
| 69 | +--- |
| 70 | + |
| 71 | +## 🟡 Phase 2 — Required within next development cycle |
| 72 | + |
| 73 | +### P2.1 — Rate limiter upgrade |
| 74 | +**Files:** `src/middleware.ts`, `src/lib/rate-limit.ts` |
| 75 | +**Problem:** In-memory `Map` in middleware doesn't persist across serverless instances; IP parsing trusts unvalidated `x-forwarded-for`. |
| 76 | +**Fix:** |
| 77 | +- Replace in-memory Map with Upstash/Redis for middleware rate limiting |
| 78 | +- Add trusted proxy chain configuration |
| 79 | +- Add `Retry-After` header with actual reset timestamp |
| 80 | + |
| 81 | +### P2.2 — Prisma schema hardening |
| 82 | +**Files:** `prisma/schema.prisma` |
| 83 | +**Changes needed:** |
| 84 | +- Convert string fields to enums: `role`, `difficulty`, `status`, `tier`, `billingPeriod`, `currency`, `fileType`, `subscriptionStatus`, `paymentStatus` |
| 85 | +- Add Prisma `Json` fields for: `toolsKnown`, `weakAreas`, `transcript`, `rubricBreakdown`, `truthFlags`, `answerKey`, `metadata` |
| 86 | +- Add indexes on: `userId`, `sessionId`, `questionId`, `expiresAt`, `resetTime`, `createdAt` |
| 87 | +- Model assessment attempts properly (user, timestamps, answers, score, rubrics, status, AI version) |
| 88 | + |
| 89 | +### P2.3 — Download route decomposition |
| 90 | +**Files:** `src/app/api/downloads/[id]/route.ts` (879 lines) |
| 91 | +**Problem:** Monolithic route handles auth, tier checks, 4 document formats, database access, and analytics. |
| 92 | +**Fix:** |
| 93 | +- Extract document builders: `src/lib/documents/pdf.ts`, `docx.ts`, `xlsx.ts`, `text.ts` |
| 94 | +- Extract template renderers: `src/lib/templates/amazon-training.ts` |
| 95 | +- Keep route focused on auth, routing, and response |
| 96 | + |
| 97 | +### P2.4 — Export endpoint size limits |
| 98 | +**Files:** `src/app/api/export/route.ts` |
| 99 | +**Problem:** No input size validation; PDF silently truncates at page bottom. |
| 100 | +**Fix:** |
| 101 | +- Add content length limits |
| 102 | +- Replace handcrafted PDF with proper pagination (e.g., `pdf-lib` or `pdfkit` with page break support) |
| 103 | +- Add request body size validation middleware |
| 104 | + |
| 105 | +### P2.5 — Add test coverage thresholds |
| 106 | +**Files:** `vitest.config.ts`, `__tests__/` |
| 107 | +**Problem:** Coverage configuration exists but has no minimum thresholds; excludes pages, layouts, and shared UI. |
| 108 | +**Fix:** |
| 109 | +- Set per-file coverage thresholds (e.g., 60% lines, 50% branches) |
| 110 | +- Remove blanket excludes for components |
| 111 | +- Add integration tests for auth flows, onboarding, interviews, resume gen, admin |
| 112 | +- Add browser tests for critical user journeys |
| 113 | + |
| 114 | +### P2.6 — Operational documentation |
| 115 | +**Problem:** README documents Bun runtime but CI uses npm; describes SQLite but schema is PostgreSQL; no standalone output config. |
| 116 | +**Fix:** |
| 117 | +- Standardize on one package manager (npm, given CI/Vercel use it) |
| 118 | +- Update README to reflect PostgreSQL-only schema |
| 119 | +- Add `output: "standalone"` to `next.config.ts` |
| 120 | +- Document required env vars with descriptions |
| 121 | +- Add setup/teardown scripts for development |
| 122 | + |
| 123 | +--- |
| 124 | + |
| 125 | +## ⚪ Phase 3 — Before public launch gate |
| 126 | + |
| 127 | +### P3.1 — Privacy & legal |
| 128 | +- Add privacy policy page with data retention and account deletion |
| 129 | +- Add AI provider disclosure (what data is sent to third-party APIs) |
| 130 | +- Resolve license contradiction (GPL v3 vs "Private, all rights reserved") |
| 131 | +- Add cookie consent banner |
| 132 | +- Add terms of service page |
| 133 | + |
| 134 | +### P3.2 — Honest structured data |
| 135 | +- Remove `offers.price: "0"` from structured data if product is truly free (or add proper "Free" offer) |
| 136 | +- Add real user review/rating system before claiming ratings |
| 137 | + |
| 138 | +### P3.3 — Security hardening |
| 139 | +- Session penetration tests |
| 140 | +- Authorization penetration tests on all API routes |
| 141 | +- Add `helmet`-style security headers |
| 142 | +- Rate limit all API endpoints consistently |
| 143 | +- Add input validation middleware for all POST/PUT routes |
| 144 | + |
| 145 | +### P3.4 — Operational readiness |
| 146 | +- Error monitoring (Sentry or similar) |
| 147 | +- Load tests on AI, export, and download endpoints |
| 148 | +- Accessibility audit (WCAG 2.1 AA) |
| 149 | +- Add health check endpoint (`GET /api/health`) |
| 150 | +- Add structured logging (not just `console.log`) |
| 151 | +- Database backup and restore procedure |
| 152 | + |
| 153 | +--- |
| 154 | + |
| 155 | +## 📊 Summary of remaining work |
| 156 | + |
| 157 | +| Phase | Items | Estimated effort | |
| 158 | +|---|---|---| |
| 159 | +| 🔴 Phase 1 (blockers) | 3 items | 2–3 sprints | |
| 160 | +| 🟡 Phase 2 (cycle) | 6 items | 4–6 sprints | |
| 161 | +| ⚪ Phase 3 (launch gate) | 4 items | 2–3 sprints | |
| 162 | + |
| 163 | +--- |
| 164 | + |
| 165 | +## 📝 Handoff notes |
| 166 | + |
| 167 | +### Current branch state |
| 168 | +- `main` at commit `190b3be` with PR #4 merged |
| 169 | +- Subscription system stubbed (not removed) to keep imports compiling |
| 170 | +- 3 stub files created: `PricingPage.tsx`, `UpgradeModal.tsx`, `SubscriptionBanner.tsx` |
| 171 | + |
| 172 | +### Key architecture decisions to carry forward |
| 173 | +1. **Auth:** JWT in HttpOnly cookies with DB re-verification on every request (keep this pattern) |
| 174 | +2. **Tier enforcement:** All subscription guard functions return `allowed: true` — product is free |
| 175 | +3. **Rate limiting:** The `db.$transaction` pattern is correct for persistent storage; middleware needs Redis/Upstash for serverless |
| 176 | +4. **AI:** Build a proper server adapter rather than trying to fix the client-side `BrowserLLMIntegration` |
| 177 | + |
| 178 | +### Files most likely to conflict with future work |
| 179 | +- `src/lib/browser-llm-integration.ts` — will be replaced entirely by P1.1 |
| 180 | +- `src/app/api/downloads/[id]/route.ts` — needs full decomposition (P2.3) |
| 181 | +- `prisma/schema.prisma` — needs migration (P2.2) |
| 182 | +- `eslint.config.mjs` — needs rules re-enabled (P1.3) |
| 183 | +- `src/lib/auth-context.tsx` — needs session endpoint (P1.2) |
| 184 | + |
| 185 | +### Stub files (to be removed when components are refactored) |
| 186 | +- `src/components/interview-lab/PricingPage.tsx` |
| 187 | +- `src/components/interview-lab/UpgradeModal.tsx` |
| 188 | +- `src/components/interview-lab/SubscriptionBanner.tsx` |
| 189 | +- `src/lib/use-subscription.ts` |
0 commit comments