Mobayilo - Project Status
Mobayilo - Project Status
Section titled “Mobayilo - Project Status”Last Updated: 2026-01-29
Current Phase: Phase 5.5 — Caller ID & Company Number Enforcement
Branch Policy: Work on development, merge to main when approved.
Current Phase Status
Section titled “Current Phase Status”Current Phase: Phase 5.5 — Caller ID & Company Number Enforcement
State: ✅ Engineering complete, ⚠️ awaiting final verification
Branch: development (no merge to main yet)
✅ What’s already done (documentation)
Section titled “✅ What’s already done (documentation)”- PRD defined (
docs/PRD.md) - Setup guidance drafted (
docs/SETUP.md) - Architecture notes drafted (
docs/ARCHITECTURE.md) - Market overview drafted (
docs/MARKET_OVERVIEW.md) - MVP analysis captured (
docs/MVP_ANALYSIS_AND_PROPOSAL.md)
🚀 MVP Delivery Goal
Section titled “🚀 MVP Delivery Goal”MVP = individual + company wallets with:
- Browser dialer (WebRTC) → PSTN via Twilio
- Pay-as-you-go credits + ledger
- Stripe top-ups (min $5 individual, min $100 company)
- Company seats (magic link), shared numbers allowed, usage tracked per seat
- Billing: per-started-minute (
ceil(duration_seconds / 60)) - Jobs: Solid Queue
Phase 0: Bootstrap Rails monolith (Target: Day 1)
Section titled “Phase 0: Bootstrap Rails monolith (Target: Day 1)”Objective: Generate the Rails 8.1 app at repo root and run it locally.
- Generate Rails app in repo root (
--database=postgresql --css=tailwind --javascript=esbuild) - Ensure
docs/remains intact and readable - Configure database and run migrations
- Confirm local boot: Rails server starts and serves a home page
- Document required env keys in
docs/SETUP.md
Test checklist (Phase 0)
-
bundle exec rails serverboots without errors - Home page renders at
/
Exit criteria: Rails boots locally and serves pages.
Phase 1: Auth + Accounts (Target: Day 1–2)
Section titled “Phase 1: Auth + Accounts (Target: Day 1–2)”Objective: Support individuals and company admins (password) + company seats (magic link).
- Add
Userauthentication for individuals + company admins (Devise) - Password reset via email (Devise recoverable)
- Add
Company/Accountmodel (wallet owner) - Add company seat login (magic link)
- Add company allowlist policy (domain-based)
- Add basic navigation (mobile-first): Dial / History / Credits / Settings
Test checklist (Phase 1)
- Individual sign up → land on home → bottom nav visible
- Individual sign out → sign in again successfully
- Company admin sign up → account created → allowlist set to admin email domain
- Create seat with allowed domain succeeds; disallowed domain fails
- Seat magic-link sign-in works (email delivered)
- Seat auto-provision works for allowed-domain email (no pre-created seat)
Exit criteria: Individual can sign up/login; company admin can create seats; seat can sign in via magic link.
Phase 1.5: Pre-Flight Fixes (Target: Day 2)
Section titled “Phase 1.5: Pre-Flight Fixes (Target: Day 2)”Objective: Resolve critical architectural gaps before building the ledger and VoIP layers.
Ledger safety
Section titled “Ledger safety”- Add immutable
Transactionmodel with idempotency keys - Add cached balance column on
accounts(computed from ledger) - Add idempotent ledger service for credits/debits
Ownership constraints
Section titled “Ownership constraints”- Validate accounts always have at least one owner user
- Prevent orphaned individual/company accounts (app-level guard)
Phone normalization
Section titled “Phone normalization”- Add
phony_rails(or equivalent) to normalize E.164 numbers - Add
PhoneNormalizableconcern for future Call model
Security baseline
Section titled “Security baseline”- Add
rack-attack - Throttle: login, magic link, token, call initiation
- Remove dev-only SMTP CRL bypass (
SMTP_DISABLE_CRL_CHECK,VERIFY_NONE) before production
Exit criteria: Ledger is safe for concurrent updates, ownership is enforced, phone normalization is ready, and rate limits are in place.
Phase 2: Wallet + Ledger (Target: Day 2–3)
Section titled “Phase 2: Wallet + Ledger (Target: Day 2–3)”Objective: Store balances and an auditable transaction log for both individual and company wallets.
- Balance stored as
*_centsinteger on wallet owner (Account) -
Transactionledger with idempotency keys (avoid double credits/charges) - Basic credits page showing current balance + recent transactions
- Admin-safe “manual adjustment” transaction type
Test checklist (Phase 2)
- Credits page shows current balance + ledger-backed balance
- Create admin adjustment (Avo): positive amount increases balance
- Create admin adjustment (Avo): negative amount decreases balance
- Transaction appears in credits list with type, status, amount
- Idempotency check via console does not double-credit
Exit criteria: You can credit/debit balances in dev with a consistent ledger.
Phase 3: “First Call” thin slice (Target: Day 3–4)
Section titled “Phase 3: “First Call” thin slice (Target: Day 3–4)”Objective: Successfully place an outbound call from the browser to PSTN.
- Twilio token endpoint:
GET /api/calls/token(rate-limited) - TwiML endpoint:
POST /api/webhooks/twilio/voice - Status endpoint:
POST /api/webhooks/twilio/status(persist call lifecycle) - Twilio webhook signatures validated (RequestValidator)
- Webhook processing offloaded to background job
- Dialer page (mobile-first)
- Stimulus controller integrating Twilio Voice JS (connect/disconnect/status)
- Server-side number normalization/validation to E.164 (e.g.,
phony_rails) - Persist Call records from Twilio webhooks
- Attribute calls to account/user/seat from client identity
- Show recent numbers on the dialer (server-side)
Exit criteria: You can dial a real number, it rings, answers, and hangs up cleanly.
Phase 3.1: Security & Quality Hardening (Target: Day 4)
Section titled “Phase 3.1: Security & Quality Hardening (Target: Day 4)”Objective: Address code review findings and improve system robustness.
- Security: Enforce strong parameter permitting in Twilio webhooks
- Observability: Enhanced error logging for Twilio API calls
- Quality: Refactored authentication and async logic
- Testing: Verified webhook security and error handling with integration tests
Phase 3.5: Unified Magic-Link Entry (Target: Day 4)
Section titled “Phase 3.5: Unified Magic-Link Entry (Target: Day 4)”Objective: Single email-first sign-in flow that routes users/seats automatically.
- Single sign-in screen with email-only input
- Existing user → magic link
- Allowed company domain → auto-provision seat + magic link
- Unknown domain → create individual account + magic link
- Navbar/CTA “Get Started” routes to the same entry point
- Async magic-link delivery (
deliver_later) + resend link - Trackable sign-in counters for cleanup
- Daily cleanup job for unconfirmed users (Solid Queue recurring)
- Mismatch handling for
/magicvs/seatslinks with expired link fallback - Add guardrails/observability for domain auto-provisioning (logging, rate limits)
Exit criteria: One entry point handles all sign-ins without account-type selection.
UI Updates (Dialer)
Section titled “UI Updates (Dialer)”Objective: Refresh the dialer UI with a glass + iPhone-style keypad layout.
- Glass/glow background shell for
/dial - iPhone-like dialpad layout with keypad interactions
- Phonebook and balance panels added (design scaffolding)
- Mobile app-like shell for Contacts/History/Settings and compact Credits summary
- Logged-out and logged-in hamburger menus aligned to mobile design
- Desktop pricing calculator now uses live rates + searchable country picker
- Public 404 page styled to match Mobayilo brand
Phase 4: Stripe top-ups + auto top-up (Target: Day 4–6)
Section titled “Phase 4: Stripe top-ups + auto top-up (Target: Day 4–6)”Objective: Users can top up credits and enable auto top-up; balances update reliably.
- Stripe Checkout session for one-time top-ups
- Stripe Checkout (setup mode) for saving a card for auto top-up
- Stripe webhook handler (idempotent) credits wallet balance + stores payment method
- Enforce minimums:
- Individual ≥ $5
- Company ≥ $100
- Auto top-up settings: enabled, threshold, amount, daily cap
- Auto top-up triggers off-session charge when balance < threshold
- Receipt/transaction record created for each top-up
Notes:
- Credits flow now redirects back to
/dialafter successful checkout or settings save. - Auto top-up values are rounded to whole dollars for entry.
Exit criteria: A real Stripe test payment increases wallet balance and auto top-up can charge and record a top-up.
Phase 5: Bill calls and update balances (Target: Day 5–7)
Section titled “Phase 5: Bill calls and update balances (Target: Day 5–7)”Objective: Calls produce costs and deduct credits correctly.
- Persist
Callrecords with Twilio SID and final duration - Billing calculation: per-started-minute
- Deduct credits exactly once on completion (idempotent)
- Call history page with cost and duration
- Seat attribution for company calls (who initiated the call)
Notes:
- Call charge rate uses
CALL_RATE_CENTS_PER_MINUTE(default 5) until rate tables land. - Static rate table now lives in
config/call_rates.ymland is served via/api/rates/:iso - Admin sync actions: “Sync Twilio Voice Rates” (Twilio) and “Sync YAML Call Rates” (static table)
Exit criteria: Balance decreases correctly after completed calls and ledger reconciles.
Phase 5.5: Caller ID & Company Number Enforcement (MVP-CRITICAL) (Target: Day 6–7)
Section titled “Phase 5.5: Caller ID & Company Number Enforcement (MVP-CRITICAL) (Target: Day 6–7)”Objective: Enable compliant outbound identity for individuals and companies, close audit blockers, and prepare for public beta.
Individual: Caller ID Verification
Section titled “Individual: Caller ID Verification”- OTP verification via Twilio Verify (anti-abuse gate, balance ≥ $5)
- Optional verified Caller ID using Twilio Outgoing Caller ID validation
- Correct flow implemented:
- Twilio returns validation_code
- User enters code on phone keypad (not website)
- No web-based confirmation endpoint
- Persist pending verification state
- Server-side enforcement at call time:
- Verified Caller ID used when available
- Fallback to Mobayilo default number otherwise
Company: Number Provisioning & Billing
Section titled “Company: Number Provisioning & Billing”- Mandatory Twilio phone number for outbound calls
- Balance pre-check before provisioning (prevents real-money risk)
- Monthly number fee charged (idempotent, once per month)
- Insufficient funds:
- Number suspended
- Outbound calls hard-fail
- Inbound calls explicitly rejected with TwiML message
Security & Compliance
Section titled “Security & Compliance”- Caller ID always chosen server-side
- Client cannot spoof callerId
- Twilio API behavior aligned with SDK constraints (validation_requests.create)
- Audit blocking issues fully resolved
Exit criteria: Caller ID and company number enforcement works end-to-end; no Twilio resources are purchased without funds; audit verdict cleared.
Phase 6 (MVP+): Marketing & Growth (Target: Day 7+)
Section titled “Phase 6 (MVP+): Marketing & Growth (Target: Day 7+)”Objective: Capture leads and enable external subscriptions.
Subscriber API
Section titled “Subscriber API”-
subscriberstable for capturing email interest - JSON API
POST /api/subscribefor public form submissions - Email uniqueness and format validation
- CORS configuration allowing
mobayilo.comrequests - Admin dashboard (Avo) resource for managing subscribers
Exit criteria: Public marketing site can successfully POST emails to the backend.
Phase 7 (Beta): Access Control (Target: Day 7+)
Section titled “Phase 7 (Beta): Access Control (Target: Day 7+)”Objective: Gate sign-ups behind a beta waitlist managed by admins.
- Add
status(waiting/invited) tosubscriberstable - Update
Subscribermodel logic - Protect
Users::SessionsControllerwith beta gatekeeper - “You’re on the list” message for blocked users
- Admin action (Avo) to “Invite to Beta”
- Add case-insensitive unique index on
subscribers.email
Exit criteria: Only invited emails can complete the sign-up flow.
Recent updates (2026-01-29)
Section titled “Recent updates (2026-01-29)”- Caller ID verification rewritten to match Twilio’s keypad-entry flow
- Company number provisioning now gated by available balance (pre-purchase)
- Server-side caller ID enforcement finalized for individuals and companies
- Audit blocking issues resolved; ready for public beta verification
- Mobile: in-phone shell for Contacts/History/Settings + Credits summary view
- Mobile: hamburger menu polish + sign-in overlay improvements
- Rates: YAML-backed rates table + API integration (individual vs company seat rates)
- Admin: Call Rates visible in Avo; added “Sync YAML Call Rates” action
- Desktop: pricing calculator uses searchable country picker + live rates
- Auth:
/dialnow requires login; “Open Dialer” routes to sign-in when logged out - Misc: styled 404 page; fixed sign-in page background; CSRF hardening for magic link form
What’s missing before opening Public Beta
Section titled “What’s missing before opening Public Beta”- Payments hardening: verify Stripe webhooks in production, SCA fallback, retry UX.
- Rate integrity: finalize rate source of truth (Twilio vs YAML), document update cadence.
- Monitoring/alerts: basic error tracking (Sentry) + uptime checks for Twilio webhooks.
- Abuse controls: finalize rate limits and add logging for domain auto-provisioning.
- Legal/Compliance: finalize Terms/Privacy and add KYC/telephony compliance checks if required.
- Support flow: user-facing help/support channel and basic FAQ.
Phase 8 (MVP+): Auto top-up hardening (optional)
Section titled “Phase 8 (MVP+): Auto top-up hardening (optional)”Objective: Improve reliability, visibility, and safeguards for auto top-up.
- Notify user on auto top-up failures (email + in-app banner)
- Add SCA recovery flow for off-session failures
- Admin dashboard for auto top-up retries and caps
Exit criteria: Auto top-ups are observable with retry + recovery path.
Decisions needed before/during Phase 1
Section titled “Decisions needed before/during Phase 1”- Company seat allowlist: domain-based vs explicit email allowlist
- Number provisioning: company admin self-serve vs manual/admin-only (MVP)
New decisions before Phase 4–5
Section titled “New decisions before Phase 4–5”- Should individual account creation ever be blocked for company-like domains?
- Do we need email-domain verification before auto-provisioning seats?
- Stripe Checkout + setup mode for payments and saved cards
- Subscriber API requires public CORS access? (Yes, implemented)