THE LIVING DOCUMENTATION

The Stryde Platform

One platform that is the UI container and control plane for many apps — it mounts their interfaces, secures them, observes them, configures them, and runs their whole lifecycle.

01 Overview

What Stryde is

An app on the platform is three things — a frontend the shell mounts, one or more backend microservices, and a manifest that declares how both plug in. The platform gives every app shared, governed capabilities, so none of them re-implement the basics.

UI container

One Expo (React Native + Web) shell mounts every app's micro-frontend. Web and native from one codebase.

Control plane

A FastAPI service is the registry, RBAC, lookups, i18n, error codes, and app-lifecycle brain.

Governed by default

Auth, telemetry, theming, i18n, lookups, errors and inter-app comms come from the SDK — not each app.

Single-tenant by design: multi-tenancy is a separate deployment of the whole platform, not tenant-scoped data inside one instance.

02 Architecture

How the pieces fit

The device runs the shell + SDK. Every backend call goes through the gateway, which load-balances across replicas and hands off to the control plane to mint an internal token. App backends trust only that token. Everything emits OpenTelemetry.

DeviceExpo shell (web + native) mounts micro-frontends@stryde/superapp-sdk Clerkhuman sign-in GatewayTraefik · routing + LBforward-auth Platform APIregistry · RBAC · lookupsi18n · errors · lifecyclemints internal token app A ×3 app B ×1 app C ×5 sandboxed (gVisor), behind gateway OTelCollector→ SigNoz /api/apps/{app} session forward-auth + internal token queries (user-centric)
Instance count is invisible — the frontend always calls one stable path; the gateway fans out across replicas.

Shell + SDK

Owns navigation, routing, app mounting, and the SDK runtime (auth, telemetry, theme, i18n, lookups, bus, errors).

Gateway

Traefik load-balances across replicas; forward-auth swaps the Clerk session for an internal token injected upstream.

Observability

OTel traces + metrics + logs → SigNoz, with user_id / session_id / app_id on every span.

03 Current Features

What's built today

The control plane and the deploy gate run and are tested. Everything else lives in Coming Soon.

CapabilityWhat it doesStatus
App registry & lifecycleregister → validate → deploy → enable/disable → rollbacklive
Validation gatemechanically enforces the app standards on every manifestlive
Lookups (type system)statuses/types as data, not enums; namespaced & cachedlive
i18n (locale-maps)EN + AR, RTL-ready, N-language storage, fallback chainlive
Error codesbackends emit codes; platform localizes themlive
RBAC modelorg → team → user, roles, permissions, assignmentslive
Shell + mountingfetches enabled-apps feed, mounts micro-frontendsscaffolded
Auth (Clerk + internal token)verify session, mint internal tokencoming
04 How it works

An app, in three parts

Each part deploys to a different place. The frontend ships to the device; the backend runs server-side behind the gateway; the manifest wires both and is the contract the platform validates.

Frontend bundleRN/Expo micro-frontendruns on the device, in the shellCDN (web) · OTA (native) Backend service(s)container, server-sidebehind the gateway, scaledFastAPI · gVisor manifest.jsonroutes, perms, events,i18n, lookups, errors, healththe contract the gate checks frontend + backend + manifest = one App
The three parts of an app. Each deploys to a different place; the manifest binds them.

Instance invisibility

Scaling a backend changes nothing the frontend can see — it always calls /api/apps/{app_key}; Traefik handles the replicas.

Inter-app communication

Apps emit/consume namespaced, versioned events through the SDK bus, and deep-link into each other via navigateToApp().

✦ Notification Center · SDK

One inbox for every app

The Notification Center is a platform capability, shipped in the SDK. Any app emits a notification through the platform with one call; the shell renders it for the recipient — a bell + drawer on every surface, and a full-screen page to manage them all. Informational messages are read/acknowledged; actionable ones capture a structured response (approve/reject, yes/no, single/multiple/custom choice, free text, file upload, comment, or a composite of these), plus comments and a full audit timeline.

The bell

In the shell's top nav on every surface, with a live unread badge. Mounted automatically — it's shell chrome, so apps never build their own. Quick triage.

The drawer

Click the bell for a glass drawer: grouped inbox, filter tabs (All / Unread / Action needed), detail view, and the response controls — without leaving the page.

The full page

The drawer's “expand” opens /notifications — a two-pane console (searchable list + detail) for managing everything, with deep-links (/notifications#id).

Emit a notification

One authenticated call (a service key or a user). Address it to one recipient or fan out to many. The initiating app (app_key) is attributed automatically for service callers.

