A lightweight live Q&A app for talks. The audience submits and upvotes questions on their phones; the speaker projects a QR code, picks the next question to answer, and moderates as they go.
Hosted at https://questions.mikecann.app.
The product fits on one mental model:
- A speaker signs in, creates a session, and opens it.
- They project the display view — a big-screen layout with a QR code, a join URL, and the current top question.
- An audience member scans the QR (or types the join code) and lands on the audience page on their phone, where they can submit questions and upvote others.
- The speaker highlights the question they're answering, then resolves it (kept in history) or discards it (also kept, but for moderation reasons). Resolved/discarded questions disappear from the live list but stay searchable for the speaker.
The full domain language — every term the codebase uses, what each one means, and what to avoid — lives in CONTEXT.md. If you're touching the product you should read it first; it's the single source of truth for naming.
- Backend: Convex — schema in
convex/schema.ts, auth via@convex-dev/auth(GitHub OAuth + password for testing). - Frontend: React 19 + Vite 8, routed with
type-route. Single SPA bundle. - Deploy: Cloudflare Workers Static Assets (no Worker script — just static asset serving with SPA fallback). Convex serves the backend.
- Testing: vitest for unit + component tests, Playwright +
playwright-bddfor end-to-end behaviour scenarios that drive a real browser against a freshly-spawned local Convex backend.
convex/ Convex schema, queries, mutations, auth wiring
src/ React app — screens/, components/, router
features/ Gherkin .feature files (the BDD contract)
e2e/ Playwright wiring: globalSetup, fixtures, step definitions
docs/ Design notes, ADRs, agent meta-docs
scripts/ One-off CLI helpers (e.g. BDD pairing check)
eslint-rules/ Project-specific ESLint rules with fixture tests
bun install
bun run dev # spawns `convex dev` + Vite togetherFirst convex dev will prompt you to set up a Convex deployment. After that, the Vite dev server hot-reloads against it.
| Command | What it runs |
|---|---|
bun run test |
vitest unit/component tests + the BDD drift check |
bun run test:bdd-check |
drift-only check (verifies every .feature step has a matching step definition) — fast, no servers needed |
bun run test:e2e |
full Playwright BDD suite, ~2 min: spawns a local Convex backend + Vite, runs all 38 scenarios across mobile and desktop viewports against a real browser |
bun run typecheck |
tsc --noEmit |
bun run lint |
ESLint, including project-specific rules in eslint-rules/ |
bun run fallow:ci |
dead-code, duplicates, and complexity health check via Fallow |
The behaviour-first workflow is the default for any user-visible change — see features/README.md for the conventions, including the behaviour-vs-styling rule for which assertions earn a place in BDD and which belong in another test layer.
CONTEXT.md— domain glossary. Read this first.AGENTS.md— workflow defaults (behaviour-first, coding conventions, CI checks).features/README.md— how the BDD suite is structured: tag conventions, shared step files, drift safety, viewport handling, the per-test sign-in pattern, and the principle that BDD scenarios test behaviour, not the way the UI happens to look today.docs/coding-conventions.md— TypeScript / React / Convex code shape rules.docs/adr/— architecture decisions; 0001 explains why the stack looks the way it does.docs/github.md— branch protection intent and Cloudflare Workers deploy secrets.
Every PR runs the checks job (typecheck, lint, vitest + BDD drift, Fallow) and the e2e job (the full Playwright suite). The deploy job runs on pushes to main once both pass — it deploys Convex functions and the Cloudflare Workers Static Assets bundle in one shot.


