DynoStatic foundations
Locked contracts for the application spine. Product features may grow; these boundaries must not drift.
Hosting contract
- PHP 8.4+ and MySQL 8 / MariaDB 10.6+ only.
- No required Node runtime, Redis, containers, or URL rewrites.
- Physical gateways:
index.php,admin/index.php,api/index.php,install/index.php,health.php,integration.php,media.php, plus avatar/feed/style/verify/unsubscribe entrypoints. - Website is the ownership, origin, permission, and settings boundary.
Public embed (widgets)
- Host markup:
data-dynostatic-widget="WIDGET_ULID". - Loader:
{installation}/embed.js(classic deferred script). - Events:
dynostatic:ready,dynostatic:submitted,dynostatic:consent,dynostatic:error. - Public widget/discussion APIs require an exact registered
Origin. - Mutations use signed one-use action tickets; never trust browser-only auth for writes.
Headless CMS (build-time)
- CMS documents are not embed widgets. Widgets remain runtime islands; CMS owns SSG-rendered site content.
- Content API:
api/?action=cms.manifest|cms.routes|cms.collection|cms.entry|cms.singleton|cms.media. - Auth:
Authorization: Bearer dynostatic_cms_…bound to a website. No browserOriginrequired (CI has none). - Public API serves published snapshots only. Drafts stay admin-only until publish.
- Media: physical
media.php?id=ULID(thin gateway into the application). Never serve raw.upload.phpstorage. - Rebuild delivery: subscribe Integrations webhooks to
content.published(and related CMS events). CLI cron (bin/dynostatic cron) is the recommended path for timely delivery; the probabilistic web runner is best-effort only.
Composition invariants (acceptance bar)
After the spine rebuild, every web request must satisfy:
- One
SiteRepository, oneJobQueue, one cache facade per request (viaSharedKernel). - Admin site selection, roles, and audit go through AdminGate — not per-controller copies.
- Worker job kinds are registered by feature modules (
JobHandler); discussion/platform/CMS handlers live undersrc/Jobs/Handlers/andCmsWebhookFanoutHandler. - Gateway query maps and Router registrations share one route catalog (parity tested). Feature packages implement
AppModule(boot/routes/jobHandlers);Applicationis the orchestrator only. - Fresh installs have no legacy
users/projects/project_members/widget_comments/comment_reactions/legacy_admin_*tables. - Content API auth is O(1) lookup + rate-limited; scopes are enforced.
- PHPUnit green, including CMS publish conflict and AdminGate role coverage.
DiscussionKernelrequiresSharedKernel(no duplicate infra graphs).
Explicit non-goals
- Rewriting the discussion engine or ModuleRegistry catalog from scratch.
- Merging CMS entries into widgets (or the reverse).
- Introducing a DI container framework.
- Git-backed CMS storage or Keystatic Cloud CDN parity.