Quickstart
Get a local ScaiControl running end-to-end in about 15 minutes. By the end you'll have:
- A running backend on
:8000with the OpenAPI Swagger UI. - A running portal on
:5173. - A registered ScaiKey app + a super-admin user.
- One service in the catalog, one trial subscription, one finalised invoice.
For production deployment, see the operator runbook (separate from this guide).
Prerequisites#
| Tool | Version |
|---|---|
| Python | 3.12+ |
| Node.js | 20+ |
MariaDB (or use aiosqlite for dev) |
10.11+ |
| Redis | 7+ |
| ScaiKey instance | Reachable URL with operator account |
You also need:
- An S3-compatible bucket (MinIO works locally) — for invoice PDFs and uploads.
- Operator access to a ScaiSend instance (or accept that emails will be logged-only).
1. Clone & install backend#
1 2 3 4 5 | |
2. Configure environment#
Create .env at the repo root (one level up from backend/):
1 2 3 4 5 6 7 8 9 10 11 12 | |
SCAIKEY_*, SCAISEND_*, payment provider keys — leave blank for now; we'll populate them via the CLI in step 4 (or set them inline if you already have credentials).
3. Run migrations#
1 2 | |
Should print "Running upgrade … 008_eu_invoicing" (or later) and exit clean.
4. Register with ScaiKey#
1 2 3 4 | |
This submits a registration request. An operator approves it in ScaiKey. Then:
1 | |
Repeat until APPROVED. The CLI writes SCAIKEY_CLIENT_ID, SCAIKEY_CLIENT_SECRET, SCAIKEY_APP_ID, and SCAIKEY_ISSUER to .env.
5. Sync users + assign super_admin#
1 2 | |
You now exist locally with full bypass on require_permission() checks.
6. Start backend + worker + frontend#
In three terminals:
1 2 3 | |
1 2 3 | |
1 2 3 4 | |
Visit:
http://localhost:5173— portal (you'll redirect through ScaiKey to log in).http://localhost:8000/docs— Swagger UI (interactive API explorer).
7. Make your first API call#
Grab a JWT by logging in through the portal, then open browser DevTools → Application → Local Storage → copy the access_token. Or use curl with ScaiKey's /oauth/token directly.
1 2 3 4 | |
Expected: a JSON CurrentUser payload with your roles and permissions.
8. Add a service to the catalog#
Either via the portal (/admin/registry) or API:
1 2 3 4 5 6 7 8 9 | |
Approve it (auto-approved if its slug is in AUTO_APPROVED_APP_IDS):
1 2 | |
9. Add a plan#
1 2 3 4 5 6 7 8 9 10 11 | |
10. Subscribe (as a tenant) and finalise an invoice#
This part assumes you have a tenant in ScaiKey already synced via step 5. From the portal:
- Switch to the tenant context.
- Open
/services, find "ScaiKey", click "Subscribe → Starter". - As the operator, open
/admin/billing, find the auto-generated draft invoice for this month, click Finalize. - Click Send — the invoice PDF is now in S3 and the customer gets an email (or a log entry if ScaiSend isn't configured).
You now have a working end-to-end flow: catalog → subscription → invoice → PDF in S3.
Next steps#
- Understand the model — read Concepts: architecture and Multi-tenancy.
- Wire up payments — set
STRIPE_API_KEYetc. and a webhook endpoint; see the catalog page for your provider in API reference. - Subscribe to webhooks — register a subscriber at
/admin/webhook-subscriptions; consume events. - Customise invoice branding —
/admin/billing/templates→ GrapesJS designer; see Concepts: templates. - Run the integration test suite —
cd backend && pytest.
Common first-run issues#
| Problem | Fix |
|---|---|
alembic upgrade head errors with "Access denied" |
Wrong DATABASE_URL. For dev without MariaDB: DATABASE_URL=sqlite+aiosqlite:///./dev.db |
setup status always pending |
Operator hasn't approved in ScaiKey yet, OR SCAIKEY_ISSUER is unreachable |
| Portal redirects to ScaiKey then 404s | Check SCAIKEY_CLIENT_ID is set in .env AND in the ScaiKey app config; the redirect URI must match exactly |
| Invoice finalize 500s | See Troubleshooting: invoice not finalising |
| Worker process exits immediately | Redis isn't reachable, or REDIS_URL is wrong |