Delivery Plan — Spike & Stages
Four delivery stages. Stage 0 is a mandatory viability spike for Zero and all hard platform bets before any product feature work. Pass/fail criteria are explicit — a failed threshold triggers a written founder escalation, not an automatic engine swap.
Stage Overview
| Stage | Focus | Gate |
|---|---|---|
| Stage 0 | Architecture spike — Zero, auth, Elysia, bojastack | Must pass all Zero viability gates before proceeding to Stage 1 |
| Stage 1 | Chat foundation | Correctness, reconnect, and authorization proven before courses or billing |
| Stage 2 | Platform foundation — billing, courses, moderation, OpenAPI/MCP/CLI | Chat stable; billing proven before live rooms |
| Stage 3 | Live rooms — LiveKit interactive, Egress → Stream, recording | Platform foundation stable |
| Stage 4 | Scale & hardening — tenant partitioning, large-server fan-out, abuse controls | Live rooms stable; scale benchmarks pass |
Stage 0 Spike Checklist
Stage 0 runs as a narrow vertical slice proving the hard parts. Each item must pass explicit measured thresholds. A demo that "kind of works" does not pass.
Authentication & Infrastructure
- Better Auth login on web, iOS, and Android
- Elysia OpenAPI contract generation + one shared Zero/REST command handler
- bojastack admin-API shell with redaction and access explain commands
- Two servers, memberships, channel permissions
Core Chat Functionality
- Channel list renders from local replica
- Recent message tail (local, no network required)
- Send a message with optimistic acknowledgement and idempotency
- Read marker updates
- Scroll older messages (paginate backward)
- Jump to a message not present locally
Resilience & Revocation
- Reconnect after short offline period (<5 minutes)
- Reconnect after long offline period (>1 hour)
- Message intentionally sent while fully offline delivers on reconnect
- Membership removed while device is offline; revocation propagates correctly on reconnect
- Cold app launch in airplane mode — cached state renders, no spinner
Required Benchmark Evidence
Every metric in this table must have a measured number attached. "Felt fast" is not evidence.
| Metric | What to Measure | Pass Threshold |
|---|---|---|
| Shell render (local) | Time to locally rendered app shell from cold launch | < 200ms (target) |
| Cached channel | Time to cached channel view from tap | < 500ms |
| Authoritative reconnect | Time to authoritative catch-up after reconnect | < 2s |
| Bytes synced | Initial sync data transfer size | Budget TBD in spike |
| Local storage | Storage growth rate per active server | Budget TBD in spike |
| Scroll latency | Message list scroll performance | 60 fps sustained |
| Jump latency | Jump to distant message not in local window | < 300ms |
| Mid-range mobile | CPU/memory on mid-range Android device | No jank; < 200MB RSS |
| Permission revocation | Inaccessible rows removed on reconnect after membership revoke | 100% cleanup |
| Offline message send | Outbox delivers message after airplane mode + reconnect | 100% delivery |
Pass/Fail Rule
Pass only when every non-negotiable acceptance criterion has an explicit measured threshold and evidence: RN persistence/recovery, cached launch, reconnect and revocation latency, query/fan-out budget, hot/archive jumps, outbox crash safety, zero-cache topology/failover/replica rebuild, publication/schema migration, rolling upgrade and disaster recovery.
A failed non-negotiable threshold triggers a written founder escalation on scope, SLO, or topology. It does not automatically select another engine.
Parallel Spikes
Eight named spikes run in parallel during Stage 0. Each has a domain, a purpose, and explicit pass/fail criteria.
| Spike | Domain | Purpose |
|---|---|---|
| S1 | Zero RN lifecycle | kvStore crash-test: process death, suspension, account switch, upgrade |
| S2 | Zero operational maturity | zero-cache failover, replica rebuild, migration, rolling upgrade, disaster recovery |
| S3 | Zero query fan-out | Hot tails, distant jumps, archive transitions, revocation at scale |
| S4 | Zero auth refresh | Refresh credentials without recreating Zero storage or losing local state |
| S5 | Outbox crash safety | Write durability, receipt protocol, client_nonce idempotency crash matrix |
| S6 | Search rebuild/reconciliation | Versioned index build, atomic swap, rebuild from Postgres authoritative source |
| S7 | ParadeDB decision gate | BM25 + synonym parity vs Meilisearch — explicit pass/fail gate for engine choice |
| S8 | pg-boss Bun runtime | Bun compatibility spike for pg-boss; Graphile Worker is the fallback if this fails |
5 Open Items Needing Resolution Before Stage 1
These five items are not implementation decisions — they require external input or organizational decisions. Stage 1 cannot start until each has a recorded resolution.
- Tax vendor selection — requires finance review of available API adapters and jurisdictional coverage
- Merchant-of-record contract — requires counsel review of the NMI + value.io TSYS deal structure
- Zero spike outcomes — S1–S4 spike results must be recorded with topology evidence before Stage 1 begins
- Product name confirmation — "Boja" must be cleared (trademark, domain, app store) before any public artifact is named
- Per-server synonym timing — decide whether per-server synonym management is V1 or fast-follow; affects search schema migration planning
Stage 1 Acceptance Criteria
Stage 1 is complete when all three criterion categories pass with measured evidence.
Chat Criteria
- Send and receive messages in real time across multiple devices
- Optimistic send with server acknowledgement observable in UI
- Message history paginates correctly in both directions
- Jump to a message by ID with correct context window
- Read markers update and persist across devices
- Reactions work and sync to all observers
- Thread reply works and is routed to the correct thread channel
Authorization Criteria
- Users cannot read channels they do not have access to
- Role changes propagate to sync publication within the reconnect SLO
- Membership revocation removes local rows from the client replica on reconnect
- Server isolation: no cross-server data leaks in any query path
access explainCLI command returns a full, accurate evaluation trace
Resumability Criteria
- Cold launch renders cached state in < 500ms without a network request
- Short offline (<5 min) reconnect catches up in < 2s
- Long offline (>1 hour) reconnect catches up correctly without state corruption
- Offline message send delivers on reconnect with no duplicates (idempotency proven)
- App process death during outbox send does not lose the message