Skip to content

System Map

Demostatics is four tiers spread over five repositories. Three of the tiers run; one of them does not exist. This page is the single place where the whole shape is drawn honestly, including the edges that are missing.

┌─────────────────────────────────────────────────────────────────────┐
│ WORKER TIER [ NOT BUILT ] │
│ demostatics-backend — one README.md, two lines, zero source files │
└──────────────────────────────┬──────────────────────────────────────┘
writes rows into `reports` ╎ and `database_items`
NO CODE ON THIS EDGE: no ingest route, no worker credential, no
producer of any kind. Both tables are filled only by local seeders.
┌─────────────────────────────────────────────────────────────────────┐
│ DISPLAY TIER — demostatics-web (Laravel 11, PHP 8.3) [ SHIPPED ] │
│ Server of record · sole identity authority · one database │
│ │
│ routes/web.php ──► Blade UI (session cookie auth) │
│ routes/api.php ──► JSON /api/v1 (Sanctum bearer token) │
└───┬────────────────────────┬──────────────────────────────┬─────────┘
│ │ │
│ SELECT on `world.*` │ HTTPS + JSON │ SMTP
│ read-only, degrades │ Authorization: Bearer … │ verification
│ to empty when down │ reads and writes │ + reset mail
▼ ▼ ▼
┌──────────────────┐ ┌────────────────────────┐ ┌────────────────────┐
│ world geo store │ │ MOBILE CLIENT │ │ outbound mail │
│ dr5hn dataset │ │ demostatics-mobile_… │ │ Laravel mailer │
│ external, r/o │ │ Expo / React Native │ │ `log` by default │
│ [ SHIPPED ] │ │ [ SHIPPED ] │ │ [ SHIPPED ] │
└──────────────────┘ └────────────────────────┘ └────────────────────┘
══════ nothing below this line touches anything above it ══════
┌────────────────────────┐ ┌────────────────────────────┐
│ DESKTOP CLIENT │ wss /v1/stream │ examples/mock-stream-server│
│ demostatics-pc_appl… │────────────────►│ same Rust repo, loopback │
│ Rust · thick client │ auth + subscribe│ synthetic generated ticks │
│ all statistics local │◄────────────────│ │
│ [ SHIPPED ] │ Snapshot/Delta │ [ SHIPPED, but a mock ] │
└───────────┬────────────┘ └────────────────────────────┘
╎ contract v0.2 expects a REAL server on this edge:
╎ /v1/auth/login, /v1/auth/refresh, wss://…/v1/stream,
╎ signed JWT claims, entitlement-gated topics
▼ [ NOT BUILT ]
no such server exists in any of the five repositories,
and demostatics-web serves none of those paths
┌────────────────────────┐
│ DOCS SITE — this site │ Astro + Starlight, static output.
│ demostatics-docs │ No client code, no API calls, no runtime.
│ [ SHIPPED ] │ Connected to nothing.
└────────────────────────┘

The disconnected desktop edge is not a drawing mistake. A case-insensitive search for api/v1, sanctum or laravel across the whole demostatics-pc_application tree (excluding build output) matches zero files. The desktop client has never been pointed at the Laravel server. See The Two Contracts.

TierRepositoryLanguageRoleStatus
Displaydemostatics-webPHP 8.3 / Laravel 11Server of record. Blade UI, JSON /api/v1, identity, roles, bans, forum, polls, editorial, and the reports + database_items tablesShipped
Mobile clientdemostatics-mobile_applicationTypeScript / Expo / React NativeReal client of /api/v1. Reads and writes the same database as the web app. Computes nothingShipped
Desktop clientdemostatics-pc_applicationRust (20 workspace members)Thick subscriber client. All statistics, forecasting and simulation run locallyShipped, but pointed at its own in-repo examples/mock-stream-server, not at Demostatics
Workerdemostatics-backendnoneGather, process, structure and store the world data every other tier assumesNot built
Docsdemostatics-docsMarkdown / Astro / StarlightThis siteShipped

The worker row is the single most important fact about the platform’s state. Every other document on this site describes itself in terms of a tier that has no code. See Worker Tier.

demostatics-web is the only implemented server in the platform and the only identity authority. There is no second server anywhere.

It owns:

  • Users, roles and bans. Registration, login, password reset, email verification, and the five roles in app/Models/UserRole.phpuser, moderator, admin, technical_staff, editor — enforced through spatie/laravel-permission.
  • The forum and polls. Posts, threaded comments, communities, poll options, votes.
  • Editorial content. Editorial articles, About Us articles, the moderation board.
  • The two data tables. reports and database_items, defined in demostatics-web/database/migrations/.

It presents two faces over one database and one set of policies:

FaceEntry pointAuthConsumers
Blade UIdemostatics-web/routes/web.phpSession cookie, ['auth','verified'] middlewareBrowsers
JSON API v1demostatics-web/routes/api.phpSanctum bearer token, ['auth:sanctum','api.banned','api.presence'], with api.verified on the nested writes-plus-data groupThe mobile app

