Galaxy / Region / Cluster / Zone / Sector / WarpTunnel¶
Status: 🚧 Partial — Galaxy/Cluster/Zone/Sector/WarpTunnel/SectorCelestial model layer is committed; design-only items confirmed absent (is_latent on warps, ANOMALY sector type, message_beacons, is_outlaw_zone … · ⚠︎ contains code↔spec divergence (impl audit 2026-06-16)
The spatial hierarchy. Region is the unified ownership unit. Regions contain Clusters (thematic groupings) and Zones (security/policing slices). A Sector belongs to exactly one Cluster and at most one Zone.
Galaxy (singleton metadata)
└─ Region (Central Nexus | Terran Space | Player-owned)
├─ Cluster (navigation/thematic)
│ └─ Sector
└─ Zone (security: EXPANSE/FEDERATION/BORDER/FRONTIER)
└─ Sector (also belongs to a Cluster)
Schema status¶
Per ADR-0066 D-V1, schema-level implementation status is consolidated here. Field descriptions describe the target schema.
Design-only columns — present in the spec, not yet committed:
Region: tier-headroom widening oftotal_sectorsupper bound,nebula_properties.Sector:ANOMALYenum value ontype;x_coord/y_coord/z_coordQuantum-Jump bearing-projection use;is_nexus_protected,message_beacons,is_outlaw_zone,is_npc_barracks_sector.sector_warps,WarpTunnel:is_latentflag (per ADR-0034).WarpTunnel: Quantum-Jumpconstruction_costfield.
All other columns on this page are committed.
Galaxy¶
Source: services/gameserver/src/models/galaxy.py
Purpose: Singleton metadata + global statistics container. Subdivision happens at the Region level.
Fields:
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| name | String(100) | not null | |
| statistics | JSONB | not null | counts: total_sectors, discovered_sectors, station_count, planet_count, player_count, team_count, warp_tunnel_count, genesis_count |
| density | JSONB | not null | station_density %, planet_density %, one_way_warp_percentage, resource_distribution map |
| faction_influence | JSONB | not null | per-faction influence numbers |
| state | JSONB | not null | age_in_days, resource_depletion, economic_health, exploration_percentage, player_wealth_distribution |
| events | JSONB | not null | active_events / scheduled_events arrays (sector-scoped phenomena: spacetime anomalies, warp storms — see SYSTEMS/sector-presence.md) |
| max_sectors | Integer | nullable | Soft observability target, not enforced. Per SK23 in ADR-0050, the galaxy has no hard sector cap — it grows organically as paying subscribers buy regions. Operator dashboards can alert at thresholds for capacity planning. Per-region cap lives on Region.total_sectors (CHECK 100–1500). |
| resources_regenerate | Boolean | default true | |
| default_turns_per_day | Integer | default 1000 | |
| combat_penalties | JSONB | not null | per-zone-type penalty levels (federation/border/frontier) |
| economic_modifiers | JSONB | not null | |
| hidden_sectors | Integer | default 5 | |
| special_features | ARRAY(String) | default [] |
Relationships: none directly modeled on Galaxy; aggregates are populated from related entities via update_statistics(). Region is the ownership/cascade root for sectors.
Region¶
Source: services/gameserver/src/models/region.py
Purpose: Owned territory unit. Three kinds: Central Nexus (5000 sectors, the universal hub), Terran Space (the operator-run vanilla starter region that ships at universe creation), and player-owned (subscription-purchased regions, sized by tier; Standard tier targets ~1000 sectors with ±20% variability — see ../OPERATIONS/multi-regional.md). Player regions attach to the Central Nexus when provisioned, like petals on a flower.
Sectors are identified by a compound key (Region.id, Cluster.id, Sector.sector_number). Sector numbers are scoped to the region, not globally unique — Region A's sector 47 and Region B's sector 47 are distinct sectors with no relationship to each other. The compound tuple is what guarantees universe-wide identity.
Fields:
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| name | String(255) | unique | machine name |
| display_name | String(255) | not null | |
| region_type | String(50) | default player_owned |
enum-like: central_nexus / terran_space / player_owned |
| owner_id | UUID FK users.id | nullable | null for special regions |
| subscription_tier | String(50) | default standard |
|
| paypal_subscription_id, subscription_status, subscription_started_at, subscription_expires_at, last_payment_at, next_billing_at | mixed | nullable | PayPal billing trail |
| status | String(50) | default active |
pending / active / suspended / grace / terminated / generation_corrupt / attachment_pending — extended per ADR-0050. State transitions documented in ../SYSTEMS/region-lifecycle.md. |
| suspended_at | DateTime | nullable | Set on transition to suspended (payment failure event). Cleared on takeover or payment recovery. Per ADR-0050. |
| terminated_at | DateTime | nullable | Set on transition to terminated (30 days suspended, no payment recovery, no takeover). |
| scheduled_hard_delete_at | DateTime | nullable | terminated_at + 7 days; cleanup orchestrator targets this for the final region row + content hard-delete via CASCADE. |
| generation_seed | BigInteger | not null | The seed used at Phase 0 input validation. Required for ops repro and bang-side reproducibility. Per SK19 in ADR-0050. |
| generation_phase_checksums | JSONB | default {} |
Per-phase row-count sentinels committed at each phase boundary; restart re-verifies counts before advancing. Schema: {phase_N: {row_count, duration_ms, completed_at}} per phase 1–14. Per SK17 in ADR-0050. |
| governance_type | String(50) | default autocracy |
autocracy/democracy/council |
| voting_threshold | DECIMAL(3,2) | default 0.51, 0.1–0.9 | check constraint |
| election_frequency_days | Integer | default 90, 30–365 | check constraint |
| constitutional_text | Text | nullable | |
| tax_rate | DECIMAL(5,4) | default 0.10, 0.0–0.25 | check constraint (zero permitted for tax-haven regional governance) |
| trade_bonuses | JSONB | default {} | per-resource multipliers |
| economic_specialization | String(50) | nullable | |
| starting_credits | Integer | default 1000, ≥100 | |
| starting_ship | String(50) | default scout |
|
| language_pack, aesthetic_theme, traditions, social_hierarchy | JSONB | default {} | cultural identity |
| nexus_warp_sector | Integer | nullable | Frontier-zone sector hosting the bidirectional natural warp to the Central Nexus, per ADR-0043. The warp is is_latent = true; per-player visibility lives in player_warp_knowledge per ADR-0045. Null for Central Nexus and Terran Space. |
| total_sectors | Integer | default 1000, CHECK 100–1,500 | sized by subscription_tier for player regions; fixed for central_nexus (5000) and terran_space (300). Standard tier 800–1,200 (±20% from 1,000); higher tiers widen the upper bound — schema CHECK 100–1,500 accommodates Standard plus tier headroom. |
| capital_sector_number | Integer | not null | The region-local sector_number of the Capital Sector (welcome hub, population-hub planet host, only place pioneer migration contracts can be secured). Randomly placed inside the Federation Zone of player regions. Fixed at sector 1 for Terran Space; canonically anchored in the Gateway Plaza cluster of the Central Nexus. See ../SYSTEMS/galaxy-generation.md#step-8-capital-sector. |
| active_players_30d, total_trade_volume | counts | default 0 | |
| pirate_ecosystem_state | JSONB | default {} |
Cached ecosystem snapshot per ADR-0048. Formal shape per ADR-0065 R-I5: {current_population_score: int, current_target: int, suppression_modifier: float (0.20..1.0), kill_weight_last_30_days: float, zero_population_since: iso8601 or null, cleansed_at: iso8601 or null, last_growth_tick_at: iso8601, last_evolution_tick_at: iso8601, evolutions_since_creation: int}. Updated by the weekly tick service. Authoritative source remains the live PirateHolding and PirateKillLog tables; this column is the fast-path read cache. |
Relationships:
- owner → User (FK owner_id).
- memberships → RegionalMembership (1:many, cascade delete).
- zones / clusters / sectors / planets / stations (1:many).
- elections, policies, treaties_as_a, treaties_as_b for governance/diplomacy.
Cluster¶
Source: services/gameserver/src/models/cluster.py
Purpose: Thematic grouping of sectors inside a Region (resource-rich, trade hub, frontier outpost, etc.).
Fields:
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| name | String(100) | not null, UNIQUE per (region_id, name) |
AI-generated at bang time per ADR-0044; names are unique within a region (two regions may each have a "Commerce Central"). |
| region_id | UUID FK regions.id | not null, CASCADE | |
| type | Enum cluster_type |
not null | STANDARD, RESOURCE_RICH, POPULATION_CENTER, TRADE_HUB, MILITARY_ZONE, FRONTIER_OUTPOST, CONTESTED, SPECIAL_INTEREST |
| sector_count | Integer | default 0 | |
| is_discovered | Boolean | default true | |
| discovery_requirement | JSONB | nullable | gates discovery |
| stats | JSONB | not null | total_sectors, populated_sectors, resource_value, danger_level, development_index, exploration_percentage |
| resource_modifiers | JSONB | default {} | |
| economic_focus | ARRAY(String) | default [] | |
| resources | JSONB | not null | primary_resources, resource_distribution, special_resources |
| economic_value | Integer | default 50 | 0-100 |
| controlling_faction | String | nullable | null = contested |
| faction_influence | JSONB | not null | per-faction numbers + dominant_faction |
| nav_hazards | ARRAY(String) | default [] | |
| recommended_ship_class | String | default light_freighter |
|
| x_coord, y_coord, z_coord | Integer | default 0 | |
| special_features | ARRAY(String) | default [] | |
| is_hidden | Boolean | default false | |
| warp_stability | Float | default 1.0 | |
| nebula_properties | JSONB | nullable | nebula_type (Crimson/Azure/Emerald/Violet/Amber/Obsidian), color_hex (canonical galaxy-map render colors per ../FEATURES/galaxy/quantum-resources.md#nebula-types-and-field-strengths — Crimson #DC143C, Azure #1E90FF, Emerald #00FF7F, Violet #9370DB, Amber #FF8C00, Obsidian #2F4F4F), quantum_field_strength (0–100), shard_yield_band, secondary_effect, coverage_pct. Set when the cluster overlaps a nebula; null otherwise. |
Relationships:
- region → Region (FK).
- sectors → Sector (1:many, cascade delete).
Zone¶
Source: services/gameserver/src/models/zone.py
Purpose: Security/policing slice of a Region defined by a sector-number range. Independent of cluster organization; orthogonal dimension.
Fields:
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| region_id | UUID FK regions.id | not null, CASCADE, indexed | |
| name | String(200) | not null | e.g., "The Expanse", "Federation Space" |
| zone_type | Enum zone_type |
not null | EXPANSE, FEDERATION, BORDER, FRONTIER |
| start_sector | Integer | not null, ≥1 | check constraint |
| end_sector | Integer | not null, ≥ start_sector | check constraint |
| policing_level | Integer | default 5, 0–10 | check constraint |
| danger_rating | Integer | default 5, 0–10 | check constraint |
Relationships:
- region → Region.
- sectors → Sector (1:many, cascade delete).
Sector¶
Source: services/gameserver/src/models/sector.py
Purpose: A discrete navigable space; the basic location unit for ships, planets, stations, drones, and combat.
Fields:
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | global UUID; used internally for FKs |
| sector_number | Integer | not null, part of composite UNIQUE (region_id, sector_number) |
region-scoped human-readable sector number; Region A's sector 47 and Region B's sector 47 are distinct. The compound key (region_id, cluster_id, sector_number) is the canonical identifier surfaced in UI and APIs (per ADR-0005). |
| name | String(100) | not null | |
| region_id | UUID FK regions.id | not null, CASCADE | |
| cluster_id | UUID FK clusters.id | not null, CASCADE | |
| zone_id | UUID FK zones.id | nullable, SET NULL, indexed | |
| type | Enum sector_type |
default STANDARD | STANDARD/NEBULA/ASTEROID_FIELD/BLACK_HOLE/RADIATION_ZONE/WARP_STORM/ANOMALY (ANOMALY is the spatial-oddity sector type with investigation-driven Quantum Shard / Lumen Crystal drops per ../FEATURES/galaxy/quantum-resources.md#2-anomaly-investigation-secondary; ~1–2% of generated sectors across all zones) |
| security_level, development_level, traffic_level | Integer | default 5/1/1 | 1-10 |
| is_discovered | Boolean | default true | |
| discovered_by_id | UUID FK players.id | nullable | |
| discovery_date | DateTime | nullable | |
| x_coord, y_coord, z_coord | Integer | not null | 3D coordinates inside the parent region's coordinate frame. These integers are the basis for Quantum Jump bearing projection: the Phase 1 long-range scan cone and the Phase 3 arrival resolver both use true Euclidean distance computed from (x_coord, y_coord, z_coord) to project a bearing vector and select destination candidates within an accuracy radius (see ../FEATURES/galaxy/sectors.md#quantum-jump-warp-jumper). |
| radiation_level | Float | default 0.0 | |
| hazard_level | Integer | default 0 | 0-10 |
| resources | JSONB | not null | has_asteroids, asteroid_yield (ore/precious_metals/radioactives), gas_clouds, has_scanned |
| resource_regeneration | Float | default 1.0 | |
| players_present | JSONB | default [] | live presence list |
| ships_present | JSONB | default [] | |
| defenses | JSONB | not null | defense_drones, owner_id, owner_name, team_id, mines, mine_owner_id (player-controlled); patrol_ships (NPC-only — Federation patrols, faction-territory enforcement, pirate raid groups) |
| controlling_faction | String | nullable | |
| controlling_team_id | UUID FK teams.id | nullable | |
| last_combat | DateTime | nullable | |
| active_events, special_features, nav_hazards, nav_beacons | JSONB / ARRAY | defaults | |
| description | String | nullable | |
| is_nexus_protected | Boolean | default false | When true, the sector is part of the Nexus Sentinel Corps protected-sector set. Warp-gate Phase 1 deploy-beacon attempts in this sector are rejected with ERR_NEXUS_PROTECTED_SECTOR, and a Sentinel squad spawns and intercepts on attempted bypass. The galaxy generator's Phase 12.5b sets this on the Nexus Capital sector (2251) and all Gateway Plaza cluster sectors (2251–2500); operator-tunable for other Nexus clusters. See ../FEATURES/gameplay/police-forces.md. |
| message_beacons | JSONB | default [] |
Denormalized array of player-deployed message-beacon summaries (id, deployer_nickname, deployed_at, message preview, expiry) for fast sector-view reads. The canonical MessageBeacon rows live in their own table; this JSONB is a denormalized read-fast cache updated on deploy / salvage / expiry. See ../FEATURES/gameplay/message-beacons.md. |
| is_outlaw_zone | Boolean | default false | When true, the sector hosts an OutlawBase for hostile-faction NPCs (pirates, Cabal). Player warp-gate construction is rejected in outlaw zones (a backstop similar to is_nexus_protected). See ./npc-lodging.md. |
| is_npc_barracks_sector | Boolean | default false | Set when an NPCBarracks row's location_type = sector and points at this sector (e.g., the dedicated Sentinel barracks sector in Gateway Plaza). Surfaces in player-info UI as "this is a Sentinel barracks sector." |
Relationships:
- cluster (FK), zone (FK), region (FK).
- planets, stations (1:many, cascade delete).
- ships via Ship.sector_id (note: integer FK by sector_id, not UUID).
- discovered_by → Player, controlling_team → Team.
- deployed_drones → Drone, drone_deployments → DroneDeployment, fleets → Fleet.
- outgoing_warps / incoming_warps (many-to-many via sector_warps).
- warp_tunnels_origin, warp_tunnels_destination → WarpTunnel (1:many each direction).
sector_warps (association table)¶
Cheap point-to-point warp links — the heavier WarpTunnel is a separate concept with its own metadata. Carries the local-graph one-ways that natural worldgen and certain formations stamp (BACKDOOR, the local end of ESCAPE_HATCH, WARP_SINK).
| name | type | constraints | notes |
|---|---|---|---|
| source_sector_id | UUID FK sectors.id | PK part 1 | |
| destination_sector_id | UUID FK sectors.id | PK part 2 | |
| is_bidirectional | Boolean | default true | false flags this row as a one-way link from source → destination. Per ADR-0034, directionality lives only on this column — never on a type enum. |
| is_latent | Boolean | default false | true means the warp looks bidirectional in the raw sector view until revealed by a Warp Jumper's existing scan suite (Quantum Jump scan). ~20% of one-ways are latent; ~80% are marked (visible directional glyph in the player UI). — see ADR-0034 and ../FEATURES/galaxy/sectors.md#one-way-warps. |
| turn_cost | Integer | default 1 | |
| warp_stability | Float | default 1.0 | |
| created_at | DateTime | not null |
WarpTunnel¶
Source: services/gameserver/src/models/warp_tunnel.py
Purpose: Named, often artificial, sector-to-sector connection with lifecycle, traversal cost, and discovery state — distinct from the lightweight sector_warps table.
Fields:
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| name | String(100) | not null | |
| origin_sector_id | UUID FK sectors.id | not null, CASCADE | |
| destination_sector_id | UUID FK sectors.id | not null, CASCADE | |
| type | Enum warp_tunnel_type |
not null | see Type enum below |
| status | Enum warp_tunnel_status |
default ACTIVE | see Status enum below |
| is_bidirectional | Boolean | default true | false flags this tunnel as a one-way link from origin → destination. Used by the long-distance variant of ESCAPE_HATCH. Player-built warp gates anchor this flag to false at Phase 3 commit (gates are intrinsically one-way; reverse traversal requires a separately-built gate). Per ADR-0034, directionality lives only on this column — never on the type enum. |
| is_latent | Boolean | default false | true means the tunnel looks bidirectional until revealed by a Warp Jumper's existing scan suite. ~20% of one-way tunnels are latent; ~80% are marked. — see ADR-0034 and ../FEATURES/galaxy/sectors.md#one-way-warps. |
| stability | Float | default 1.0 | continuous score 0.0–1.0 |
| stability_enum | Enum warp_tunnel_stability_enum |
default STABLE | discrete classification: STABLE / UNSTABLE |
| properties | JSONB | not null | length, stability_rating, expected_lifetime, age, traversal_cost, cool_down, discovered, discoverer_id, discovery_date, affected_by_storms |
| tunnel_status | JSONB | not null | is_active, disruption, traffic_level, last_traversal, maintenance_status |
| source_endpoint, destination_endpoint | JSONB | not null | sector/cluster/region/coordinates/controlling_faction/is_secured/access_requirements |
| artificial_data | JSONB | nullable | management data for player-built tunnels |
| total_traversals | Integer | default 0 | |
| traversal_history | JSONB | default [] | |
| turn_cost | Integer | default 1 | mirrors properties.traversal_cost |
| energy_cost | Integer | default 0 | |
| is_public | Boolean | default true | |
| access_requirements | JSONB | nullable | |
| created_by_player_id | UUID FK players.id | nullable | |
| created_by_faction | String | nullable | |
| construction_cost | Integer | nullable | Snapshot of the gate's all-in construction cost at build commit time (Warp Jumper hull value + Lumen Crystals + Phase 1–3 materials, summed at then-current market prices). Set on ARTIFICIAL tunnels with created_by_player_id IS NOT NULL; null for natural tunnels and operator-placed artificials. Immutable after build. Per ADR-0052 SK38, this snapshot drives the 50% refund on cascade-driven gate destruction. |
| max_uses, current_uses | Integer | nullable / default 0 | |
| expires_at | DateTime | nullable | |
| special_effects | JSONB | default {} |
Type enum (warp_tunnel_type)¶
Two values:
- NATURAL — formed by spacetime fold during galaxy generation. Most tunnels in the universe. No maintenance, no owner.
- ARTIFICIAL — engineered tunnel. Two sources, distinguished by
created_by_player_id: created_by_player_id IS NULL— generator-placed at world creation. Used to densely interconnect the low-numbered sectors of each region (sectors 1..fedspaceSize) so new-player areas remain well-connected regardless of random natural-tunnel layout.created_by_player_id IS NOT NULL— player-built warp gate produced by the beacon → focus → quantum-link construction pipeline (see../FEATURES/galaxy/warp-gates.md). Owner controls access, may charge tolls, can be destroyed.
Tunnel direction (one-way vs. bidirectional) is captured by the is_bidirectional column on the WarpTunnel row, not by the type.
Status enum (warp_tunnel_status)¶
- ACTIVE — in normal use.
- UNSTABLE — random failure rate elevated; usable.
- DEGRADING — stability is dropping over time; collapse imminent.
- COLLAPSED — no longer traversable; row kept for archaeology.
- MAINTENANCE — owner has paused traffic for repairs/upgrades.
- FORMING — under construction (player gate beacon/focus phase).
- INITIALIZING — Phase 3 harmonization in progress. The Warp Jumper is in
HARMONIZINGship-status and the focus structure has spawned, but the tunnel is not yet open for traffic. Flips toACTIVEat harmonization-completion commit (per ADR-0036). Traversal attempts during this state fail withERR_GATE_INITIALIZING.
Stability: continuous vs. discrete¶
stability (Float, 0.0–1.0) is the live continuous score consumed by traversal-risk calculations and decay ticks. stability_enum is the discrete bucket (STABLE / UNSTABLE) used for indexing, list filters, and UI badging. The two are kept consistent: when stability crosses the unstable threshold, stability_enum flips and status may advance to UNSTABLE or DEGRADING.
Disruption & maintenance¶
The tunnel_status JSONB blob carries the live operational signals:
disruption— active anomaly events (warp storms, gravitational shear, faction interdiction) that prevent traversal while present. Disruption events are randomly seeded by the world tick (e.g., warp storms sweeping a cluster) and clear after a defined duration; the tunnel returns to its priorstatuswhen the disruption expires.last_traversal— timestamp of the most recent successful transit; feeds cool-down and traffic analytics.maintenance_status— owner-initiated state for player-built gates only. While maintenance is in progress, traffic is paused andstatusis set toMAINTENANCE; the tunnel returns toACTIVEon completion.traffic_level— rolling counter feeding congestion modifiers and economic telemetry.
Natural tunnels never enter MAINTENANCE; only artificial (player-gated) tunnels expose maintenance controls.
State transitions¶
FORMING ──► ACTIVE ◄──► UNSTABLE ──► DEGRADING ──► COLLAPSED
│
▼
MAINTENANCE ──► ACTIVE
FORMING is the construction phase for artificial tunnels. ACTIVE is the steady state. UNSTABLE is reversible — stability can recover and the tunnel returns to ACTIVE. Once a tunnel enters DEGRADING, collapse is the only terminal: it advances to COLLAPSED and the row is retained for archaeology and discovery history. MAINTENANCE is reachable only from ACTIVE on player-owned tunnels and always returns to ACTIVE.
Relationships:
- origin_sector, destination_sector → Sector.
- created_by → Player.
Note: Per-traversal cost and stability are authoritative inside the properties JSONB (traversal_cost, stability_rating); the column-level turn_cost and stability fields are denormalized mirrors used for indexing and quick filters.
See also:
- FEATURES/galaxy/warp-gates.md — player gate construction, beacon/focus phases, and maintenance flows for ARTIFICIAL tunnels. Gate construction requires a Warp Jumper to reach the destination first; that reach is provided by Quantum Jump (see Sector schema note above).
- FEATURES/galaxy/sectors.md — natural-tunnel seeding, the lightweight sector_warps association table, and how sectors expose adjacency.
SectorCelestial — solar-system composition¶
A sector's "solar system" (its star(s), habitable zone, planets/orbits, belt,
nebula, debris) is a persisted, generate-once-then-stable model — a
dedicated sector_celestials table (1:1 with Sector), not JSONB on the
hot, FOR-UPDATE-locked sectors row (ADR-0073).
The gameplay/design rules (star types, HZ bands, orbit speed, axial rotation,
generation weights) are canonized in
FEATURES/galaxy/star-systems.md; this is
the persistence shape.
Status: ✅ Shipped —
services/gameserver/src/models/sector_celestial.py(SectorCelestial); filled bycelestial_service.generate_skeleton, read throughGET /api/v1/sectors/{id}/system.
sector_celestials¶
| Column | Type | Notes |
|---|---|---|
sector_uuid |
UUID PK | FK → sectors.id (cascade delete) |
sector_id |
Integer | indexed; mirrors Sector.sector_id for convenience lookup |
composition |
JSONB | the deterministic procedural skeleton (below). Real Planet/Station rows are not stored here — they are merged over the skeleton at read time |
seed |
BigInteger | the sector_id × SECTOR_SEED_SALT root seed |
created_at / updated_at |
timestamptz | generate-once; mutable thereafter |
composition JSONB shape¶
{
star: { kind, label, color, secondary? } | null, // null = VOID sector
extra_stars?: [{ kind, color }], // STAR_CLUSTER: 2–4
nebula?: { hue, density }, // NEBULA sectors
belt?: { inner_au, outer_au }, // ASTEROID_FIELD always; else ~15%
debris?: { inner_au, outer_au }, // ~12% collision ring
habitable_zone?: { inner_au, outer_au }, // per star kind; absent for neutron/black-hole
bodies: [{
slot, orbit_au, phase_deg, // orbit position + initial revolution phase
kind, // PlanetType (procedural subset, or real planet's type once merged)
size_class, palette: { hue, sat }, rings, moons,
rotation_period_hours, axial_tilt_deg, // axial spin (the local "day" + obliquity) — distinct from revolution
real: bool, planet_id?, name?, habitability?, owned?, can_rename?
}]
}
All body fields are deterministic from the body's sub-seed. rotation_period_hours
+ axial_tilt_deg drive the windshield's per-planet axial spin (see
star-systems.md → "Planet rotation"); the live orbital and spin angles are
recomputed client-side per frame and not stored.
Relationships: sector_uuid → Sector (1:1, cascade delete). A sibling
sector_feature_discoveries table tracks per-sector hidden-feature discovery
((sector, feature_type) unique), kept separate from planet discovery and the
sector's own first-discoverer (ADR-0073).