03/Work, selected
04 / 08
Civic AI Course Delivery launch film: text alternative Landscape (1920x1080) and vertical (1080x1920) cuts share one timeline and run 20 seconds, with a quiet music bed and a few soft interface sounds. There is no narration. In the landscape cut the captions sit on the left and a phone on the right; in the vertical cut the captions sit above a centred phone, and the closing lines stack on two lines or in a column. Content flags - ILLUSTRATIVE: the learner name (Marisol Herrera, a placeholder from the product), the sign-in code, the short link address (an example domain), the certificate ID, the watch progress (38%, 74%) and the selected quiz answer are sample values. No real learner data and no usage numbers are shown. - The phone screens are rebuilt from the product's own pages and its registered text wording. The lesson title, description and question are the real content of lesson 3. - The film does not say the course is live. BEAT BY BEAT 0:00 to 0:03 Hook On-screen text: "No password · No app" (in capitals). "The course that texts you." ("texts" in an italic serif.) A notification card reads: "InnovateUS", "now", "InnovateUS: Hi Marisol, your next CivicAI lesson (3 of 8) is ready when you are: https://cvai.example.org/l/Ab3d". Visual: dark purple screen. The headline rises into place, then a notification card with a blue chat icon drops in beneath it. 0:03 to 0:05.8 Beat 1, The text On-screen text: "01 · The text". "A link to your next lesson." "From the course's own number, one text segment, a link on its own domain." Inside the phone, a message thread with "InnovateUS": "Yesterday 4:38 PM", "InnovateUS: 482916 is your CivicAI Course sign-in code. It expires in 10 minutes. Don't share it with anyone."; "Today 10:04 AM", "InnovateUS: Hi Marisol, your next CivicAI lesson (3 of 8) is ready when you are: https://cvai.example.org/l/Ab3d Reply STOP to opt out." Visual: a phone rises into view on the right. The second message pops in, then a tap ripple lands on the link and it highlights. 0:05.8 to 0:09 Beat 2, The lesson On-screen text: "02 · The lesson". "Skipping ahead doesn't count." "The question unlocks once most of the video has really been watched." Inside the phone: "InnovateUS Courses", "Marisol", "Sign out", "All lessons", "LESSON 3 OF 8", "Getting Started: Finding Free and Affordable AI Tools", the lesson description, a video player titled "Lesson 3: Free and affordable AI tools". Progress box: "38% watched", "2:15 left to unlock the question", "You skipped 1:10 to 1:40.", "Watch the part you skipped", "Watch most of the video to unlock the question. Skipping ahead doesn't count. Your place is saved, so you can stop and come back any time." Later "74% watched", "0:56 left to unlock the question", then "100% watched", "Question unlocked". Visual: the lesson page slides in and scrolls to the video and a gold progress meter. The skipped-stretch notice fades out as the meter fills to full. 0:09 to 0:12.65 Beat 3, One question On-screen text: "03 · One question". "Wrong answers cost nothing." "The answer key never leaves the server." Inside the phone: "QUESTION", "Answer to finish lesson 3", "Pick the answer you think is right. If it's wrong, just pick another.", "Which of the following is a key advantage that paid AI services often provide over free versions?", four options A to D ("They can browse the internet for current information", "They provide enhanced privacy protections for sensitive information", "They work faster than free versions", "They require less specific instructions to get good results"), then "Correct" on option B. Then: "LESSON 3 DONE", "Nice work.", "Lesson 4 is ready now. Your place is saved, so you can come back any time.", "Start lesson 4", "Stop for now". Visual: the question panel replaces the progress box. A tap ripple selects option B, which turns blue and then green with a "Correct" mark. A "Nice work." panel with a yellow button follows. 0:12.65 to 0:14.9 Beat 4, The finish On-screen text: "04 · The finish". "Eight lessons. Your name on it." "A PDF certificate, once all eight are passed." Inside the phone: "CONGRATULATIONS, MARISOL", "Your certificate", "CERTIFICATE OF COMPLETION", "This certifies that", "Marisol Herrera", "has completed", "CivicAI Course", "Certificate ID CERT-7Q2M9X4A", "Download certificate (PDF)". Visual: the certificate page slides in. A yellow line draws under the name and the download button presses once. 0:14.9 to 0:17.9 Reminder rules On-screen text: "A reminder only if you go quiet." ("go quiet." in italic serif.) Four labels appear one by one: "At most 1 a day", "9 am to 8 pm local", "First 8 days only", "Reply STOP to opt out". Eight numbered circles 1 to 8 with the label "8 lessons · 8 days". [Vertical: the four labels stack in a column and the headline breaks onto two lines.] Visual: large headline on the dark background, labels in rounded outlines, then eight small gold-outlined circles that fill in turn. 0:17.9 to 0:20 End card On-screen text: "Civic AI Course Delivery". "Sole engineer · Dhruv Kamalesh Kumar" (in capitals). [Vertical: the title breaks onto two lines.] Visual: a small speech-bubble icon with three dots, the product name in large type, a thin gold line, and the credit line in small monospace capitals. A soft bell sounds as the title appears.
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.
- 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.
- 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.
- 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.
- 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.
- 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
B/Reminder path
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.
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
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
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
- 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
08/In use
The work, up close
09/Links
