Skip to content

Add premium subscriptions and casual server orchestration#62

Draft
NicholasBottone wants to merge 7 commits into
mainfrom
polar-subscriptions
Draft

Add premium subscriptions and casual server orchestration#62
NicholasBottone wants to merge 7 commits into
mainfrom
polar-subscriptions

Conversation

@NicholasBottone

@NicholasBottone NicholasBottone commented May 28, 2026

Copy link
Copy Markdown
Member

Summary

Adds premium subscriptions for casual server hosting. Polar is the billing provider and credit balance authority, while SecondWebsite owns entitlement checks, casual server authorization, website UX, lifecycle state, and orchestrator callbacks. Ranked server flows remain free and separate.

Subscriptions and casual servers

  • Adds the new subscriptions Django app.
  • Uses the Polar Python SDK for checkout creation, webhook verification, customer meter balance lookup, and usage event ingestion.
  • Uses Polar Credits for monthly casual-server allotments. V1 maps 1 credit to 1 runtime minute, rounded up to 5-minute increments when sessions stop.
  • Adds website pages for viewing the current plan, Polar-backed remaining credits, recent sessions, and launching/stopping casual servers.
  • Adds orchestrator integration so SecondWebsite authorizes casual launches, creates a website session, calls the orchestrator, and records lifecycle callbacks.

API endpoints added

  • GET /api/subscriptions/me/entitlement/
  • GET /api/subscriptions/casual-games/
  • GET /api/subscriptions/users/{discord_user_id}/entitlement/
  • POST /api/subscriptions/server-sessions/start/
  • POST /api/subscriptions/server-sessions/{session_id}/stop/
  • POST /api/subscriptions/server-sessions/{session_id}/orchestrator-event/
  • POST /subscriptions/polar/webhook/

DB tables/models added

  • SubscriptionPlan: configurable tiers, pricing, monthly credit allotment, max session length, concurrency, Polar product mapping.
  • SubscriptionEntitlement: provider-neutral active subscription/comp entitlement records.
  • ServerSession: casual server reservation/lifecycle state, orchestrator session details, connection info, callbacks, failures.
  • UsageLedgerEntry: local audit/idempotency ledger for consumed credits; Polar is the paid-user balance authority.
  • WebhookEvent: idempotency/audit record for Polar and orchestrator events.

Inter-service contracts

  • Discord bot -> SecondWebsite:

    • Casual server launches must go through SecondWebsite.
    • Uses the existing shared API_KEY via X-API-KEY.
    • Sends owner_discord_id; SecondWebsite handles entitlement, Polar credit balance checks, max session length, and concurrency.
    • Ranked flows are unchanged and do not consult subscriptions.
  • SecondWebsite -> Polar:

    • Uses POLAR_ACCESS_TOKEN, POLAR_WEBHOOK_SECRET, and the configured Polar casual-server meter.
    • Creates checkout sessions via the SDK.
    • Reads customer meter balance before launch.
    • Ingests a usage event when a session stops so Polar credits are consumed in the portal-managed system.
  • SecondWebsite -> orchestrator:

    • Uses ORCHESTRATOR_API_BASE_URL and ORCHESTRATOR_API_TOKEN.
    • Fetches casual game metadata, launches casual sessions, and requests stops.
    • The orchestrator owns actual server lifecycle; SecondWebsite owns authorization and credit accounting.
  • Orchestrator -> SecondWebsite:

    • Sends all casual lifecycle callbacks to orchestrator-event/ with X-API-KEY.
    • Supported events include launch_accepted, ready, heartbeat, stopping, stopped, launch_failed, exited, and killed.
    • Callback event_id is used for idempotency.

Environment/configuration

  • Adds polar-sdk as a dependency.
  • Adds Polar SDK/credits settings: POLAR_SERVER, optional POLAR_API_BASE_URL, POLAR_CASUAL_SERVER_METER_ID, POLAR_CASUAL_SERVER_EVENT_NAME, and POLAR_REQUEST_TIMEOUT_SECONDS.
  • Existing plan rows need polar_product_id configured in Django admin to map website tiers to Polar products.

Migration baseline repair

  • Removes migrations/ from .gitignore.
  • Adds baseline migrations for existing first-party apps.
  • Production deployment needs this one-time command:
    • .venv/bin/python manage.py migrate --fake-initial
  • After the baseline is established, future deploys should use normal committed migrations:
    • .venv/bin/python manage.py migrate

CI

  • Updates GitHub Actions to check for missing migrations.
  • Verifies a fresh DB can run migrations.
  • Runs Django checks and pytest before deploy.

Validation

  • .venv/bin/python manage.py makemigrations --check --dry-run
  • .venv/bin/python manage.py check
  • .venv/bin/python -m pytest

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant