Skip to main content

Course Intro + Pawtograder Architecture I

Pixel art cutaway of an old, still-occupied city building. The lower floors are a tangle of rusted amber pipes and patched wiring; on scaffolding above, a crew of five engineers in teal and blue trace the wiring with flashlights and pin up new blueprints. Lights are on in the windows — the building is still running. Tagline: The Lights Stay On While You Rewire.

Reminders​

  • RELEASED: The Ticket Hunt. Due Wed Sep 16
  • RELEASED: Onboarding: Gradebook Column Groups. Due Thu Sep 24
  • RELEASED: Project Bids. Due Thu Sep 17

CS 4535: Software Design & Delivery

Course Intro + Pawtograder Architecture I​

©2026 Jonathan Bell, CC-BY-SA

Learning Objectives​

After this session, you'll be able to:

  1. Describe the major components of the Pawtograder stack and how one request flows through them
  2. Map the project slate onto areas of the system
  3. State what you need working before Thursday

Notice what is not on that list. You don't need to understand any of this deeply today — "describe" and "map" are the verbs. Every box on today's diagrams gets its own session later.

Who's In the Room​

It's a small room. By December you'll have reviewed each other's code. Let's start there.

Tell us:

  1. Your name, and something you did over the summer
  2. What you want out of this Fall — in this course, and after it
  3. Your relationship with AI tooling: how you use it, how you want to use it, and how you don't

I'll go first.

On question 3: there is no AI restriction in this course. Use anything. I'm asking because nobody has this figured out, and a room's worth of honest answers is a better starting point than a policy.

Grading: Four Bands, No Points​

BandMeansLetter
PassTrusted to contribute under reviewB
CreditTrusted to exercise judgment, not just executeA−
DistinctionTrusted to own what ships (four of five)A
High DistinctionTrusted to extend the systemA, and a letter with something in it

Each band is a published list of things you've demonstrably done. Every band requires the one below it. You declare which you're working toward on Oct 1, and you can change it either way until Dec 3.

There's no way to reach an A while being weak at one of the eight outcomes.

What That Means In Practice​

Almost nothing here is a submission. You're graded from the things professional work produces anyway: pull requests, review threads, commit history, design notes, postmortems, dashboards.

In December you write a Learning Summary Report: the band you're claiming, and a link to the artifact that satisfies each requirement. I verify the claim rather than re-grading the work, because the work was already reviewed when it happened.

Which makes the report quick to write if you did the work, and unwritable if you didn't.

Two Phases, Two Rhythms​

Weeks 1–3: Onboarding

  • Lecture every session
  • The Ticket Hunt: file two, triage two. Due 9/16
  • Column Groups: everyone builds the same feature, alone. Due 9/24
  • Bids due 9/17 · teams announced 9/24

Weeks 4–14: Studio

  • Mon: standup + clinic
  • Wed: tech talk or student presentations
  • Thu: team work, game day, or demo day
  • Demos every two weeks. Game days unannounced.
  • You will hold two roles: a project team and a cross-project function

Feature freeze is Mon Nov 23. Weeks 13–14 are hardening, documentation, and ops playbooks for the January handoff. Nothing new lands after the freeze.

Before the Diagrams: The Vocabulary​

Cloud platforms give you a standard set of parts. Every architecture diagram you'll see this semester is made of these six, and nothing else.

Database

Structured data you can query

ours: Postgres

Object storage

Files too big for a database

ours: Supabase Storage

Queues and event buses

Work that waits its turn

ours: pgmq, EventBridge

Cache

A fast copy of hot data

ours: Upstash Redis

API gateway

One front door, with a lock

ours: the Supabase gateway

Observability

Logs, metrics, traces

ours: Sentry, Prometheus

Plus one more: serverless compute — code that runs on demand and then disappears. Ours are the edge functions.

Every one of these six gets its own session — schedule at the end of today

What a Database Actually Is​

Somewhere to put data that survives a restart — and, more importantly, somewhere you can ask questions of it. The right kind depends entirely on the questions.

Relational (SQL)

Rows, columns, and relationships between tables. Powerful queries, real transactions, rigid schema.

Postgres, MySQL

SELECT s.*, a.title
FROM submissions s
JOIN assignments a
ON s.assignment_id = a.id
WHERE s.student_id = ?

Document (NoSQL)

