The original multi-tenant design (PR #184, superseded ADRs 0008-0011) routed every user through Alpaca OAuth for paper and live trading. This over-depended on Alpaca:
Every user — including free users who may never make a real trade — had to complete OAuth authorization with Alpaca before paper-trading.
Raxx stored an encrypted Alpaca OAuth token for every user, creating a documented exception to invariant #1 (no stored credentials) that applied across the entire user base.
Paper-trade history was governed by Alpaca's retention policy, not ours. Tier-gated retention (Free 90d / Pro 3yr / Pro+ unlimited per pricing matrix) was hard to implement cleanly on top of Alpaca's opaque storage.
Alpaca's paper trading is itself a simulation against their market data. We can run the same simulation ourselves.
Realization: Alpaca's paper trading is a simulator. We can be that simulator. Doing so eliminates per-user OAuth complexity for paper (vast majority of users), restores the "no stored credentials" invariant for that majority, makes tier retention trivial (our DB), gives us data sovereignty, and keeps Raxx out of Broker-API / BD territory forever. We become a research + paper + broker-handoff platform, not a broker.
Decision
Raxx builds MBT — a native paper-trading engine — and uses it as the default execution surface for all users. Alpaca is scoped to (a) one shared server-side market-data account, and (b) optional per-user live-broker handoff for Pro+ users who graduate from paper (see ADR 0014).
Scope
MBT owns accounts, positions, orders, fills, activities, and end-of-day snapshots for every user.
Market data: one Alpaca Market Data account, server-side; tier-gated delivery (Free delayed, Pro real-time, Pro+ real-time + archive).
Async jobs: Celery + Redis for v1 (Temporal deferred to v2 for stateful long-running workflows).
Sessions: REST /api/sessions/*, JWT + HTTP-only cookie, server-side revocation, per-tier rate limits (60/600/3000 per minute per pricing.md). Detailed in docs/architecture/session-engine.md.
Out of scope (intentional)
Alpaca paper-trading for any tier after GA.
Per-user Alpaca OAuth for paper or for market data.
Raxx as broker / clearing agent (Broker API path permanently dropped).
MBT user-to-user order matching (single-book-per-user, real-market-data-informed fills).
Migration
Dark → shadow (double-write MBT alongside Alpaca paper for parity diff) → flagged per-user cutover → GA (Alpaca paper writes disabled). Detailed in mbt-paper-trading-engine.md §10.
Consequences
Positive
Invariant #1 restored for free + most Pro users. No broker token to store. The ADR 0009 exception narrows to the Pro+ live-handoff subset (re-scoped as ADR 0014).
Tier-gated retention is trivial. Free 90d / Pro 3yr / Pro+ unlimited is a purge job on our DB, not a dance with Alpaca's policies.
Data sovereignty. Alpaca cannot change paper policy and break our product overnight. Our simulator, our rules, our retention.
Regulatory posture cleaner. MBT stays firmly in the user-directed-simulation lane; no BD/Broker-API exposure; Advisers Act flags only arise if we publish individualized strategies (same as before, surfaced for counsel).
Simpler onboarding. A free user can paper-trade within seconds of account creation; no third-party OAuth flow gates the first-run experience.
Deterministic replay — every fill records the NBBO snapshot that produced it. Auditable "why did this fill at $X" forever.
Negative
We build the simulator. Order-matching logic, corporate-actions handling, options expiration, margin math — these are real engineering, not library installs. Multi-month effort.
Fill realism is our responsibility. Users will compare MBT fills to Alpaca's paper and to real fills. We need to be defensibly close and honest where we differ ("simulated paper trade with realistic but not perfect fills").
Options complexity. Multi-leg fills, margin calculations for spreads, and expiration handling are the largest implementation surface. v1 scope trims some edge cases (portfolio margin, calendar spreads, partial fills) deliberately.
Migration cost. Existing users on the shared Alpaca paper account need state imported into MBT. One-shot importer + shadow period mitigate.
We still depend on Alpaca for market data and for the minority live-handoff path. Narrower surface, but not zero.
Neutral
Celery + Redis over Temporal is a v1 choice, not a forever choice. Temporal's right answer for stateful long-running workflows arrives in v2 when MBT grows them.
Single Alpaca data account suffices for v1 user counts; requires re-evaluation (second key, entitlement upgrade) at scale. Not a blocker for GA.
Alternatives considered
Stay with the PR #184 plan (per-user Alpaca OAuth for paper)
Rejected. The reasons to change are the positive consequences above: invariant compliance, tier retention, data sovereignty, onboarding friction. The reasons to stay were mostly "less engineering for us" — real, but outweighed.
MBT for paper, but route all live via our own broker/clearing partnership (Broker API)
Rejected and permanently off-roadmap. BD status + FINRA-regulated clearing is a regulatory lift Raxx does not want. Live routes stay user-to-Alpaca OAuth via the live-handoff pattern (ADR 0014). Pro tier adds a second broker (per pricing matrix — likely IBKR or tastytrade) via the same handoff pattern.
Use a third-party simulator library / service
Considered, rejected. No mature off-the-shelf options simulator exists that covers our scope (multi-leg options, corporate actions, tier retention). Commercial options (e.g. QuantConnect-as-backend) cede too much of the product. Open-source options-pricing libraries (e.g. QuantLib) help at the math layer but do not solve the account/order/fill surface. Build remains correct.
Minimal v1 scope (equities only, no options)
Rejected for product reasons. Persona is options-forward ("Weekly-Income Pat"). Options parity in v1 is a product requirement, not a nice-to-have.
Compliance checklist
[x] Invariant #1 restored for the majority of users (no broker token).
[x] GDPR erasure cascades through MBT tables (mbt_accounts + children on users.id delete).
[x] Audit trail on every order lifecycle event (submit, accept, reject, modify, cancel, fill, corporate action).