TaskId (Single line text)Title (Single line text)Description (Long text)Status (Single line text)Assignee (Single line text)Position (Number)data.records:read, data.records:write, schema.bases:readapp...)Tasks.env.example to .env and fill in:AIRTABLE_API_KEY=your_token
AIRTABLE_BASE_ID=your_base_id
AIRTABLE_TABLE_NAME=Tasks
docker-compose up --build once — confirm app loads at localhost:3000docker-compose exec web npm run db:seed — confirm it worksdocker-compose exec web npm test — confirm all tests passmeera@taskboard.dev / password123 — explore the UI for 5 minutesdocker-compose down — you'll restart everything on cameralocalhost:3000 (will 404 until Docker starts — that's fine)Open Loom, start recording. Say out loud:
"Hi, I'm [your name]. I'll be walking through the TaskBoard senior fullstack assessment. I've read the assignment document and reviewed the repo structure beforehand. Let me get the environment running first."
[TERMINAL 1 ACTION] Run:
script -a terminal_log.txt
docker-compose up --build
Narrate:
"I'm starting the terminal log capture first — this file becomes my TERMINAL_LOG.md at the end. Then spinning up Docker."
[TERMINAL 1 ACTION] Once Docker is up, run:
docker-compose exec web npm run db:reset
Narrate:
"Running a database reset to ensure I'm starting from a clean seed state."
[TERMINAL 1 ACTION] Run:
docker-compose exec web npm test
Narrate:
"Running the initial test suite to confirm the baseline before I touch anything."
[BROWSER ACTION] Open localhost:3000, log in as meera@taskboard.dev / password123.
Show on camera:
Narrate:
"App is running. I can see the Kanban board. I'll note that Q3 Launch has the most data — 7 tasks and 4 members including a viewer role. I'll use this project for most of my testing. Now let me load the codebase into Claude Code before writing anything."
[TERMINAL 2 — CLAUDE CODE ACTION] Open Claude Code in the project directory. Paste Prompt 1 from your doc.
Narrate while Claude Code reads:
"I'm having Claude Code read the full codebase before touching anything. I want to understand the existing auth patterns and how roles are enforced — that'll guide exactly where I look for bugs."
[WAIT] Let Claude Code finish and read its summary on screen.
[CLAUDE CODE ACTION] Paste Prompt 2 from your doc.
Narrate while it works:
"I'm specifically directing it toward authorization gaps. In a multi-role app like this, the most critical bugs are usually where role checks are missing on mutation endpoints."
[MANUAL ACTION — IMPORTANT] When Claude Code responds, visibly open the files it references on screen. Read through each bug finding. Confirm it's real. Say out loud what you agree or disagree with. Evaluators are watching you review AI output — not blindly accept it.
[TERMINAL 1 ACTION] Get a viewer token using Dev Sharma's account:
curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"dev@example.com","password":"password123"}'
[TERMINAL 1 ACTION] Copy the token from the response. Run the bug proof curl:
curl -X PATCH http://localhost:3000/api/tasks/<any_task_id> \
-H "Authorization: Bearer <paste_viewer_token_here>" \
-H "Content-Type: application/json" \
-d '{"status":"done"}'
NOTE: Get a real task ID from the Q3 Launch project URL or from the API. The project ID is
cmpls4i0l0006tjafee8b8jd5— you can call GET/api/projects/cmpls4i0l0006tjafee8b8jd5/tasksto get task IDs.
Narrate:
"Dev Sharma is a viewer on this project. A viewer should not be able to modify tasks. The 200 response confirms the bug is real."
[MANUAL ACTION] Create REVIEW.md in the project root. Paste Claude Code's markdown output. Manually edit it — adjust any wording, add your own observations. Make it yours. Save it.
[TERMINAL 1 ACTION]
git add REVIEW.md
git commit -m "docs: add code review with top 4 issues"
Narrate:
"Now I'll fix the highest priority issue. I want Claude Code to follow existing patterns — no new libraries, surgical fix only."
[CLAUDE CODE ACTION] Paste Prompt 3 from your doc.
Narrate while it works:
"I want the fix minimal and conventional. A senior engineer doesn't over-engineer a bug fix."
[MANUAL ACTION] When Claude Code finishes, open the changed files on screen. Read what changed. Understand why. If anything looks over-engineered, push back to Claude Code before accepting.
[TERMINAL 1 ACTION] Run tests:
docker-compose exec web npm test
[TERMINAL 1 ACTION] Run the SAME curl command as Phase 3 with the SAME viewer token:
curl -X PATCH http://localhost:3000/api/tasks/<same_task_id> \
-H "Authorization: Bearer <same_viewer_token>" \
-H "Content-Type: application/json" \
-d '{"status":"done"}'
Narrate:
"Same request, same token — now correctly rejected with 403. Before and after proof is both captured in the terminal log."
[TERMINAL 1 ACTION]
git add -A
git commit -m "fix: enforce role-based authorization on task mutations"
Narrate:
"Moving to Part 3c — the mandatory Airtable export. Three focused steps: backend route, unit tests, then the frontend trigger."
[CLAUDE CODE ACTION] Paste Prompt 4 (3c-1) from your doc.
Narrate while it works:
"The upsert logic is the key requirement — the export must be idempotent so running it twice doesn't create duplicates in Airtable."
[MANUAL ACTION] Read the generated route file. Specifically verify:
[CLAUDE CODE ACTION] Paste Prompt 5 (3c-2) from your doc.
[TERMINAL 1 ACTION] Run tests:
docker-compose exec web npm test
[CLAUDE CODE ACTION] Paste Prompt 6 (3c-3) from your doc.
[TERMINAL 1 ACTION]
git add -A
git commit -m "feat: add Airtable export endpoint with upsert and retry logic"
[BROWSER ACTION — CRITICAL DEMO MOMENT]
Narrate:
"Now I'll trigger the export from the UI using Q3 Launch — it has 7 tasks across all statuses which makes for a good demo."
localhost:3000, go to the Q3 Launch project pagescreenshots/airtable-run1.png in the repoNarrate:
"All 7 tasks are now visible in Airtable. Now I'll run the export a second time to prove idempotency — same records should appear, no duplicates."
screenshots/airtable-run2.pngNarrate:
"Still 7 records — no duplicates. The upsert logic is working correctly."
[TERMINAL 1 ACTION]
mkdir -p screenshots
# save your two screenshots here as airtable-run1.png and airtable-run2.png
git add -A
git commit -m "feat: add Export to Airtable button on project detail page"
Narrate:
"Moving to Part 3a — task comments. Three prompts: schema update, API routes, then frontend and tests."
[CLAUDE CODE ACTION] Paste Prompt 7 (3a-1) from your doc.
[TERMINAL 1 ACTION] You run the migration yourself:
docker-compose exec web npx prisma migrate dev --name add_comments
Narrate:
"Running the migration myself — I want to be deliberate about when schema changes are applied to the database."
[CLAUDE CODE ACTION] Paste Prompt 8 (3a-2) from your doc.
[CLAUDE CODE ACTION] Paste Prompt 9 (3a-3) from your doc.
[TERMINAL 1 ACTION]
docker-compose exec web npm test
[BROWSER ACTION] Open a task in Q3 Launch on localhost:3000. Post a comment on camera. Show it appearing in the thread with author name and timestamp.
[TERMINAL 1 ACTION]
git add -A
git commit -m "feat: add append-only task comments with role-based authorization"
Narrate:
"Now Part 3b — the activity feed. Before I write a single line of code I need to make a design decision and commit it: if the audit log write fails, should the original operation roll back? My answer is no, and I'll document that reasoning now."
[MANUAL ACTION — WRITE THIS YOURSELF, DO NOT USE AI]
Create DESIGN_NOTES.md and type this yourself:
# Design Notes
## Activity Feed — Rollback Decision
Activity writes use a fire-and-forget pattern wrapped in try/catch.
If the audit log write fails, the error is logged server-side but
the original operation completes successfully and the user receives
a normal response. This prioritizes UX reliability over audit
completeness — a failed task update caused by a non-critical audit
entry would be a worse outcome than a missing log entry.
[TERMINAL 1 ACTION] Commit it immediately before building:
git add DESIGN_NOTES.md
git commit -m "docs: add design notes for activity feed rollback decision"
Narrate:
"Committing the design decision before implementation — the reasoning should exist independently of the code."
[CLAUDE CODE ACTION] Paste Prompt 10 (3b-1) from your doc.
[TERMINAL 1 ACTION] Run the migration yourself:
docker-compose exec web npx prisma migrate dev --name add_activity_feed
[CLAUDE CODE ACTION] Paste Prompt 11 (3b-2) from your doc.
[TERMINAL 1 ACTION]
docker-compose exec web npm test
[BROWSER ACTION] On camera:
[TERMINAL 1 ACTION]
git add -A
git commit -m "feat: add activity feed with fire-and-forget audit logging"
[CLAUDE CODE ACTION] Paste Prompt 12 from your doc.
[TERMINAL 1 ACTION] Run these yourself on camera:
docker-compose exec web npm run typecheck
docker-compose exec web npm test
Narrate:
"All tests passing, no TypeScript errors. Let me check the commit history is clean before pushing."
[TERMINAL 1 ACTION]
git log --oneline
Expected output:
feat: add activity feed with fire-and-forget audit logging
docs: add design notes for activity feed rollback decision
feat: add append-only task comments with role-based authorization
feat: add Export to Airtable button on project detail page
feat: add Airtable export endpoint with upsert and retry logic
fix: enforce role-based authorization on task mutations
docs: add code review with top 4 issues
[TERMINAL 1 ACTION]
git push origin main
[TERMINAL 1 ACTION] Stop the terminal log capture:
exit
[MANUAL ACTION] Open terminal_log.txt in VS Code:
code terminal_log.txt
Create TERMINAL_LOG.md and paste the relevant sections:
## 1. Setup Output
## 2. Initial Test Run
## 3. Bug Curl Proof (before fix)
## 4. Fix Curl Proof (after fix)
## 5. Airtable Export — First Run