JSON-shaped blobs. Flexible schema, fast to start, weak at questions that span records.

MongoDB, Firestore

{
student: "alice",
scores: [85, 92, 78]
}

Key-value

Fetch by key. Blazing fast, no queries at all.

Redis, DynamoDB

GET user:12345
SET session:abc {...}

Why Postgres, reason 1: our questions are relational

"Every submission by this student, across every assignment, with the assignment title."

That's a join, and joins are what SQL is for.

Reason 2: it can enforce the rules itself

Postgres has row-level security — a policy attached to the table.

"A student sees only their own submissions" becomes a property of the rows, not something every query has to remember.

Reason 2 is the bigger one, and it shapes almost everything else you'll see today.

Full session: Mon 9/14 — Architecture II: Supabase, RLS & Student-Data Privacy

Webhooks, Queues, and Why There Is an EventBridge​

A webhook is just an HTTP POST that someone else sends you, when something happens on their side. No magic. GitHub calls us; we didn't ask.

A queue or event bus sits in the middle and holds the message. The sender is done once it's accepted; delivery is somebody else's problem.

So: if we're deploying when a student pushes, a raw webhook is lost forever. GitHub gives up quickly. EventBridge keeps trying long after GitHub would have stopped and we pay for the privilege.

Comes back on Thu 9/24 (Monitoring) and Thu 10/22 (Game Day 1)

Pawtograder Has One Architectural Thesis​

1. The database is the application. The logic lives in the database, and the database enforces security on the data.

2. We want the application to be sequentially consistent. One coherent order of events. What you just did is what you see.

3. Consistency is hard when you have to wait. So everything crossing the boundary gets a queue, in both directions. The outside world is allowed to be on fire — and so are we.

Every diagram for the rest of today is one of these three claims.

The Stack: Everything In Play​

How They Talk​

  1. rpc() — most reads and writes
  2. Realtime broadcast — nothing polls
  3. functions.invoke()
  4. service-role available, prefer user-role
  5. pg_cron + pg_net — the database calls out
  6. webhook, via EventBridge
  7. dispatch grade.yml
  8. OIDC-authenticated callback

Left off on purpose: Discord and Chime hang off the edge functions, Sentry collects exceptions from both tiers, Prometheus scrapes the functions.

The Database Is the Application​

Authorization, business logic, queueing, scheduling and fan-out all live in Postgres. Not in the app.

Full session: Mon 9/14 — Architecture II: Supabase, RLS & Student-Data Privacy

Consistency Is Easy Until You Have To Wait​

Block on the outside world

Commit, then enqueue

The transaction only depends on Postgres. Postgres is up, so we are up — and the work that needs GitHub happens whenever GitHub comes back.

GitHub had a worldwide outage on August 17. Grading kept queueing.

Queues, retries and dead letters in depth: Thu 9/24 — Monitoring & Incident Response

And We Are Allowed To Be On Fire Too​

The same trick, pointed inward. Nothing outside should have to wait on us either.

For machines: a durable buffer

GitHub's webhooks land on an event bus, never on us directly.

  • Buffers and retries with backoff
  • Dead-letter queue for what still fails
  • Durable audit trail, and replay
  • Smooths a burst of pushes into a rate we can take

We can be down for a deploy, a migration, or a bad afternoon. The events wait.

For humans: an honest status page

A real page, served instead of the app.

  • HTTP 503 with a Retry-After header
  • Title, message and an ETA, set per window
  • Refreshes itself, so nobody sits reloading
  • Runs on its own replicas — it survives what took the app down

Users find out what happened and when we're back.

And we choose honest downtime over a half-working app: a read-only database is "unavailable, but unpredictably so."

Planned windows and rollback: Thu 9/17 · incident response: Thu 9/24

Sequence: How Autograding Works​

CI in depth: Wed 9/23 · what it tests: Thu 9/24

Sequence: How a Gradebook Cell Gets Its Value​

Queues, retries and dead letters again on Thu 9/24 — Monitoring

Data Access: Prefer RPCs​

For data operations, reach for a Postgres RPC before a server action or an edge function.

RPC in Postgres

  • Runs next to the data
  • Authorization already applies
  • One round trip
  • The default for reads and writes

Edge function

  • For integrations that call out: GitHub, Discord, AWS
  • Not a general data path
  • Deno, so no @/ alias and no Node imports

