Files
settled-reach/server/data/systems-schema.sql
T
jpmschweitzer 03e0d1c022 feat(simulation): brand layer schema and import pipeline (#827)
Adds the brand layer per D-189 §5:
- Schema: brand_products, brand_inputs, system_fiscal, corp_financial_state,
  corp_lifecycle_events (+ 5 indexes).
- Importer: reads wiki/economics/corporations/brands.toml, populates the
  new tables, validates V-B01–V-B05 structural rules, and derives
  system_fiscal for inhabited systems.
- Data: 8 brand_products, 16 brand_inputs, 301 system_fiscal rows.

Brand products are demand nodes — they consume commodities; they are not
commodities themselves (D-185). Depends on copy PR #127 for the corp
records referenced by brands.toml.
2026-04-14 17:24:51 +02:00

367 lines
16 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- Star Systems Database Schema — server/data/systems.db
-- Source of truth for all structured star system data.
-- Authored via tooling pipeline; wiki pages are generated views.
-- Shipped with the game — read-only from the server's perspective.
--
-- Rebuild: tooling/process-wiki-system-changes --rebuild-db
PRAGMA journal_mode=WAL;
PRAGMA foreign_keys=ON;
-- Core identity, physical character, political character
CREATE TABLE IF NOT EXISTS star_systems (
system_id TEXT PRIMARY KEY, -- GJ catalog number (e.g., "GJ 244A")
proper_name TEXT,
system_name TEXT,
star_type TEXT,
spectral_class TEXT,
dist_ly REAL,
geographic_sector TEXT,
geographic_band TEXT,
political_zone TEXT,
-- Physical character
habitable_planet_count INTEGER,
inhabited_planet_count INTEGER,
asteroid_belt INTEGER, -- boolean 0/1
gas_giant INTEGER, -- boolean 0/1
habitability_profile TEXT,
-- Political character
earth_alignment TEXT,
earth_proximity TEXT,
earth_tension TEXT,
-- Content notes
stability_index INTEGER,
system_volatility TEXT,
cultural_corridor TEXT,
generation_priority TEXT,
-- Economics (D-172)
currency_zone TEXT DEFAULT 'TRACTUS_PRIMARY', -- TRACTUS_PRIMARY | MARK_PRIMARY | MIXED
-- Energy-over-gate (D-186)
-- Gate Corp energy service: on-grid nodes get ~0.3× fusion_fuel utility demand.
-- MARK_PRIMARY zones default false (Compact refused Gate Corp dependency).
gate_energy_connected INTEGER DEFAULT 1, -- boolean 0/1
updated_at TEXT DEFAULT (datetime('now'))
);
-- Gate infrastructure — queried independently for pathfinding/topology
CREATE TABLE IF NOT EXISTS system_gates (
system_id TEXT PRIMARY KEY REFERENCES star_systems(system_id),
horizon_station INTEGER, -- boolean 0/1
aperture_count INTEGER,
gate_connections INTEGER,
gate_topology TEXT,
hop_distance_from_gateway INTEGER,
span_gate_network TEXT
);
-- Settlement history
CREATE TABLE IF NOT EXISTS system_history (
system_id TEXT PRIMARY KEY REFERENCES star_systems(system_id),
settlement_wave TEXT,
founding_motivation TEXT,
founding_culture_primary TEXT,
founding_culture_secondary TEXT,
cultural_persistence TEXT,
religious_status TEXT,
religious_generation_count INTEGER
);
-- Historical events — proper 1:N child table
CREATE TABLE IF NOT EXISTS historical_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
system_id TEXT NOT NULL REFERENCES star_systems(system_id),
event_type TEXT NOT NULL,
age_years INTEGER,
sort_order INTEGER NOT NULL DEFAULT 0 -- 0 = most recent
);
-- Economic life
CREATE TABLE IF NOT EXISTS system_economy (
system_id TEXT PRIMARY KEY REFERENCES star_systems(system_id),
economic_tier INTEGER,
population INTEGER,
economic_base_primary TEXT,
economic_base_secondary TEXT,
distribution_index TEXT,
imprint_access TEXT
);
-- Faction presence
CREATE TABLE IF NOT EXISTS system_factions (
system_id TEXT PRIMARY KEY REFERENCES star_systems(system_id),
governance_type TEXT,
dominant_faction TEXT,
primary_fault_line TEXT,
secondary_fault_line TEXT,
assembly_presence TEXT,
commission_presence TEXT,
syndic_presence TEXT,
syndic_type TEXT,
separatist_presence TEXT,
separatist_type TEXT,
institute_presence TEXT,
guardians_presence TEXT
);
-- Cultural voice
CREATE TABLE IF NOT EXISTS system_culture (
system_id TEXT PRIMARY KEY REFERENCES star_systems(system_id),
cultural_register TEXT,
cultural_register_secondary TEXT,
ambient_anxiety TEXT,
local_pride TEXT,
atmospheric_tone TEXT,
atmospheric_tone_secondary TEXT,
active_situation TEXT,
silence_threshold TEXT,
primary_archetype TEXT,
secondary_archetype TEXT,
narrative_notable INTEGER -- boolean 0/1
);
-- Authored prose (supply_dependency, faction_notes, silence_topic,
-- narrative_hook, calibration_note) lives in wiki markdown files only.
-- No DB mirror — read the file if you need the text.
-- Celestial bodies — planets, moons, gas giants, asteroid belts, oort clouds
-- Naming convention:
-- GJ-{n}b/c/d... — planets (innermost first)
-- GJ-{n}Ab/c/d... — planets orbiting primary (binary systems)
-- GJ-{n}d-1 — first moon of third planet
-- GJ-{n}-oort — oort cloud region
-- GJ-{n}-belt — asteroid belt
CREATE TABLE IF NOT EXISTS bodies (
body_id TEXT PRIMARY KEY,
system_id TEXT NOT NULL REFERENCES star_systems(system_id),
parent_body_id TEXT REFERENCES bodies(body_id), -- NULL for planets; parent planet for moons
-- Classification
body_type TEXT NOT NULL, -- planet, moon, gas_giant, asteroid_belt, oort_cloud
orbit_index INTEGER, -- innermost = 1 (planets around star, moons around planet)
proper_name TEXT, -- "Xin Chengdu", NULL for unnamed
-- Physical
mass_class TEXT, -- terrestrial, super_earth, ice_giant, gas_giant, dwarf
atmosphere TEXT, -- breathable, thin, toxic, none, dense
surface_gravity REAL, -- in g (Earth = 1.0), NULL for gas giants
orbital_period_days REAL, -- orbital period in Earth days, NULL for oort/belt
rotation_period_hours REAL, -- rotation period in Earth hours (Earth = 24), NULL for tidally locked/gas giants
planet_class TEXT, -- temperate, arid, frozen, oceanic, volcanic, barren, etc.
hydrosphere TEXT, -- ocean, ice, rivers, none, subsurface
-- Settlement
inhabited INTEGER NOT NULL DEFAULT 0,
population INTEGER DEFAULT 0,
economic_role TEXT, -- manufacturing, agricultural, extraction, research, transit
founding_age_years INTEGER,
settlement_pattern TEXT, -- urban_concentrated, dispersed_rural, orbital_only, domed, cave
-- Cultural (inherited from system, can override)
cultural_corridor TEXT, -- override system corridor if different
industrial_corridor TEXT, -- MVG, Gate_Corp, DSMC, Prometheus, Agricultural_Syndic
-- Rendering
terrain_reference TEXT, -- heightmap path when authored, NULL otherwise
screenshot_path TEXT, -- planetary shader screenshot path
updated_at TEXT DEFAULT (datetime('now'))
);
-- Stations and orbital facilities
-- Naming: GJ-{n}b-S1 (first station orbiting planet b), GJ-{n}-oort-S1 (horizon station)
CREATE TABLE IF NOT EXISTS stations (
station_id TEXT PRIMARY KEY,
system_id TEXT NOT NULL REFERENCES star_systems(system_id),
orbits_body_id TEXT REFERENCES bodies(body_id),
-- Classification
station_type TEXT NOT NULL, -- horizon, commercial, military, research, industrial, agricultural, transit
proper_name TEXT, -- "Chengdu Orbital", "Horizon Station"
-- Settlement
population INTEGER DEFAULT 0,
economic_role TEXT,
governance_type TEXT, -- can differ from system governance
-- Infrastructure
docking_class TEXT, -- major, standard, restricted, none
has_gate_infrastructure INTEGER DEFAULT 0,
district_count INTEGER DEFAULT 1,
updated_at TEXT DEFAULT (datetime('now'))
);
-- Corporations, combines, and major economic entities
-- Source: wiki/corporations/ pages (canonical)
CREATE TABLE IF NOT EXISTS corporations (
corp_id TEXT PRIMARY KEY, -- slug from wiki (e.g., "gate-corporation", "vethara")
proper_name TEXT NOT NULL, -- display name
corp_type TEXT NOT NULL, -- corporation, combine, syndic, institution, independent
scope TEXT, -- reach-wide, sector, system, local
headquarters_system TEXT REFERENCES star_systems(system_id),
headquarters_body TEXT, -- body_id or station_id
specialization TEXT, -- primary product/service
parent_corp TEXT REFERENCES corporations(corp_id),
notes TEXT,
-- Economics (D-175)
behavioral_archetype TEXT, -- Monopolist|Distributor|Producer|Specialist|Cooperative|Intermediary
supply_chain_role TEXT,
shadow_economy_access INTEGER DEFAULT 0,
updated_at TEXT DEFAULT (datetime('now'))
);
-- Gate adjacency graph — bidirectional edges from star-map.json (D-178)
-- Transport cost computation: 512% per hop (gate edge), 13% (orbital edge)
CREATE TABLE IF NOT EXISTS gate_links (
from_system_id TEXT NOT NULL REFERENCES star_systems(system_id),
to_system_id TEXT NOT NULL REFERENCES star_systems(system_id),
PRIMARY KEY (from_system_id, to_system_id)
);
-- Commodity catalog — 36 types (D-184)
-- Source: wiki/economics/commodities.toml
CREATE TABLE IF NOT EXISTS commodities (
commodity_id TEXT PRIMARY KEY,
name TEXT NOT NULL,
tier TEXT NOT NULL, -- raw|intermediate|final|service_professional|service_luxury
elasticity TEXT NOT NULL, -- perfectly_inelastic|inelastic|unit_elastic|elastic
base_price REAL NOT NULL,
bulk_class TEXT, -- bulk|liquid|perishable|standard|compact|precision|oversized|non_physical
unit TEXT, -- tonnes|units|contracts
production_ubiquity TEXT, -- ubiquitous|common|regional|concentrated|monopolistic
demand_model TEXT, -- market|utility|compliance
commission_certifiable INTEGER DEFAULT 0, -- subject to certification in TRACTUS_PRIMARY zones
compact_contested INTEGER DEFAULT 0,
shadow_viable INTEGER DEFAULT 0,
panic_threshold_weeks INTEGER DEFAULT 0,
description TEXT,
updated_at TEXT DEFAULT (datetime('now'))
);
-- Leontief production chain recipes (D-178)
-- Source: wiki/economics/production_chains.toml
CREATE TABLE IF NOT EXISTS production_chains (
chain_id TEXT PRIMARY KEY,
output_commodity_id TEXT NOT NULL REFERENCES commodities(commodity_id),
output_quantity REAL NOT NULL DEFAULT 1.0,
location_bound INTEGER DEFAULT 0,
description TEXT,
updated_at TEXT DEFAULT (datetime('now'))
);
-- Input requirements per production chain
CREATE TABLE IF NOT EXISTS chain_inputs (
chain_id TEXT NOT NULL REFERENCES production_chains(chain_id),
input_commodity_id TEXT NOT NULL REFERENCES commodities(commodity_id),
quantity REAL NOT NULL,
PRIMARY KEY (chain_id, input_commodity_id)
);
-- Corporation operating locations (D-175)
-- Populated by corporation assignment pipeline, not by initial import
CREATE TABLE IF NOT EXISTS corp_presence (
corp_id TEXT NOT NULL REFERENCES corporations(corp_id),
location_id TEXT NOT NULL, -- body_id or station_id
location_type TEXT NOT NULL, -- body|station
primary_operation TEXT,
updated_at TEXT DEFAULT (datetime('now')),
PRIMARY KEY (corp_id, location_id)
);
-- Brand layer (D-189) — administered-price layer above commodity tâtonnement.
-- Brands consume commodities as demand nodes; they are NOT commodities (D-185).
CREATE TABLE IF NOT EXISTS brand_products (
brand_product_id TEXT PRIMARY KEY,
corp_id TEXT NOT NULL REFERENCES corporations(corp_id),
product_name TEXT NOT NULL,
brand_category TEXT NOT NULL, -- terroir|heritage_craft|tech_premium|cultural|service_premium|commodity_branded|design_heritage|platform_catalogue
value_trajectory TEXT NOT NULL, -- appreciating|depreciating|timeless
scarcity_class TEXT NOT NULL, -- capped|constrained|scalable|unlimited
product_subcategory TEXT,
base_premium_multiplier REAL NOT NULL DEFAULT 1.0,
premium_floor REAL NOT NULL DEFAULT 0.0,
origin_system TEXT REFERENCES star_systems(system_id),
terroir_locked INTEGER NOT NULL DEFAULT 0, -- boolean: production bound to origin_system
currency_denomination TEXT NOT NULL DEFAULT 'tractus', -- tractus|mark|mixed|sol_adjacent
shadow_viable INTEGER NOT NULL DEFAULT 0, -- boolean: circulates in shadow economy
brand_tier TEXT NOT NULL, -- halo|volume
halo_brand_id TEXT REFERENCES brand_products(brand_product_id), -- NULL for halo tier
updated_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS brand_inputs (
brand_product_id TEXT NOT NULL REFERENCES brand_products(brand_product_id),
commodity_id TEXT NOT NULL REFERENCES commodities(commodity_id),
quantity REAL NOT NULL,
PRIMARY KEY (brand_product_id, commodity_id)
);
-- Fiscal parameters per star system (D-189 section 5 + section 6)
CREATE TABLE IF NOT EXISTS system_fiscal (
system_id TEXT PRIMARY KEY REFERENCES star_systems(system_id),
corp_tax_rate REAL NOT NULL DEFAULT 0.22, -- 0.01.0
collection_efficiency REAL NOT NULL DEFAULT 1.0, -- derived: 1.0 - shadow_intensity × 0.6
updated_at TEXT DEFAULT (datetime('now'))
);
-- Phase 2: passive corp health tracking (D-189 section 8)
CREATE TABLE IF NOT EXISTS corp_financial_state (
corp_id TEXT PRIMARY KEY REFERENCES corporations(corp_id),
health_metric REAL NOT NULL DEFAULT 1.0, -- 0.0 (distressed) to 1.0 (healthy)
updated_at TEXT DEFAULT (datetime('now'))
);
-- Phase 3 lifecycle state machine stub (D-189 section 8) — schema correct, not driven yet
CREATE TABLE IF NOT EXISTS corp_lifecycle_events (
event_id INTEGER PRIMARY KEY AUTOINCREMENT,
corp_id TEXT NOT NULL REFERENCES corporations(corp_id),
event_type TEXT NOT NULL, -- Founded|Growing|Active|Distressed|Acquired|Dissolved
event_tick INTEGER NOT NULL DEFAULT 0,
event_data TEXT, -- JSON blob for future lifecycle detail
created_at TEXT DEFAULT (datetime('now'))
);
-- Indexes
-- astronomical_id removed: system_id IS the GJ catalog number
CREATE INDEX IF NOT EXISTS idx_star_systems_sector ON star_systems(geographic_sector);
CREATE INDEX IF NOT EXISTS idx_star_systems_wave ON system_history(settlement_wave);
CREATE INDEX IF NOT EXISTS idx_star_systems_topology ON system_gates(gate_topology);
CREATE INDEX IF NOT EXISTS idx_star_systems_star_type ON star_systems(star_type);
CREATE INDEX IF NOT EXISTS idx_star_systems_volatility ON star_systems(system_volatility);
CREATE INDEX IF NOT EXISTS idx_historical_events_system ON historical_events(system_id);
CREATE INDEX IF NOT EXISTS idx_system_factions_dominant ON system_factions(dominant_faction);
CREATE INDEX IF NOT EXISTS idx_system_economy_tier ON system_economy(economic_tier);
CREATE INDEX IF NOT EXISTS idx_system_culture_archetype ON system_culture(primary_archetype);
CREATE INDEX IF NOT EXISTS idx_bodies_system ON bodies(system_id);
CREATE INDEX IF NOT EXISTS idx_bodies_parent ON bodies(parent_body_id);
CREATE INDEX IF NOT EXISTS idx_bodies_type ON bodies(body_type);
CREATE INDEX IF NOT EXISTS idx_bodies_inhabited ON bodies(inhabited);
CREATE INDEX IF NOT EXISTS idx_stations_system ON stations(system_id);
CREATE INDEX IF NOT EXISTS idx_stations_orbits ON stations(orbits_body_id);
CREATE INDEX IF NOT EXISTS idx_stations_type ON stations(station_type);
CREATE INDEX IF NOT EXISTS idx_corps_system ON corporations(headquarters_system);
CREATE INDEX IF NOT EXISTS idx_corps_type ON corporations(corp_type);
CREATE INDEX IF NOT EXISTS idx_star_systems_currency ON star_systems(currency_zone);
CREATE INDEX IF NOT EXISTS idx_gate_links_from ON gate_links(from_system_id);
CREATE INDEX IF NOT EXISTS idx_gate_links_to ON gate_links(to_system_id);
CREATE INDEX IF NOT EXISTS idx_commodities_tier ON commodities(tier);
CREATE INDEX IF NOT EXISTS idx_production_chains_output ON production_chains(output_commodity_id);
CREATE INDEX IF NOT EXISTS idx_chain_inputs_commodity ON chain_inputs(input_commodity_id);
CREATE INDEX IF NOT EXISTS idx_corp_presence_corp ON corp_presence(corp_id);
CREATE INDEX IF NOT EXISTS idx_corp_presence_location ON corp_presence(location_id);
-- Brand layer indexes (D-189 section 5 — composite for UI queries)
CREATE INDEX IF NOT EXISTS idx_brand_products_corp_category ON brand_products(corp_id, brand_category);
CREATE INDEX IF NOT EXISTS idx_brand_products_origin ON brand_products(origin_system);
CREATE INDEX IF NOT EXISTS idx_brand_products_tier ON brand_products(brand_tier);
CREATE INDEX IF NOT EXISTS idx_brand_inputs_commodity ON brand_inputs(commodity_id);
CREATE INDEX IF NOT EXISTS idx_corp_lifecycle_events_corp ON corp_lifecycle_events(corp_id);