## 6. Airtable Export — Second Run (no duplicates)

## 7. Comments Demo
## 8. Activity Feed Demo
## 9. Final Test Run
[TERMINAL 1 ACTION]
git add TERMINAL_LOG.md screenshots/
git commit -m "docs: add terminal log and screenshots"
git push origin main
Stop Loom recording.
Before submitting, confirm every single item:
REVIEW.md — 4 issues, curl proof for #1 issueTERMINAL_LOG.md — all 9 sections filled with real outputDESIGN_NOTES.md — rollback reasoning, written by youRECORDING.md — create with your Loom linkscreenshots/airtable-run1.png — tasks visible in Airtablescreenshots/airtable-run2.png — second run, no duplicates[TERMINAL ACTION] Final commit:
echo "# Recording\n\nLoom: YOUR_LOOM_LINK_HERE" > RECORDING.md
git add RECORDING.md
git commit -m "docs: add screen recording link"
git push origin main
Submit your repo URL. You're done. 🎯
Read the entire codebase carefully. Focus on:
1. src/app/api/ — all API route handlers
2. prisma/schema.prisma — the data model
3. src/lib/ — shared utilities including auth helpers
4. src/app/ — frontend pages and components
Don't write any code yet. Give me a structural summary:
- How JWT auth is implemented and where it's validated
- How role/membership checks are done (or not done) on API routes
- What the Prisma models look like
- How the frontend pages are structured
Based on your reading of the codebase, identify the top 4 bugs
prioritized by business impact. For each issue give me:
- File path and line number
- Category: Security / Performance / Architecture / Data Integrity / Testing
- Severity: Critical / High / Medium / Low
- 2-3 sentence description of the problem
- Recommended fix
- For the #1 issue only, a curl command I can run against
localhost:3000 to demonstrate the bug
Focus especially on: missing role/membership authorization on task
and project mutation endpoints, JWT handling, and missing ownership
checks. Format the output as markdown for REVIEW.md.
Fix the #1 critical issue you identified. Requirements:
- Use the existing Prisma client and auth patterns already
in the codebase — do not introduce new libraries
- Write Vitest tests that prove the bug exists (failing before fix)
and that your fix resolves it (passing after fix)
- Keep the fix minimal and surgical — do not refactor unrelated code
- Do not run any commands — just implement the fix and tests
Build the Airtable export backend for Next.js App Router (TypeScript).
Create: src/app/api/projects/[id]/export/airtable/route.ts
Requirements:
- POST handler only
- Validate JWT from Authorization header using the existing
auth pattern in this codebase
- Check the requesting user is admin or member of the project
(not viewer) using Prisma — fetch their Membership record
- Fetch all tasks for the project via Prisma
- Use the official `airtable` npm package (already in package.json)
- Read AIRTABLE_API_KEY, AIRTABLE_BASE_ID, AIRTABLE_TABLE_NAME
from process.env
- For each task, upsert using the task's id as the unique identifier:
search for an existing record with matching TaskId field first,
update if found, create if not — this makes the export idempotent
- Retry on 429 (rate limit) with exponential backoff, max 3 retries
- On permanent 4xx errors for a single record, log and skip —
do not fail the whole export
- Return JSON: { exported: number, skipped: number, errors: string[] }
- Do not run any commands
Write Vitest unit tests for the Airtable export route using the
existing src/lib/airtable-mock.ts test double. Test:
1. A viewer gets 403 forbidden
2. A non-member gets 403 forbidden
3. Successful export returns correct exported count
4. A single record 422 error is skipped, export continues
5. A 429 triggers retry logic
Use the same test patterns already in the codebase.
Do not run any commands.
Add an "Export to Airtable" button to the project detail page.
Find the existing project detail page component in src/app/ and add:
- A button visible only to admin and member roles (not viewers)
- On click, POST to /api/projects/[id]/export/airtable with JWT
from the existing auth context/session pattern in this codebase
- Show loading state while request is in flight
- On success show inline message: "Exported X tasks to Airtable"
- On error show the error message
- Use useMutation from TanStack Query consistent with existing
mutations in the codebase
- Style with Tailwind consistent with existing button styles
- Do not run any commands
Add a Comment model to prisma/schema.prisma:
- Fields: id (cuid), taskId (FK to Task), authorId (FK to User),
body (String, non-empty), createdAt (DateTime default now)
- No updatedAt field — comments are append-only by design
- Add the reverse relation fields to Task and User models
Only update the schema file. Do not run any commands.
Create the comments API route for Next.js App Router (TypeScript):
src/app/api/tasks/[id]/comments/route.ts
GET handler:
- Auth required
- User must be a member of the task's project (any role
including viewer can read)
- Returns all comments chronologically oldest first
- Include author name and email in each comment
POST handler:
- Auth required
- User must be admin or member — viewers get 403
- Body: { body: string }, validate with Zod (non-empty string)
- No PUT, PATCH, or DELETE handlers — comments are append-only
Use the existing auth and Prisma patterns from the codebase.
Do not run any commands.
Add a comments section to the task detail UI and write tests.
Frontend:
- Display comments list chronologically with author name,
body, and relative time (e.g. "2 hours ago")
- Textarea and submit button for posting, hidden from viewers
- useQuery to fetch comments, useMutation to post
- Optimistic update: add comment immediately, roll back on error
- Consistent Tailwind styling with the rest of the app
Vitest tests:
- Viewer can GET comments but gets 403 on POST
- Non-member gets 403 on both GET and POST
- Valid POST creates and returns the comment with author info
Do not run any commands.
Add an ActivityEvent model to prisma/schema.prisma:
- Fields: id (cuid), projectId (FK to Project), actorId (FK to User),
type (String), payload (Json), createdAt (DateTime default now)
- Add reverse relation fields to Project and User models
Create src/lib/activity.ts with a helper function:
logActivity(prisma, { projectId, actorId, type, payload })
This function writes the ActivityEvent inside a try/catch.
If it fails, log the error but do NOT throw — the caller must
not roll back because of a failed audit write.
Only update the schema file and create the lib file.
Do not run any commands.
Wire up activity logging and build the feed.
1. Call logActivity() after each of these existing operations:
- Task created (POST /api/projects/[id]/tasks)
- Task status changed (PATCH /api/tasks/[id])
- Task assignee changed (PATCH /api/tasks/[id])
- Comment posted (POST /api/tasks/[id]/comments)
2. Create GET /api/projects/[id]/activity:
- Auth required, project member only (any role)
- Returns last 50 events, most recent first
- Include actor name and human-readable description per event
3. Add an Activity Feed section to the project detail page:
- Shows who did what and when (relative time)
- useQuery with TanStack Query
- Consistent Tailwind styling with the rest of the app
Do not run any commands.
Do a final review pass:
1. Check every new API route has: auth check, membership/role check,
Zod input validation, and proper error responses (400/401/403/404)
2. Check for any TypeScript strict mode violations
3. Confirm no seed data was modified
4. List any issues found and fix them
Do not run any commands.
End of script.