Working Session: Local Dev & the Contribution Workflow

Reminders
- OPEN: The Ticket Hunt — due Wed Sep 16
- OPEN: Project Bids — due Thu Sep 17
- OPEN: Onboarding: Gradebook Column Groups — due Thu Sep 24
CS 4535: Software Design & Delivery
Working Session: Local Dev & the Contribution Workflow
©2026 Jonathan Bell, CC-BY-SA
Learning Objectives
After this session, you'll be able to:
- Run Pawtograder locally against a seeded database
- Trace a change through branch, PR, CI, review, merge and deploy
- Claim a hunt role, and say what makes a ticket somebody can act on
- Know where and how to ask for help when stuck
You Leave This Room With Two Things
1. Pawtograder running on your machine
2. A hunt role with your name on it
Everything else this semester is downstream of those two facts.
Two Ways to Run Pawtograder

Which One Do You Need?
| If your work touches… | You need |
|---|---|
| Docs, copy, a component, a page layout | Path A — staging backend |
| A database migration or an RLS policy | Path B — full local |
| An edge function | Path B — full local |
| Playwright end-to-end tests | Path B — full local |
| Anything you aren't sure about | Start with A, escalate |
Signups are disabled on staging. In a local instance, any email works — and putting instructor in the address makes you an instructor.
Path A: Frontend Against Staging
git clone https://github.com/pawtograder/platform
cd platform
nvm install 22 && nvm use 22
npm install # ignore the deprecation wall
cp .env.local.staging .env.local # nothing to fill in
npm run dev # https://localhost:3000
Your browser will warn you about the self-signed certificate. That's expected — click through. HTTPS is required for camera and microphone access in the help queue.
Sign in with email and password. OAuth on staging redirects to the deployed site, not your laptop.
Every command on the next few slides also lives at /docs/local-dev.
Path B: The Full Local Stack
# Docker must be running first
npx supabase start # boots Postgres, Auth, Realtime, Storage
npx supabase db reset # replays 400+ migrations, loads base data
# the CLI's key names are not the app's. Rename them on the way out:
npx supabase status -o env \
--override-name api.url=NEXT_PUBLIC_SUPABASE_URL \
--override-name auth.anon_key=NEXT_PUBLIC_SUPABASE_ANON_KEY \
--override-name auth.service_role_key=SUPABASE_SERVICE_ROLE_KEY >> .env.local
npm run seed # a test class with real logins
npm run dev
# only when you're exercising an edge function:
npx supabase functions serve --env-file .env.local
Then three by hand, which no command emits: SUPABASE_URL and SUPABASE_ANON_KEY (same values, without the NEXT_PUBLIC_), and ENABLE_SIGNUPS=true.
Then: app on https://localhost:3000 · Studio on localhost:54323 · captured mail on localhost:54324
dev Is For Editing. Otherwise, Build.
npm run dev # compiles each route on first hit
npm run build && npm start # a few minutes, then fast everywhere
next dev recompiles per route as you click. Fine while you're editing one page. Painful when you're exploring the app as four different roles, and fatal for a Playwright run.
NEXT_PUBLIC_* is baked into the bundle at build time. Change it, delete .next, rebuild. And never run dev and start at the same time.
The Three Gotchas
- Your database is older than your checkout. Symptoms all differ, cause is one:
column ... does not exist,Could not find the '...' column in the schema cache,no partition of relation "audit" found for row. Fix:npx supabase db reset, thennpm run seed. Ifstartrestored a stale volume,npx supabase stop --no-backupfirst. - Wrong Supabase CLI. The CLI is pinned to 2.105.0 in
package.json. On older versionsdb resetdies withmust be owner of table objects. Usenpx, never a global install. - You changed the schema and skipped
npm run client-local. The generated types still describe the old schema, so you get type errors that point anywhere except at your migration.
Schema change, in full: npx supabase migration new <name> · write the SQL · npx supabase db reset · npm run client-local
All three are written down in AGENTS.md. Point your agent at that file.
Work Block: Get to the Checkpoint
10 minutes. Staff are circulating.
The checkpoint: you're logged in to a course as a seeded user and can see an assignment.
Every command is at /docs/local-dev. Don't retype from the slides.
If you get there: help the person next to you.
If you are stuck: raise a hand. Don't silently debug — that's what the rest of the semester is for.
The Path of a First PR