Types come from the schema. After a migration, run npm run client-local — never hand-edit the generated types.

Today Is the Map. The Detail Comes Later.​

What you saw todayWhere it gets a whole session
Databases, RLS, student-data privacyMon 9/14 — Architecture II
The frontend: App Router, types, TableControllerWed 9/16 — Architecture III: The Client
Migrations, down paths, rollbackThu 9/17 — Architecture IV: Deployment
CI/CD, feature flags, dark launches, trunk-based developmentWed 9/23 — Software Processes & Continuous Delivery
E2E and visual acceptance testingThu 9/24 — Testing
IaC, drift, Sentry/Grafana, incident responseThu 10/1 — Tech Talk: Operations
Agents, context, sub-agentsWed 10/7 — Tech Talk: Agents & Workflows
Risk registers, release readinessWed 11/18 — Tech Talk: Risk & Release Readiness
All of it, under time pressureGame days — 10/22, 11/5, 11/19

Today's only job is that the picture makes sense. If you can point at a box and say roughly what it does, you're exactly where you should be.

Complexity Is Not Evenly Distributed​

Treemap of the codebase sized by lines of code and colored by concentration of complexity: app/ at 99k lines, supabase/functions/ at 84k and warm, components/ at 57k, lib/ at 25k and warm, utils/ and hooks/ at 16k each, cli/ at 6k. Three dashed callouts point at specific regions: realtime controllers in lib/, the autograder and gradebook workers in supabase/functions/, and the gradebook React tables in app/. A legend runs from well understood to concentrated complexity.

Seven Projects, Seven Parts of the System​

ProjectWhere it livesWhat you'd be doing
Usability Strike Forceapp/, components/Studies with real users, then shipping the redesign
Accessibility Strike Forcestudent pages, tools/a11y-judge/WCAG AA against real screen readers, then fixing what fails
Office Hours Reconceptualizationhelp queue, Realtime, ChimeFull product redesign, research through deploy
Docusaurus Integrationplugins/, public APIsSchedule sync, embedded polls, search across two ecosystems
Paper Exam Generation & Gradingmostly new codeVariant generation, barcodes, scan ingest, OCR, grader UX
GitHub → Forgejo MigrationGitHub App, repo automation, CIProvisioning, permissions, a migration path for live courses
Coder Workspaces Integrationauth, provisioning, grading actionsSSO and one-click cloud dev environments

Every project spans the full lifecycle. None of them is only frontend or only backend.

What Happens Next​

  • Wed Sep 16 — Ticket hunt due. The pool you build is the pool we all draw from.
  • Thu Sep 17 — Project bids due. Ranked preferences across the slate.
  • Thu Sep 24 — Teams announced. Column groups due.
  • Mon Sep 28 — Studio kickoff: charters, backlog, estimation.
  • Thu Oct 1 — Declare your target band.

Between now and 9/17 you'll have run the app locally, filed a ticket or two from the hunt, and read code in at least two of those seven areas. Bid on the basis of that, not on the basis of this slide.

Before Thursday​

Come to Thursday ready to get Pawtograder running.

  • Bring a laptop with Node 22 (use nvm) and Docker installed
  • A fresh clone of pawtograder/platform if you get to it — main has moved since the application
  • You don't have to have it working by then. Thursday is when we do that part together
  • If you do get a head start, click through the app as a user and note one thing that's wrong
  • Being stuck is a fine outcome, being stuck silently is not

Thursday is a working session, not a lecture. Whatever is already installed when you sit down is time you get back for code.

Key Takeaways​

  1. The database is the application. The logic lives there, and it enforces security on the data.
  2. We want sequential consistency, so nothing waits on anyone else. Commit what we own, queue what leaves the building, buffer what arrives — and when we're down, say so honestly.
  3. Complexity is concentrated, and the debt is not a secret. Working well inside it is the skill this course grades.

Thursday: get it running, together. Then ship something.

Up Next​

Thu Sep 10 — Working Session: Local Dev & the Contribution Workflow

Today was the map. Tomorrow you get the keys: the app running locally, and a first ticket claimed.

Before then:

  • The Ticket Hunt — due Wed Sep 16
  • Onboarding: Gradebook Column Groups — due Thu Sep 24
  • Project Bids — due Thu Sep 17