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.
The map
Section titled “The map” ┌─────────────────────────────────────────────────────────────────────┐ │ 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.
The five repositories
Section titled “The five repositories”| Tier | Repository | Language | Role | Status |
|---|---|---|---|---|
| Display | demostatics-web | PHP 8.3 / Laravel 11 | Server of record. Blade UI, JSON /api/v1, identity, roles, bans, forum, polls, editorial, and the reports + database_items tables | Shipped |
| Mobile client | demostatics-mobile_application | TypeScript / Expo / React Native | Real client of /api/v1. Reads and writes the same database as the web app. Computes nothing | Shipped |
| Desktop client | demostatics-pc_application | Rust (20 workspace members) | Thick subscriber client. All statistics, forecasting and simulation run locally | Shipped, but pointed at its own in-repo examples/mock-stream-server, not at Demostatics |
| Worker | demostatics-backend | none | Gather, process, structure and store the world data every other tier assumes | Not built |
| Docs | demostatics-docs | Markdown / Astro / Starlight | This site | Shipped |
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.
Who is the server of record
Section titled “Who is the server of record”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.php—user,moderator,admin,technical_staff,editor— enforced throughspatie/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.
reportsanddatabase_items, defined indemostatics-web/database/migrations/.
It presents two faces over one database and one set of policies:
| Face | Entry point | Auth | Consumers |
|---|---|---|---|
| Blade UI | demostatics-web/routes/web.php | Session cookie, ['auth','verified'] middleware | Browsers |
| JSON API v1 | demostatics-web/routes/api.php | Sanctum bearer token, ['auth:sanctum','api.banned','api.presence'], with api.verified on the nested writes-plus-data group | The 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.
Which tier computes what
Section titled “Which tier computes what”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 clients
Section titled “The clients”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.
The journey of one value
Section titled “The journey of one value”This is what a single measured value’s path is supposed to be, end to end, with each step marked honestly.
- A source emits an observation — a satellite pass, a mapping API, a news feed. Not built. No source is integrated anywhere.
- A worker node ingests it and normalizes the raw input. Not built.
- ML/LLM workers classify and contextualize it into the platform’s meta-descriptive dimensions. Not built.
- The worker writes it to the display tier as a
reportsordatabase_itemsrow. Not built. There is no ingest endpoint inroutes/api.php, no scoped ingest ability, and no worker credential in use. This is the break in the chain. - 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 areReportSeederandDatabaseItemSeeder. - A user filters the listing by region → subregion → country → state → city and by
category → subcategory. Shipped on both faces:
/databaseand/reportsin Blade,GET /api/v1/database-itemsandGET /api/v1/reportsin JSON. The geo dropdowns are populated from the external world store. - The value is displayed. Partial.
database_items.valueis astringcolumn holding a display string, with one nullablemeasured_atand no history table. It is never cast to a number, which is why nothing in the product charts it. - 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 theexport_limitsetting. - 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_itemsrow. 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.
External dependencies
Section titled “External dependencies”Real today
Section titled “Real today”| Dependency | What it is | How it is used | Status |
|---|---|---|---|
| World geo store | The dr5hn countries-states-cities dataset, loaded into an external store | Read-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 500 | Shipped |
| Outbound mail | Laravel’s mailer | Email verification and password reset. Nothing else | Shipped |
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 dependency | Intended role |
|---|---|
| Satellite observation | Raw imagery and observation input |
| Google Maps, Yandex, Baidu APIs | Mapping and traffic data |
| ISO datasets | Standardized reference data |
| News networks | Worldwide local news capture |
| Social media platforms | Open-web and social signal capture |
Deliberately not integrated
Section titled “Deliberately not integrated”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.