The access tiers mirror each other deliberately: public reads for forum, polls, editorial and geo; authenticated for account operations; verified email for every write plus Reports and Database. A post created on the phone appears on the web forum immediately because it is the same row in the same table. See Web — Display Tier, Mobile — Expo Client and JSON API v1.

The display tier’s own README states that this repository “does not gather or process anything”. That line needs to be drawn precisely, because two planned features sit right on top of it. The distinction below is reproduced from demostatics-mobile_application/docs/roadmap.md §4a.

Request-scoped arithmetic belongs in Laravel

Section titled “Request-scoped arithmetic belongs in Laravel”

One user asks a question and the server answers it from current state: a quote from current rates, a page of results, a vote tally, an export. This is display-tier work and it must be server-computed and server-authoritative.

The transaction calculator named in the roadmap is exactly this shape. A phone that works out fees from a cached rate shows a number you did not charge and leaves no audit trail, so the rates must be versioned and the quote must carry an id and an expiry binding the price shown to the price executed. That feature is Planned — no such endpoint exists today.

Continuous processing over the dataset belongs to the worker tier

Section titled “Continuous processing over the dataset belongs to the worker tier”

Evaluating threshold rules across every series on a schedule, and computing rollups, are pipeline work, not request work. Putting them in Laravel would quietly turn the display tier into a compute tier, and it would split “when did this cross a line” away from the forecasting that answers “what happens next”.

So the division is: Laravel stores alert rules, serves them, and notifies; the worker decides when one fires. Both halves are Planned; neither exists.

The desktop client keeps doing the heavy statistics, forecasts and simulation locally — that is the whole premise of a thick client, and ds-analytics, ds-charts, ds-graph and ds-compute are real crates that do it. The phone never attempts any of it; it renders what it is given. See Desktop — PC Client.

This is what a single measured value’s path is supposed to be, end to end, with each step marked honestly.

  1. A source emits an observation — a satellite pass, a mapping API, a news feed. Not built. No source is integrated anywhere.
  2. A worker node ingests it and normalizes the raw input. Not built.
  3. ML/LLM workers classify and contextualize it into the platform’s meta-descriptive dimensions. Not built.
  4. The worker writes it to the display tier as a reports or database_items row. Not built. There is no ingest endpoint in routes/api.php, no scoped ingest ability, and no worker credential in use. This is the break in the chain.
  5. The row sits in the Laravel database. Shipped — the tables exist, are indexed on (region_id, country_id), (category_id, subcategory_id) and the timestamp, and are queryable today. Their only current writers are ReportSeeder and DatabaseItemSeeder.
  6. A user filters the listing by region → subregion → country → state → city and by category → subcategory. Shipped on both faces: /database and /reports in Blade, GET /api/v1/database-items and GET /api/v1/reports in JSON. The geo dropdowns are populated from the external world store.
  7. The value is displayed. Partial. database_items.value is a string column holding a display string, with one nullable measured_at and no history table. It is never cast to a number, which is why nothing in the product charts it.
  8. The user exports it. Shipped for Reports only — xlsx, csv, json and a Word-openable doc, via demostatics-web/app/Support/ReportExporter.php, capped by the export_limit setting.
  9. A client computes on it. Not built as drawn. The desktop client does compute, but on ticks from its own mock server; it never sees a database_items row. The phone does not compute at all.

Steps 1 through 4 are the entire acquisition half of the platform, and none of it exists. See Data Pipeline.

DependencyWhat it isHow it is usedStatus
World geo storeThe dr5hn countries-states-cities dataset, loaded into an external storeRead-only, through schema-qualified names (world.regions, world.countries, …) on the same connection as the app — there is no separate world connection. Every accessor in demostatics-web/app/Support/GeoData.php degrades to an empty collection on a connection or missing-table error, so a missing store yields empty dropdowns rather than a 500Shipped
Outbound mailLaravel’s mailerEmail verification and password reset. Nothing elseShipped

Both are visible from GET /api/v1/health, which reports world_store reachability, can_register (false whenever MAIL_MAILER is log or array, because unverified accounts cannot reach Reports or Database) and whether the queue needs a supervised worker.

Named in the founding documents, integrated nowhere

Section titled “Named in the founding documents, integrated nowhere”

Every item below is Planned. No client, credential, SDK, config key or HTTP call for any of them appears in any of the five repositories.

Named dependencyIntended role
Satellite observationRaw imagery and observation input
Google Maps, Yandex, Baidu APIsMapping and traffic data
ISO datasetsStandardized reference data
News networksWorldwide local news capture
Social media platformsOpen-web and social signal capture

Two absences are worth stating so nobody spends a day looking for them.

Mobile and desktop do not know about each other. There is no pairing flow, no shared session, no shared account handoff, and no shared dataset identifier namespace. They do not even share a data shape: the phone reads "48,210 MW" as a display string from database_items, while the desktop consumes numeric MetricTick values over a stream. “Connect the phone to the PC application” is not a pairing feature first — it is a contract decision first.

This docs site has no client code. demostatics-docs is Markdown compiled to static HTML by Astro and Starlight. It makes no API calls, has no runtime backend, holds no credentials, and reads nothing from any other tier. It can be wrong about the system without the system noticing. See Docs Site.