Community cinema over SMS · In development
Back to the Big Screen
A monthly neighbourhood movie night you join by sending one text — pick a seat, pay what you can, get a check-in code.
Role: Concept, identity, flow design, and direction of the agents that wrote it.
Timeline: Built 2026 — awaiting carrier registration and film rights
- Database tables
- 22
- API endpoints
- 51
- Source files
- 62
Table definitions in shared/schema.ts. Counted in the repository on 8 August 2026.
Route handlers across routes.ts, adminRoutes.ts and webhooks. Counted in the repository on 8 August 2026.
The tightest codebase of the seven. Counted in the repository on 8 August 2026.
What was actually broken
A monthly community film night has to solve ticketing, capacity, money and the door — for an audience that includes people who will not install an app, will not make an account, and should not have to.
Every ticketing platform available assumes the opposite: that the audience is online, signed in, and willing to be onboarded. For a neighbourhood event, that assumption quietly excludes exactly the people you most want in the room.
The flow I designed
The whole reservation happens over text message. You text one word. It asks how many seats. It asks what you'd like to contribute. It sends a link to pay if you're paying by card, and a check-in code either way. That is the product.
No app. No account. No password. The device requirement is "a phone that can text", which is every phone.
Pay what you can, phrased as a ladder. Contribution options are presented as a small set of suggested amounts rather than an open box, because an open box makes people guess and guessing makes people leave. The same ladder maths is shared across SMS, web and the walk-in flow, so the three surfaces cannot drift into quoting different numbers.
The website is discovery, not transaction. It exists so someone who heard about it can find out what it is. The moment they want in, it hands them to the text thread.
The organiser app is designed for a dark lobby. Dark is the design, not a mode — light mode exists only so the legal pages are readable. Check-in is one-handed and one-thumbed, because the organiser is standing up with a phone in one hand and a queue in front of them.
The identity is a marquee, not a movie. Bulb light, neon, chrome, film grain, ticket stubs — the era, deliberately steering clear of any specific film's trademarks.
Interface notes
The frequency is stated before you join
Two to six messages a month, in writing. The single biggest reason people rage-unsubscribe from SMS is volume they did not agree to.
Leaving takes one word
STOP works on any message and ends everything immediately. Making the exit easy is both the law and the reason the list stays healthy.
Consent is never inferred
Exactly two ways in, both requiring the person to act. No bought lists, no third-party data, no “we assumed you wanted this”.
The hard part
A conversation you can actually test.
Anything that talks to people over SMS is a state machine: someone will reply "2" to a question you asked four days ago, reply twice, reply with an emoji, or reply while a reminder is going out. Getting that wrong means charging the wrong person or double-booking a seat.
The state machine was written as a pure function — no database, no Twilio client, no clock. It takes the current state and an incoming message, and returns the next state and what to send. All the I/O lives outside it.
That single constraint is what makes the whole thing testable. Every weird ordering becomes an ordinary unit test with no mocks and no network. Of all the projects here this is the only one with real test coverage of its core logic, and it is not a coincidence — it is testable because it was shaped to be.
The other genuinely fiddly piece: message templates count their own GSM-7 segments, so an innocuous wording change can't silently turn one billed message into three.
Stack
| Frontend | React 18 + Vite, Wouter, TanStack Query |
|---|---|
| UI | A deliberately slim Radix subset, Tailwind |
| Backend | Express + TypeScript, one process serving API and client |
| Database | PostgreSQL (Neon) + Drizzle ORM |
| Auth | Passwordless organiser login codes over SMS, against an allowlist — There are five organisers. An accounts system would have been more code and less security. |
| SMS | Twilio, with signature verification and a compliant outbound queue |
| Payments | Stripe Checkout — the webhook is the only thing that confirms a reservation — The browser redirect is a hint, not a fact. |
| Testing | Vitest over the pure SMS state machine and contribution maths |
| Hosting | Render, on a plan that never sleeps so the reminder cron can't silently stop |
Outcome
Fully built and deployed to Render — SMS reservation, seat holds, Stripe payments confirmed strictly by webhook, an organiser app with QR check-in, reminder scheduling, and polling for which film to show next.
Not yet live, and the blockers are not software: carrier registration for the SMS number, and film screening rights. Both are real-world approvals, and the case study says so rather than implying a launch that hasn't happened.