What CI Protects
| Check | What it catches |
|---|---|
npm run lint | ESLint violations, and unformatted code |
| Jest | Unit-level regressions |
npm run test:functions | Deno tests for the edge functions |
| Playwright (~100 tests) | A user flow that stopped working |
| Argos | A page that changed appearance without anyone deciding to |
| Preview deploy | Your branch, running, at a URL commented on the PR |
Run npm run format before you commit. CI rejects unformatted code, and that round trip is a wasted twenty minutes.
Branch in the repo, not in a fork. The E2E lane won't run for a fork PR.
What a Good PR Looks Like Here
Gets merged
- One concern, reviewable in one sitting
- Description says what changed and why
- Links the ticket
- Green CI before you ask for review
- Says how you tested it
Sits for a week
- Four unrelated changes in one branch
- Description is the branch name
- Red CI, awaiting review
- A formatting sweep mixed into a feature
- No indication anyone ran it
Your git history is the evidence for your band claim in December, and a professional record besides.
Claim Your Role
The hunt has four roles: the student, the grader, the instructor, the new contributor. You already have the student role. Claim a second one here, so all four get covered.
The new-contributor role expires. You're a new contributor exactly once, and it's this week. By October you'll know too much to see what the setup docs leave out.
What Makes a Fileable Ticket
File this
- Numbered steps a stranger can follow
- What you expected, and what happened
- Who it affects, and what it cost them
- Evidence: a screenshot, a trace, a log line
Not yet
- "This file uses
anyforty-one times" - A symptom with no user in it
- Something you couldn't reproduce
- A duplicate one search would have found
Hunt in the area you're curious about. Your bid on 9/17 will be much better for it.
The Other Half: Triage
Two tickets filed, and two things somebody hasn't decided about, decided. Every triage reaches one of three verdicts:
- Still real. The reproduction, who it affects, a size. It becomes claimable.
- No longer real. Fixed, obsolete, or a false positive. Say how you know.
- Undecidable without something I don't have. Name what you'd need and who has it.
The verdict earns nothing. The reasoning is the deliverable.
Session Capture: Install Entire
Required on every repo you work in this semester. One install, one enable, then it rides along on git push.
# macOS / Linux
brew tap entireio/tap && brew trust entireio/tap
brew install --cask entire
# no Homebrew: curl -fsSL https://entire.io/install.sh | bash
# Windows, PowerShell 5.1 or later
irm https://entire.io/install.ps1 | iex
cd platform
entire enable --local \
--checkpoint-remote github:neu-cs4535/fa26-entire-checkpoints
entire status # checkpoint destination must be the corpus repo
It hooks whichever agent you use and stores each session beside the commit it produced. Transcripts go to a private course repo, never to pawtograder/platform. Who reads them, and how to opt out of the research half: syllabus.
Already have the stack running? Give your agent one small task, commit it, then read back what got captured: entire checkpoint list, then entire checkpoint explain <id>.
Work Block: Get Wired Up, Claim Your Role
8 minutes. Four things, in this order.
- Link your GitHub handle to your Pawtograder account. Without it we can't credit anything you file.
- Open the column-groups assignment and confirm your fork of the handout repo exists.
- Enable session capture. The two commands on the last slide, then
entire statusto confirm where checkpoints are going. - Claim your second role so all four get covered.
If any of the four didn't work: tell me now, not on Monday.
The 30-Minute Rule
Thirty minutes of no progress on the same problem, and you owe the team a question.
Not because struggling is bad — struggling is where the learning is. But because silent struggling is invisible to everyone who could have unblocked you in ninety seconds.
The failure mode isn't asking too early. It's a student who says nothing for eight days.
How to Ask
Four lines. That's the whole template.
- What I'm trying to do
- What I did
- What I expected, and what happened instead — paste the actual error
- What I already ruled out
Not: "supabase isn't working, any ideas?"
Instead: "Running db reset to get the seeded class. It fails at migration 2026… with must be owner of table objects. I checked I'm on the pinned CLI via npx. Full log in the thread."
Where to Ask
| Where | For what |
|---|---|
| Discord | Setup problems, "is this expected?", anything fast |
| The ticket itself | Scope questions — they belong in the thread, permanently |
| Monday clinic | Design tradeoffs, architecture, "we're stuck as a team" |
| /docs/local-dev | Every command from today, plus seeding, migrations, edge functions |
| The repo | README.md, AGENTS.md, CLAUDE.md, DEPLOYMENT.md — read first |
Ask in public by default. Your question is somebody else's answer next week.
Key Takeaways
- Pick your path deliberately. Staging for frontend and docs; the full local stack the moment you touch the schema, an edge function, or E2E.
- Small, green, well-described PRs get merged. Everything else waits.
- Thirty minutes, then ask — in public, with the error pasted.
You have a running app, a role, and everything wired up. Now go find what's wrong.
Up Next
Mon Sep 14 — Architecture II: Supabase, RLS & Student-Data Privacy
You now have a local database with seeded students in it. Monday: why every row checks your badge, why that check is expensive, and what FERPA obligates you to.
Before then:
- The Ticket Hunt — two filed, two triaged, due Wed Sep 16
- Project Bids — due Thu Sep 17
- Column groups is open the whole time. Don't start it on Sep 23