POST /v1/notifications
{
  "user_id": 42,                      // recipient (or "recipients": [1,2,3])
  "app_key": "llm_manager",           // which app initiated (auto for service keys)
  "type": "llm_manager.budget.exceeded",
  "title": { "en": "Approve a budget increase", "ar": "..." },
  "body":  { "en": "GPT-4o crossed 90% of its monthly cap." },
  "category": "approval",             // notification.category lookup
  "priority": "high",                 // low | normal | high | urgent | critical
  "interaction": "approve_reject",    // the response UI to render
  "action_required": true,
  "config": { "require_rejection_reason": true },
  "due_at": "2026-06-10T17:00:00Z",
  "link": "/llm-manager"
}

Interaction types

Set interaction (+ a matching config) and the SDK renders the controls for you:

acknowledge · approve_reject · yes_no · single_choice · multiple_choice · custom_choice

text · file_upload · comment · composite · none (informational)

Choices live in config.choices [{id,title,description,recommended,risk}]; text takes config.max_length; composite takes config.components [{type,required}]. Governed fields (category / priority / interaction / status) are platform lookups — GET /v1/notifications/meta returns the live option lists.

Read, respond & manage

The recipient's surface uses GET /v1/notifications (inbox, filters incl. ?app_key=), /{id} (detail), POST /{id}/respond, /{id}/read, /read-all, /{id}/comments, /{id}/assign, /{id}/escalate, /{id}/cancel, and GET|PUT /v1/notifications/preferences. Every notification, response, comment and preference is also fully manageable from the Admin console (full CRUD + soft-delete + audit).

Open the Notification Center → SDK guide
05 Build an App

From scaffold to running

Apps use the mandated runtime — TypeScript on Expo for the frontend, FastAPI for the backend — and build against @stryde/superapp-sdk. You declare everything in the manifest; the platform wires it.

  1. Scaffold apps/<app_key>/

    Create manifest.json, frontend/ (the mount entry), and service/ (the backend). app_key namespaces everything.

  2. Adopt the design system — link both SDK sheets

    Link /sdk/stryde.css then /sdk/stryde-tokens.css (last) in your <head>, map your Tailwind colours to the SDK token names as HSL channels (bg-bg, text-ink, …), and build your surface with the .stryde-* classes + a .stryde-side side menu (no top nav — the shell owns it). That alone makes the app match the homepage. Download the kit and copy the starter scaffold from Downloads.

  3. Write the backend

    Expose /healthz + /readyz, a versioned API under /api/apps/<app_key>, trust only the internal token, and return code-based errors.

  4. Declare i18n, lookups & error codes

    Every user-facing key + error code, with full coverage for all active locales. Reference data goes in namespaced lookups, never hardcoded enums.

  5. Wire observability

    Initialize OTel; the SDK attaches the mandatory attributes automatically. Log through the SDK, not console.log.

Adopt the design system — the whole visual contract is two links + the .stryde-* classes:

<!-- app/layout.tsx <head> — tokens sheet LAST so the SDK wins -->
<link rel="stylesheet" href="/sdk/stryde.css?v=3"/>
<link rel="stylesheet" href="/sdk/stryde-tokens.css?v=3"/>

// Build with the canonical classes — they re-theme automatically:
<nav class="stryde-side"> … <a class="stryde-side-item active">Overview</a> </nav>
<span class="stryde-eyebrow">★ Section</span>
<h1 class="stryde-hero">Build it once. <span class="g">Look like Stryde.</span></h1>
<div class="stryde-card">…</div>
<button class="stryde-btn stryde-btn-primary">Primary →</button>

// manifest.json — declare it, or the gate (GATE.UI.DESIGN_SYSTEM) rejects you:
"frontend": { "design_system": "stryde@2",
  "stylesheets": ["/sdk/stryde.css", "/sdk/stryde-tokens.css"] }

Native/federated apps additionally receive the injected sdk (sdk.api, sdk.i18n.t(), OTel attributes) and use the @stryde/design-system primitives — see app-standards.md §6. For the look, the two sheets above are all you need.

06 The Manifest

The single source of wiring

The platform validates it on registration and stores it versioned — immutable once deployed. Full schema is in app-standards.md §3.

{
  "app_key": "invoicing",
  "name": { "en": "Invoicing", "ar": "..." },   // locale-map, not a string
  "version": "1.0.0",                          // semver, immutable once deployed
  "frontend": { "route": "/invoicing", "mount": "default",
                 "nav": { "label_key": "invoicing.nav.title" },
                 "budget": { "max_bundle_kb": 250 } },     // enforced
  "backends": [{ "api_base": "/api/apps/invoicing",
                 "health": { "liveness": "/healthz", "readiness": "/readyz" } }],
  "permissions": [{ "key": "app.invoicing.view" }],
  "observability": { "otel": true,
                 "mandatory_attributes": ["user_id","session_id","app_id","org_id","team_id"] }
}
07 The Validation Gate

Nothing deploys until it passes

Every manifest passes through an automated gate before it can deploy. A report with zero error-severity issues means pass. These checks are mechanical — the gate is the standard.

