Phase 2: Monetization MVP — Stripe, license keys, Pro feature gating#2
Merged
Conversation
- Rename Sim2Real -> Sim2Sim across README, page, hero, docstrings, CSS, JS - Add GitHub Actions CI workflow (fixes broken badge) - Fix solve_base_stock dead code; correct Type-II fill-rate formula (1 - E[B per cycle] / mu_L, not E_B * D / D) - Standardize inventory lead-time to DAYS everywhere (lead_time_days param; sigma_L = sigma_d * sqrt(L_days)) for unit consistency - Add _little_law_residual: relative Little's Law diagnostic instead of absolute - Simulation: fix warm-up off-by-one; raise default warmup to max(100, N/5) - Production CORS: require ALLOWED_ORIGIN (fail loudly on empty) - Cache Anthropic client lazily at module level - Add pyproject.toml with ruff + mypy + pytest config - README polish: live demo placeholder, screenshot, monetization note - Add 7 new tests for reorder-point and base-stock (57 -> 64 passing)
- src/export/excel.py: queuing, inventory, LP workbook builders (openpyxl) - src/export/pdf.py: ReportLab Platypus templates with clean Sim2Sim branding - 6 new POST /api/export/* endpoints gated by require_pro dependency - Stub src/billing/licenses.py:require_pro (real impl in billing branch) - 7 new tests in tests/test_exports.py
Billing - src/billing/licenses.py — HMAC-signed LIC-XXXX-XXXX-XXXX-XXXX keys - src/billing/db.py — SQLite storage with idempotency on stripe session id - src/billing/webhook.py — checkout.session.completed handler with stdlib-only Stripe signature verification (no SDK dependency) - src/billing/email.py — Resend integration with graceful no-op when key is unset, so failed emails never block paid customers - src/billing/schemas.py — Pydantic models - 24 new tests covering key generation, activation, webhook signature verification, idempotency, and end-to-end license creation Endpoints - POST /api/billing/activate — paste key, get tier - GET /api/billing/status — header-based status check - POST /api/billing/webhook — Stripe receiver Frontend - static/pricing.html — three-tier card layout (Free / 49 Pro / 249 Team) - static/account.html — paste-key flow + clear-license button - static/js/license.js — localStorage handling, status fetch, activation - static/js/exports.js — Excel + PDF buttons attached after each result; Free users see a locked button + Upgrade modal - static/css/billing.css — pricing grid, account card, modal, tier pill - index.html — Pricing/Account nav links, tier pill, exports.js wiring - app.js — Sim2SimExports.attach() called after each render call site Plumbing - main.py — explicit /pricing and /account routes (catch-all served SPA); lifespan now calls billing_db.init_db() - .env.example — full launch config (Stripe, Resend, license secret, app URL) - .gitignore — exclude sim2sim.db and its WAL/journal files - LAUNCH.md — 30-minute deployment checklist (domain, Stripe, Resend, Replit) Tests: 111 passed (was 64 → +47: 24 billing + 23 from export module)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
Turns Sim2Sim from a free demo into a paid product, ready to deploy in one afternoon.
New
LIC-XXXX-XXXX-XXXX-XXXX, HMAC-signed, SQLite-backed/api/billing/webhook— stdlib-only signature verification, no SDK dependencycheckout.session.completed/pricing— three-tier card layout (Free, $49 Pro, $249 Team)/account— paste-key activation, no login requiredTests
Was 64 → now 111 passing:
tests/test_billing.py— key generation/validation, activation, webhook signature, idempotency, end-to-end license creationFiles
Operator checklist before going live
See LAUNCH.md for the full 30-minute walkthrough:
sim2sim.app)/api/billing/webhook4242 4242 4242 4242Notes
ENVIRONMENT=development, the license keydev(or empty header) unlocks Pro endpoints, so the demo still runs without Stripe.sim2sim.db. Replit's filesystem persists this across deploys. Excluded from git via.gitignore.stripe_session_id— Stripe's retries won't double-issue keys.