Skip to content

CASE STUDY

03/Work, selected

04 / 08

Civic AI Course Delivery

An 8‑day, SMS‑paced course platform for InnovateUS Civic AI.

What I ownedOwnership: Sole author

Sole engineer, start to finish in three days: sign‑in, SMS pacing, the quiz gate, certificate, admin console, runbook and the carrier compliance doc.

3Days, solo, to a working course

Year
2026
Role
Sole engineer
With
InnovateUS
Category
Platform

01/The problem

A free course only works if people come back.

Self-paced online courses lose learners early. The InnovateUS Civic AI course needed a gentle nudge that nobody would mistake for spam, and a real check that a lesson was watched, not just opened.

02/What I built

An 8‑day course that texts you the way back.

  1. 01

    Learners sign up with a name and a mobile number or email, confirm with a six-digit code, and watch one video lesson a day. A one-question quiz gates each next lesson, and a personalized PDF certificate follows lesson eight.

  2. 02

    Skipping ahead does not count. The player reports which seconds were actually seen, and the question unlocks at about 90 percent coverage, so dragging the scrubber to the end changes nothing.

  3. 03

    Reminders follow strict rules: 24 hours of inactivity, at most one a day, 9 am to 8 pm in the learner's time zone, only in the first 8 days, and never more than two unanswered in a row. Each text starts with "InnovateUS:", fits one segment, and carries a short link on the course's own domain that drops the learner back where they stopped.

  4. 04

    Texts leave from the course's own 10DLC number through AWS End User Messaging. STOP, START and HELP are handled and delivery failures are classified. Email sign-ups get the same limits through SES, with a suppression list, one-click unsubscribe and a service-wide send cap.

  5. 05

    Around the learner flow: an admin console and API, a Turnstile bot check on sign-in, a WAF rate limit on admin sign-in, two CDK stacks (dev and prod) with alarms and a manual CI deploy, and five docs (SMS, email, runbook, admin API, copy deck). It is pre-launch: there is no public URL yet.

03/Architecture

Two paths: the lesson you take, and the reminder you might get.

A learner taps the texted link, CloudFront serves the React site, and the Hono API on Lambda records watch coverage and quiz results in DynamoDB. Separately, an hourly EventBridge pass runs the scheduler, which applies the send rules and sends at most one reminder over SMS or email, carrying a short link back to the exact spot.

A/Learner path

01Texted link02CloudFront03React site04API Gateway05Hono on Lambda06DynamoDB

B/Reminder path

01EventBridge, hourly02Scheduler Lambda03Send rules04SMS or SESemail05Short link back

04/Try the rules

Scrub the clock. Watch what gets texted.

A made-up learner and the real reminder rules, played over the eight days. Change what she does, drag the clock, and see which texts go out, which are held back, and which rule decided.

Fictional learner, sample sign-in code and link. The rules are written out by hand from the scheduler as of 1 Oct 2026, and its hourly pass is drawn on the hour. The app is pre-launch and nothing here sends a text.

05/Outcomes

Built in three days, not public yet.

  1. 3

    Days, solo, to a working course

    From the first import on 29 Sep to the admin console on 1 Oct 2026, one engineer end to end.

    From the repo

  2. 8

    Lessons, one question each

    The real chapters of the InnovateUS Civic AI course, about 34 minutes of video in all. Answers are checked on the server; the answer key is pending author sign-off before launch.

    From the repo

  3. Pre-launch

    Status as of 3 Oct 2026

    Not public yet, and the repo records no launch date. Dev and prod stacks, alarms, a CI deploy and a runbook are in place. Still open before launch: re-file the carrier campaign with the current wording, confirm the monthly spend limit and get the answer key signed off.

    From the repo

Check these in the ledger

06/Production notes

Behind the numbers

All receipts for this project
Mechanism

A learner signs up with a mobile number or an email, confirms a six-digit code and watches one lesson a day. The question after a lesson unlocks only when about 90 percent of the video’s seconds were actually seen, kept as a per-second watch map, so dragging the scrubber to the end changes nothing. A one-question quiz, graded on the server, gates the next lesson, and a personalized PDF certificate follows lesson eight. An admin console shows progress by lesson.

Reminders

A reminder goes out after 24 hours of inactivity, at most one a day, only in the first 8 days, and never more than two unanswered in a row. An hourly scheduler claims each learner’s day before it sends, so a retried run cannot text twice.

Guardrails
  • Quiet hours. Texts go out only between 9 am and 8 pm in the learner’s time zone.
  • Opt-outs. STOP, START and HELP are handled. A learner who replied STOP is told how to turn texts back on instead of seeing an error.
  • Carrier rules. Every text starts with the program name, and reminders carry the opt-out line and fit one segment. Links point only to the course’s own domain, never a shortener, because carriers filter texts with links. Message text uses plain characters, because one accented or curly character cuts a segment from 160 characters to 70.
  • Failed sends. They are sorted into spam filtering, carrier block, unreachable, invalid number and spend limit. Logs mask phone numbers and never keep message text.
What broke
  • A blank video box. When the video host failed to load, the lesson page showed an empty box. It now shows a Try again button and a link to the video, and a lesson already passed keeps its player.
  • Admin numbers undercounted. The per-lesson funnel counted from the event log, so learners whose progress predated the log, or whose video an admin marked as watched, were missing. It now counts from progress records.
  • A wrong claim in my own notes. The first deploy notes said a settings change reaches running servers within about 15 minutes. They cache settings for hours, so I corrected the note and added a deploy option that replaces the containers.
Evaluation

Tested

29 server test files cover the reminder rules, the watch-coverage check, text wording and length, STOP handling, sign-in limits and the admin API. The course is pre-launch, so there are no usage numbers.

Evidence

Private repo

The repo is private, so nothing here is linked. Status: pre-launch.

07/Stack

Built with

  • Hono
  • TypeScript
  • AWS Lambda
  • AWS CDK
  • DynamoDB
  • EventBridge
  • End User Messaging SMS
  • SES
  • CloudFront
  • React
  • Vite
  • Vitest
  • Cloudflare Turnstile
  • GitHub Actions