manifest.json+ frontend source schema · app_key · semver namespacing & collisions locale coverage (all locales) strict SDK usage · logging UI heritage · health · budget Gate PASS→ deployable FAIL→ blocked, reasons
Checks include the gates you asked for: strict SDK usage, lookups, locale coverage, logging, and UI heritage.
# dry-run any manifest → { "passed": true|false, "issues": [...] }
curl -X POST $API/v1/apps/validate -H 'Content-Type: application/json' --data @manifest.json
08 Deploy an App

The pipeline & lifecycle

Deployment is admin-console-driven and gated. The backend deploys to the orchestrator; the frontend ships as a bundle the shell mounts. Rollback is repointing the manifest at the previous version.

build publish register validate deploy enable rollback → previous version
The gate sits between register and deploy; nothing deploys without passing it.
draft validated deployed enabled disabled deprecated archived
enabled ⇄ disabled toggles from the admin console with no redeploy.
# the deploy loop, end to end
curl -X POST $API/v1/apps/register   --data @manifest.json   # runs the gate → "validated"
curl -X POST "$API/v1/apps/myapp/deploy?version=1.0.0"          # → "deployed"
curl -X POST $API/v1/apps/myapp/enable                        # → shows in the shell
curl -X POST "$API/v1/apps/myapp/rollback?version=0.9.0"        # instant rollback
09 What NOT to Deploy

The gate rejects these

Most of these are caught automatically — but build with them in mind so you never hit the wall.

Will be rejected by the gate

  • Hardcoded user-facing strings, or keys missing any active locale
  • Un-namespaced or colliding permissions / events / lookups / error codes
  • Direct fetch/axios, or no @stryde/superapp-sdk import (strict SDK)
  • Missing /healthz or /readyz, or a wrong api_base
  • OTel off or missing mandatory attributes; bundle over budget

Don't do it (policy / safety)

  • Secrets in the frontend bundle or a git-committed manifest
  • Translated error strings from the backend — emit codes only
  • Hardcoded colors/spacing or physical left/right (breaks theming & RTL)
  • Bypassing the gateway or trusting client-supplied identity/roles
  • Mutating a deployed manifest version (it's immutable — ship a new one)

A good app, in one line

  • Declares everything in its manifest, uses the SDK for every platform concern, localizes all text, emits codes + telemetry, stays in budget, and ships a new version to change anything.
10 References & Downloads

Everything you need

Get the SDK kit, then follow the README. Every link below is live — they download the real files the platform serves.

stryde-superapp-sdk.zipThe full SDK kit — both stylesheets, userbtn.js, the copy-me starter scaffold, the example manifest, app-standards.md, and a README with step-by-step instructions.
Download SDK
README.mdHow to use the SDK — link the sheets, map your tokens, build with .stryde-*, the side menu, the manifest contract.
Download
stryde.css + stryde-tokens.cssThe two stylesheets — the skin (brand/font/glow/components) and the surface palette + app-usable .stryde-* classes.
stryde.csstokens
starter scaffold + live proofA Next.js app pre-wired to the SDK (in the kit), and a page that links ONLY the SDK and renders the whole catalog — if it matches the homepage, your app will too.
Open proof
app-standards.md + manifest.example.jsonThe app contract (manifest schema + deploy-gate checklist) and a complete, gate-passing example manifest.
standardsmanifest
CHANGELOG.md + TypeScript typesWhat's new in stryde@2.2 (Notification Center, app_key attribution, S3 attachments, canonical top bar, app icon system, ?v=3 cache-bust) — and the .d.ts files for the full SdkContext, the skin helpers, and the notification emit contract.
changelogtypes

The SDK is design_system stryde@2. Link both sheets (tokens last), build with .stryde-* and a .stryde-side side menu, declare design_system + stylesheets in your manifest — the gate (GATE.UI.DESIGN_SYSTEM) rejects anything that doesn't.

11 Coming Soon

On the roadmap

Straight from the backlog. These are designed and specced — not yet wired.

soon Live shell on web + native

Wire the monorepo, boot Expo, render mounted apps in the browser and on device with OTA updates.

soon Auth & gateway

Clerk session → internal-token mint, service-to-service credentials, Traefik forward-auth, effective permissions.

soon Real orchestration

Deploy driver applies k3s manifests, health-gated rollout/rollback, image+bundle publish step.

soon Redis cache + pub/sub

Cross-instance cache coherence for lookups/permissions/theme — the must-fix for horizontal scale.

soon Configurable theming

Edit platform tokens live from the admin console; apps re-theme with no rebuild.

soon User-centric observability

Per-user activity timeline assembled from SigNoz — sessions, apps, traces, errors, latency.

soon Full admin console

App management, health, metrics, RBAC, lookups, i18n, error codes, theme, audit, notifications.

soon Phase-2 federation

Independent per-app frontend deploys via Module Federation (web) + Re.Pack (native).