🎬 TaskBoard Assessment — Complete 100-Minute Session Script

Final Version (All Corrections Incorporated)


⏰ PRE-SESSION — Do This Before Recording (NOT On Camera)

1. Airtable Setup

2. Repo & Environment Setup

AIRTABLE_API_KEY=your_token
AIRTABLE_BASE_ID=your_base_id
AIRTABLE_TABLE_NAME=Tasks

3. Prepare Your Prompts Doc

4. Tools Ready


🎬 START RECORDING NOW

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."


✅ PHASE 1 — Environment Setup

⏱ 0:00 – 0:10

[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."


✅ PHASE 2 — Context Loading

⏱ 0:10 – 0:18

[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.


✅ PHASE 3 — Code Review

⏱ 0:18 – 0:30

[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/tasks to 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"

✅ PHASE 4 — Fix #1 Critical Issue

⏱ 0:30 – 0:45

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"

✅ PHASE 5 — Part 3c: Airtable Export (Mandatory)

⏱ 0:45 – 1:10

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."

Narrate:

"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."

Narrate:

"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"

✅ PHASE 6 — Part 3a: Task Comments

⏱ 1:10 – 1:30

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"

✅ PHASE 7 — Part 3b: Activity Feed

⏱ 1:30 – 1:50

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"

✅ PHASE 8 — Final Checks & Wrap Up

⏱ 1:50 – 2:00

[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
![First Run](./screenshots/airtable-run1.png)
## 6. Airtable Export — Second Run (no duplicates)
![Second Run](./screenshots/airtable-run2.png)
## 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.


📤 POST-SESSION — Submission Checklist

Before submitting, confirm every single item:

[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. 🎯



📋 CLAUDE CODE PROMPTS

Copy these into your Google Doc before the session. Number them 1–12.


Prompt 1 — Context Loading (Phase 2)

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

Prompt 2 — Code Review (Phase 3)

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.

Prompt 3 — Fix #1 Issue (Phase 4)

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

Prompt 4 — Airtable Backend Route / 3c-1 (Phase 5)

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

Prompt 5 — Airtable Unit Tests / 3c-2 (Phase 5)

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.

Prompt 6 — Airtable Frontend Button / 3c-3 (Phase 5)

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

Prompt 7 — Comment Schema / 3a-1 (Phase 6)

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.

Prompt 8 — Comments API Routes / 3a-2 (Phase 6)

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.

Prompt 9 — Comments Frontend + Tests / 3a-3 (Phase 6)

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.

Prompt 10 — Activity Schema + Helper / 3b-1 (Phase 7)

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.

Prompt 11 — Activity Wire Up + Feed / 3b-2 (Phase 7)

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.

Prompt 12 — Final Review (Phase 8)

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.