scalio-platform
Shared building blocks of the Scalio apps (Nexus, Compass, Citadel, Foundry, Rosetta, Pulse, Beacon, Cockpit, ID, Monitor). Before this package each app kept its own copy of these files (architecture review C2/C4, ADR 0058 in scalio-docs). Nothing in this package is secret.
| Module | What it does |
|---|---|
scalio_platform.job_lease |
Runs a background loop on one instance at a time (lease in db.job_leases). During an update two instances run side by side; without the lease both would act. |
scalio_platform.migrations |
Schema migrations for MongoDB: ordered steps, each applied once, version in db.meta (schema_version). |
scalio_platform.health |
The answer of GET /api/health that Scalio Monitor reads (ok / degraded / down, leases of the loops). |
scalio_platform.error_report |
Sends unexpected errors to Scalio Monitor, only when ERROR_REPORT_URL and ERROR_REPORT_TOKEN are set. |
scalio_platform.app_links |
Links and features of the product switcher (SCALIO_APP_LINKS, SCALIO_STAGE, SAAS_MODE). |
scalio_platform.roles |
Permission catalog of the app, built-in and own roles (app_roles), require_perm for routes, shared role API (roles_router) for RoleAdmin in scalio-ui. |
scalio_platform.tenant_jobs |
Runs one job per tenant side by side (for_each_tenant): at most TENANT_JOBS_PARALLEL at once (default 4), a time budget per tenant (TENANT_JOBS_TIMEOUT, default 900 s), a failing tenant never stops the others; for MSP instances with many customers (ADR 0063 mandant/M11). |
scalio_platform.setup_wizard |
State of the Einrichtungsassistent (GET/PUT /api/setup/wizard, ADR 0060): wizard_state, save_wizard, parse_update. |
scalio_platform.audit |
Protokoll → Aktionen (ADR 0070): one format in db.audit_log (record, target, diff), TTL 365 days, audit_router (GET /api/audit with filters, cursor and counts per chip, GET /api/audit/export.csv), migrate for old formats, uncovered for the route guard test. |
scalio_platform.jobs |
Protokoll → Jobs (ADR 0070): Registry of the background jobs, run records each run (db.job_runs, TTL 90 days; a job returning None, 0, False, an empty list or a dict without summary and counts only updates db.job_state), «Jetzt ausführen» through db.job_requests and serve_requests in the worker, QueueSource for the app's queue, jobs_router. |
scalio_platform.mail |
E-Mail (ADR 0069 W5): sending through SMTP or Microsoft 365 (secrets sealed by the app, never returned), outbox mail_outbox with retries (flush in the worker), templates per mail kind and language with placeholders (MailKind, own texts in settings {id: "mail_templates"}), router for «E-Mail-Versand» and «E-Mail-Vorlagen» in scalio-ui 0.29.0. |
Use in an app
scalio-platform==0.1.0 # backend/requirements.txt, exact version
from scalio_platform import error_report, health, job_lease
from scalio_platform.migrations import BASELINE, run_migrations
MIGRATIONS = BASELINE # append (2, migrate_002_...) and so on, never edit past steps
async def startup():
await run_migrations(db, MIGRATIONS) # before the background loops
for name, loop in LOOPS.items():
asyncio.create_task(job_lease.run_exclusive(db, name, loop))
error_report.install(app, "citadel", build_info)
code, body = await health.health_report(db, build_info(), lease_jobs=sorted(LOOPS))
# probe of the provisioning engine (SaaS on the Docker engine), header X-Provision-Health-Secret
code, body = await health.provision_report(db, build_info(), secret=os.environ.get("PROVISION_HEALTH_SECRET", ""),
provided=request.headers.get("x-provision-health-secret", ""))
A migration step must be safe to run twice: two instances can start at the same moment.
Zurücksetzen (factory reset, ADR 0064 / 0069)
from scalio_platform.factory_reset import factory_reset_router
async def after_wipe(remove_license: bool):
if remove_license:
await licensing.runtime.refresh(db) # free edition right away
await login_policy.announce_setup_code() # new setup code in the log
app.include_router(factory_reset_router(
get_db=lambda: db, current_user=require_admin,
password_hash=lambda u: u.get("password_hash"), verify_password=auth.verify_password,
keep_meta=(f"{PRODUCT.code}_installation", "schema_version"), license_meta=(PRODUCT.meta_id,),
saas_mode=saas_mode, after_wipe=after_wipe))
GET /api/admin/factory-reset answers {available, password} (SaaS: not available, the customer portal resets it);
POST takes {confirm: "RESET", password, remove_license}. allowed(user) narrows who may (Foundry: platform owner),
error(code) maps the codes reset_in_portal, reset_confirm_wrong, current_password_wrong to the app's own errors.
The frontend is FactoryReset from @scalio-cloud/ui 0.27.0.
Develop and release
pip install -e ".[dev]", thenpytest -qandruff check .(both run in CI).- Release: bump
pyproject.tomland__version__, open a scalio-docs PR withpython3 tools/changelog.py --repo scalio-platform release <version>(changelog in scalio-docschangelog/scalio-platform/, ADR 0066), merge, then «Freigeben» in the Scalio Cockpit (workflowpublish.yml: PyPI with trusted publishing, tag and GitHub release). Tags withoutv. - A change of behaviour changes every app on its next upgrade: say so in the PR and the CHANGELOG.
Protokoll: Aktionen und Jobs (ADR 0070)
from scalio_platform import audit, jobs
from scalio_platform.audit import Category
CATEGORIES = (Category("access", "Zugriff", "Access", ("user.", "role.")),
Category("license", "Lizenz", "License", ("license.",), always=True))
await audit.record(db, "user.create", user, category="access", target=audit.target("user", u["id"], u["email"]),
detail=f"Konto angelegt · {u['email']}", request=request)
app.include_router(audit.audit_router(get_db=lambda: db, viewer=require_perm(CATALOG, me, get_db, "audit.view"),
categories=CATEGORIES, tenant_scope=lambda u: None), prefix="/api")
# worker
REGISTRY = jobs.Registry([jobs.Job("mail_intake", "Mail-Eingang", "Mail intake", "Jede Minute", "Every minute")])
await jobs.run(db, "mail_intake", mail_intake) # inside the loop; return None when nothing happened
await jobs.serve_requests(db, REGISTRY, HANDLERS) # own loop every few seconds («Jetzt ausführen»)
# API
app.include_router(jobs.jobs_router(registry=REGISTRY, get_db=lambda: db, viewer=view, runner=run_perm,
queue=MyQueue(), audit=log), prefix="/api")
Call audit.ensure_indexes(db) and jobs.ensure_indexes(db) at startup. Never write passwords, tokens or contents
into detail, changes or a job summary (changes drops fields named like pass/secret/token/key).
E-Mail (ADR 0069 W5)
from scalio_platform import mail
KINDS = (mail.MailKind("resolved", ("Ticket erledigt", "Ticket done"),
("An die meldende Person, wenn ein Ticket erledigt ist", "To the reporter when a ticket is done"),
subject={"de": "[{key}] Erledigt: {title}", "en": "[{key}] Done: {title}"},
body={"de": "Guten Tag {name}\n\n...\n\n{sender}", "en": "Hello {name}\n\n...\n\n{sender}"},
tokens=("key", "title", "name", "link"), sample={"key": "IT-12", "title": "Drucker", ...},
switchable=True),)
mailer = mail.Mailer(get_db=lambda: db, app_name="Scalio Beacon", kinds=KINDS,
seal=secret_box.seal, unseal=secret_box.unseal, # the app's own encryption
collection="meta", # default "settings"
override=scalio_selftest.mail.smtp_settings, # test mailbox on test instances
allowed=scalio_selftest.mail.allowed, base_url=lambda: os.environ.get("APP_PUBLIC_URL", ""))
app.include_router(mailer.router(admin=require_admin, audit=log), prefix="/api") # /api/mail/...
await mailer.send(person["email"], "resolved", {"key": t["key"], ...}, lang=person.get("language"), ref=t["id"])
await jobs.run(db, "mail_outbox", mailer.flush) # worker, every 30 seconds; call mailer.ensure_indexes() once
Every template knows {app_name}, {app_url} and {sender} (sender name of the settings, else the app name). A
template may be plain text or HTML (from the editor); in HTML the values are escaped. The built-in kind test is the
test mail. send returns False when mail is off, the kind is switched off, or allowed refuses the address. check(subject, html) may refuse a mail with ValueError (Foundry: no forms, only https links); it runs on saving or testing a template and before a mail goes into the outbox.
Metadata
Release files for scalio-platform 0.8.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| scalio_platform-0.8.1.tar.gz | 63.2 kB | With provenance | Details for scalio_platform-0.8.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| scalio_platform-0.8.1-py3-none-any.whl | Python 3 | none | any | Details for scalio_platform-0.8.1-py3-none-any.whl |
Total release size: 110.6 kB
Release files / scalio_platform-0.8.1.tar.gz
| Download URL | scalio_platform-0.8.1.tar.gz |
|---|---|
| Size | 63.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5f00cf2f7412e95b4ba677f28bd566fc9ac5bd2bba003289e6d331abf7d52c65
|
|
BLAKE2b-256 checksum How to use checksums |
f96531c51c5e99472710bfeae7e7b50024fc20325327f7d90aab1f4d714ab1be
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.
Transparency logRelease files / scalio_platform-0.8.1-py3-none-any.whl
| Download URL | scalio_platform-0.8.1-py3-none-any.whl |
|---|---|
| Size | 47.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e3926ab080614fbdab700859a27419e7f27cfc65407bcae00418b2bd67136935
|
|
BLAKE2b-256 checksum How to use checksums |
0b3c0df423947a6cdc21bbee6fb319ec71fe94ca31f90760fff0fe5f1e3ec088
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.
Transparency logSecurity for scalio-platform 0.8.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for scalio_platform-0.8.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.