Spaces:
Running
Running
Download sql/intel_schema.sql from Success-dev/venthrive-api: direct link, hf CLI and curl.
- Browser
- Download file 6.76 kB
-
https://huggingface.co/spaces/Success-dev/venthrive-api/resolve/main/sql/intel_schema.sql
- Command line
-
hf download hf://spaces/Success-dev/venthrive-api/sql/intel_schema.sql
-
curl -L -o intel_schema.sql https://huggingface.co/spaces/Success-dev/venthrive-api/resolve/main/sql/intel_schema.sql
6.76 kB
| -- Intel store: Phase 0 + Phase 1 of the predictive business-intelligence system | |
| -- (docs/blueprint/intelligence-system.md, ADR-0017..0021). | |
| -- | |
| -- Portable SQL: runs unchanged on SQLite (Phase 1, local — ADR-0020) and on | |
| -- Postgres/Supabase when the store moves. The price of that portability: | |
| -- timestamps are ISO-8601 UTC text, booleans are 0/1 integers, JSON is text, ids | |
| -- are generated in Python (no serial/uuid defaults). Revisit all three when the | |
| -- store moves to Postgres for good. | |
| -- | |
| -- Applied by `py -m intel.cli init` (idempotent — every statement is IF NOT EXISTS). | |
| -- ─── Gazetteer ────────────────────────────────────────────────────────────── | |
| -- Everything in the store is keyed by location, so this comes first. Ids are | |
| -- dotted paths: 'ng', 'ng.lagos', 'ng.lagos.ikeja'. State/LGA names are exactly | |
| -- the ones users pick in onboarding (data/nigeria-locations.ts → nigeria_locations.json). | |
| create table if not exists locations ( | |
| id text primary key, | |
| level text not null check (level in ('country', 'state', 'lga', 'town')), | |
| name text not null, | |
| parent_id text references locations(id), | |
| lat real, | |
| lon real, | |
| source text not null | |
| ); | |
| -- Normalised alternative names → location. Seeded from the gazetteer itself, | |
| -- boundary-file spellings, a short curated city list, and place-data localities | |
| -- (intel/locations.py). The seed of the Layer 5 search/geocoding service. | |
| create table if not exists location_aliases ( | |
| alias text not null, | |
| location_id text not null references locations(id), | |
| origin text not null, -- 'gazetteer' | 'boundary' | 'curated' | 'places' | |
| primary key (alias, location_id) | |
| ); | |
| -- ─── Layer 1: stale awareness ─────────────────────────────────────────────── | |
| -- One row per external source. "Stale" means late against the source's OWN | |
| -- cadence, and two dates are tracked because a fetch can succeed today and still | |
| -- return last quarter's numbers. | |
| create table if not exists sources ( | |
| id text primary key, | |
| family text not null, | |
| provider text not null, | |
| licence text not null, | |
| expected_cadence_hours integer not null, | |
| latency_hours integer not null default 0, -- how far behind "now" the newest data legitimately is | |
| last_attempt_at text, | |
| last_success_at text, | |
| latest_data_period text, -- newest period the source has given us | |
| last_error text | |
| ); | |
| -- Every layer reports "done" and the receiving layer acknowledges it. Layer 1 | |
| -- flags reports nobody received. | |
| create table if not exists handoffs ( | |
| id text primary key, | |
| run_id text not null, | |
| from_layer text not null, | |
| to_layer text not null, | |
| report text not null, -- JSON | |
| produced_at text not null, | |
| received_at text, | |
| received_by text | |
| ); | |
| create index if not exists handoffs_pending on handoffs (to_layer, received_at); | |
| -- ─── Layer 2: data stream ─────────────────────────────────────────────────── | |
| -- A stream is one metric from one source, stored at its NATIVE resolution | |
| -- (never copied down to finer locations — that would fake precision the models | |
| -- would then learn from). | |
| create table if not exists streams ( | |
| id text primary key, -- 'weather.precipitation_sum' | |
| family text not null, | |
| metric text not null, | |
| unit text not null, | |
| kind text not null check (kind in ('driver', 'indicator')), | |
| native_level text not null check (native_level in ('country', 'state', 'lga', 'town', 'point')), | |
| cadence text not null check (cadence in ('daily', 'weekly', 'monthly', 'quarterly', 'yearly', 'event')), | |
| source_id text not null references sources(id) | |
| ); | |
| -- Numeric time series. Observed history and forecasts share one table: | |
| -- history has is_forecast=0 and issued_at=''; each forecast run keeps its own | |
| -- rows (issued_at = run date) so forecast skill can be measured later. | |
| create table if not exists observations ( | |
| stream_id text not null references streams(id), | |
| location_id text not null references locations(id), | |
| period_start text not null, | |
| is_forecast integer not null default 0 check (is_forecast in (0, 1)), | |
| issued_at text not null default '', | |
| value real not null, | |
| ingested_at text not null, | |
| primary key (stream_id, location_id, period_start, is_forecast, issued_at) | |
| ); | |
| create index if not exists observations_loc on observations (location_id, stream_id, period_start); | |
| -- Things that happen rather than values that move: a policy enacted, a holiday, | |
| -- an incident, a project gazetted. Kept permanently — this is the history the | |
| -- correlation step and models learn from (unlike news_items, which expire from | |
| -- the user-facing feed). | |
| create table if not exists events ( | |
| id text primary key, | |
| family text not null, -- policy | weather | infrastructure | funding | security | calendar | other | |
| type text not null, -- e.g. 'public_holiday', 'religious_holiday', 'season', 'news' | |
| location_id text references locations(id), | |
| starts_on text not null, | |
| ends_on text, | |
| title text not null, | |
| detail text, | |
| is_estimate integer not null default 0 check (is_estimate in (0, 1)), | |
| source_id text not null references sources(id), | |
| source_ref text not null, -- natural key at the source, so re-ingest is idempotent | |
| ingested_at text not null, | |
| unique (source_id, source_ref) | |
| ); | |
| create index if not exists events_loc on events (location_id, starts_on); | |
| -- Points of interest. subsector is one of backend/news/subsectors.json, or null | |
| -- for a context place (worship, civic, landmark) — those still matter as | |
| -- footfall generators even though they aren't competitors. | |
| create table if not exists places ( | |
| id text primary key, -- Overture GERS id | |
| name text, | |
| category text, | |
| taxonomy text, | |
| subsector text, | |
| confidence real, | |
| operating_status text, | |
| lat real not null, | |
| lon real not null, | |
| location_id text references locations(id), -- the LGA it falls in | |
| locality text, | |
| source_id text not null references sources(id), | |
| release text not null | |
| ); | |
| create index if not exists places_loc on places (location_id, subsector); | |