Single-table multi-tenant Postgres with RLS + a sparse EAV override layer. One pattern, three substrates: configuration (what users edit), audit + lineage (what happened), computed (what's been derived). All three sit on a shared reference foundation that public + tenant rows co-occupy via workspace_id + Postgres RLS per DD-016. Adding a new analytical dimension is schema-additive, not architecturally novel.
Schema rows are queried live from information_schema.columns + pg_indexes — always honest. For the full prose, read tenant_workspace_v2 README, architecture overview, schema reference, governance, and decisions.md.
configuration · audit + lineage · modeling · Your session has performed 0 actions · fa2c9fb8-e42…
The shared data layer. Public EIA-derived rows (workspace_id IS NULL) live alongside tenant-private rows in the same physical table; Postgres RLS draws the boundary at read time per DD-016. Legacy `engineering_plant` + `engineering_generator` were dropped in 04m.12 — substrate is the only engineering grain.
| data | jsonb | NOT NULL |
| data_hash | text | |
| data_provenance | jsonb | NOT NULL |
| id | uuid | NOT NULL |
| eia_plant_id | integer | |
| slug | text | NOT NULL |
| source_type | text | NOT NULL |
| workspace_id | uuid | |
| creation_method | text | NOT NULL |
| id | uuid | NOT NULL |
| plant_id | uuid | NOT NULL |
| eia_generator_code | text | |
| source_type | text | NOT NULL |
| workspace_id | uuid | |
| creation_method | text | NOT NULL |
| prime_mover_code | text | |
| fuel_code | text | |
| technology | text | |
| nameplate_mw | numeric | |
| net_summer_capacity_mw | numeric | |
| net_winter_capacity_mw | numeric | |
| status | text | |
| status_code | text | |
| in_service_date | date | |
| planned_operation_date | date | |
| retirement_date | date | |
| created_at | timestamp with time zone | NOT NULL |
| updated_at | timestamp with time zone | NOT NULL |
| data_provenance | jsonb | NOT NULL |
| template_id | uuid | |
| tech_class | text |
| plant_id | integer | NOT NULL |
| plant_name | text | |
| state | text | |
| county | text | |
| lat | double precision | |
| lon | double precision | |
| primary_fuel | text | |
| fuel_types | ARRAY | |
| technologies | ARRAY | |
| is_hybrid | boolean | |
| total_capacity_mw | double precision | |
| n_generators | integer | |
| utility_eia_name | text | |
| gem_entity_name | text | |
| gem_parent_name | text | |
| operating_year | integer | |
| status | text | |
| wikidata_qid | text | |
| rank_state | integer | |
| rank_national | integer | |
| total_in_state | integer | |
| total_in_nation | integer | |
| iso | text | |
| has_financial | boolean | |
| has_pricing_node | boolean | |
| annual_mwh | double precision | |
| capacity_factor | double precision | |
| has_wikipedia | boolean | |
| has_news | boolean | |
| status_detail | text | |
| has_interconnection_queue | boolean | |
| slug | text | |
| canonical_owner | text | |
| canonical_owner_all | ARRAY | |
| grid_region | text | |
| is_thermal | boolean | |
| has_combined_cycle | boolean | |
| has_dual_fuel | boolean | |
| has_repower_planned | boolean | |
| has_emissions | boolean | |
| egrid_subregion_code | text | |
| co2_rate_lb_per_mwh | double precision | |
| ba_code | text | |
| iso_rto_code | text | |
| nerc_region_code | text | |
| rc_code | text | |
| status_code | text | |
| has_corporate_ppa | boolean | |
| offtaker_ids | ARRAY | |
| offtaker_names | ARRAY | |
| fts | tsvector |
| subsystem_id | uuid | NOT NULL |
| workspace_id | uuid | |
| plant_id | uuid | NOT NULL |
| generator_id | uuid | |
| subsystem_code | text | NOT NULL |
| instance_no | integer | NOT NULL |
| data | jsonb | NOT NULL |
| data_provenance | jsonb | NOT NULL |
| created_at | timestamp with time zone | NOT NULL |
| updated_at | timestamp with time zone | NOT NULL |
| variant_id | uuid | |
| tombstone_of | uuid | |
| geometry | jsonb | |
| lat | numeric | |
| lon | numeric | |
| grid_substation_id | text |
| component_id | uuid | NOT NULL |
| workspace_id | uuid | |
| subsystem_id | uuid | NOT NULL |
| component_code | text | NOT NULL |
| manufacturer | text | |
| model | text | |
| quantity | integer | NOT NULL |
| year_installed | integer | |
| specs | jsonb | NOT NULL |
| data | jsonb | NOT NULL |
| data_provenance | jsonb | NOT NULL |
| created_at | timestamp with time zone | NOT NULL |
| updated_at | timestamp with time zone | NOT NULL |
| variant_id | uuid | |
| tombstone_of | uuid |
| code | text | NOT NULL |
| display_name | text | NOT NULL |
| description | text | |
| applicable_tech_classes | ARRAY | NOT NULL |
| default_parent_scope | text | NOT NULL |
| damage_behavior | text | |
| is_active | boolean | NOT NULL |
| created_at | timestamp with time zone | NOT NULL |
| updated_at | timestamp with time zone | NOT NULL |
| requirement | text | NOT NULL |
| code | text | NOT NULL |
| display_name | text | NOT NULL |
| description | text | |
| parent_subsystem_code | text | NOT NULL |
| specs_schema | jsonb | NOT NULL |
| is_active | boolean | NOT NULL |
| created_at | timestamp with time zone | NOT NULL |
| updated_at | timestamp with time zone | NOT NULL |
| requirement | text | NOT NULL |
| exclusive_group | text | |
| is_default | boolean | NOT NULL |
Where the workspace expresses its view of the world. `tenant_overrides` is a row-per-field EAV cell store; `tenant_variants` groups override sets into named what-if scenarios; `tenant_templates` are reusable blueprints. The resolver primitives in `provenance.ts` merge baseline + variant overlays at read time — the rendered page is always derived, never persisted.
| id | uuid | NOT NULL |
| name | text | NOT NULL |
| slug | text | NOT NULL |
| created_at | timestamp with time zone | NOT NULL |
| updated_at | timestamp with time zone | NOT NULL |
| deleted_at | timestamp with time zone |
| id | uuid | NOT NULL |
| workspace_id | uuid | NOT NULL |
| name | text | NOT NULL |
| description | text | |
| created_at | timestamp with time zone | NOT NULL |
| updated_at | timestamp with time zone | NOT NULL |
| deleted_at | timestamp with time zone | |
| kind | text | NOT NULL |
| id | uuid | NOT NULL |
| workspace_id | uuid | NOT NULL |
| portfolio_id | uuid | NOT NULL |
| reference_generator_id | text | |
| variant_name | text | NOT NULL |
| is_baseline | boolean | NOT NULL |
| override_capacity_mw | numeric | |
| notes | text | |
| created_at | timestamp with time zone | NOT NULL |
| updated_at | timestamp with time zone | NOT NULL |
| deleted_at | timestamp with time zone | |
| reference_plant_id | uuid | NOT NULL |
| id | uuid | NOT NULL |
| workspace_id | uuid | NOT NULL |
| plant_id | uuid | NOT NULL |
| generator_id | uuid | |
| name | text | NOT NULL |
| description | text | |
| created_by | uuid | |
| created_at | timestamp with time zone | NOT NULL |
| updated_at | timestamp with time zone | NOT NULL |
| id | uuid | NOT NULL |
| workspace_id | uuid | NOT NULL |
| variant_id | uuid | |
| plant_id | uuid | NOT NULL |
| generator_id | uuid | |
| dimension | text | NOT NULL |
| field_path | text | NOT NULL |
| value | jsonb | NOT NULL |
| rationale | text | |
| source_event_id | uuid | |
| author_id | uuid | |
| created_at | timestamp with time zone | NOT NULL |
| updated_at | timestamp with time zone | NOT NULL |
| subsystem_id | uuid | |
| component_id | uuid |
| id | uuid | NOT NULL |
| workspace_id | uuid | |
| name | text | NOT NULL |
| description | text | |
| fuel_code | text | |
| tech_code | text | |
| default_capacity_mw | numeric | |
| body | jsonb | NOT NULL |
| created_by | text | |
| created_at | timestamp with time zone | NOT NULL |
| updated_at | timestamp with time zone | NOT NULL |
| is_deprecated | boolean | NOT NULL |
| id | uuid | NOT NULL |
| workspace_id | uuid | NOT NULL |
| portfolio_id | uuid | NOT NULL |
| name | text | NOT NULL |
| description | text | |
| reference_data_version | text | NOT NULL |
| synthesis_function_version | text | |
| model_version | text | |
| computed_at | timestamp with time zone | NOT NULL |
| created_at | timestamp with time zone | NOT NULL |
Append-only history. Every mutation handler wraps the data write + audit row in one transaction (DD-013); `event_session_id` groups multi-write actions like Promote-variant into one user-readable line. `model_input_snapshot` extends the same idea for modeling — every output row carries a snapshot ID, so the inputs that produced a number stay reproducible after the workspace moves on.
| id | uuid | NOT NULL |
| workspace_id | uuid | NOT NULL |
| actor_type | text | NOT NULL |
| actor_id | text | |
| action | text | NOT NULL |
| resource_type | text | NOT NULL |
| resource_id | text | |
| occurred_at | timestamp with time zone | NOT NULL |
| before_state | jsonb | |
| after_state | jsonb | |
| event_session_id | uuid |
| id | uuid | NOT NULL |
| workspace_id | uuid | |
| variant_id | uuid | |
| plant_id | uuid | NOT NULL |
| bundle | jsonb | NOT NULL |
| model_version | text | NOT NULL |
| override_count | integer | NOT NULL |
| computed_at | timestamp with time zone | NOT NULL |
Modeled outputs (DD-033/DD-034) at monthly grain. Production is staleness-driven: a config edit fires a `modeling_invalidation` row per affected output dim (DD-038), the UI surfaces an amber badge, and Re-run clears it. Currently a mock — real model orchestration lands later without changing this surface. 04m.13.9: per-field `modelDependencies` declarations are preliminary; the runtime fires all dims on every edit until the modeling team validates.
| plant_id | uuid | NOT NULL |
| tech | text | NOT NULL |
| grain | text | NOT NULL |
| parameters | jsonb | NOT NULL |
| source | text | NOT NULL |
| confidence | text | NOT NULL |
| data | jsonb | NOT NULL |
| data_provenance | jsonb | NOT NULL |
| created_at | timestamp with time zone | NOT NULL |
| updated_at | timestamp with time zone | NOT NULL |
| id | uuid | NOT NULL |
| workspace_id | uuid | |
| variant_id | uuid | |
| plant_id | uuid | NOT NULL |
| period_kind | text | NOT NULL |
| period_start | date | NOT NULL |
| generation_mwh | numeric | NOT NULL |
| capacity_factor | numeric | |
| peak_hour_mw | numeric | |
| availability_pct | numeric | |
| curtailment_mwh | numeric | |
| data | jsonb | NOT NULL |
| model_version | text | NOT NULL |
| source | text | NOT NULL |
| computed_at | timestamp with time zone | NOT NULL |
| input_snapshot_id | uuid | NOT NULL |
| id | uuid | NOT NULL |
| workspace_id | uuid | |
| variant_id | uuid | |
| plant_id | uuid | NOT NULL |
| generator_id | uuid | NOT NULL |
| period_kind | text | NOT NULL |
| period_start | date | NOT NULL |
| generation_mwh | numeric | NOT NULL |
| capacity_factor | numeric | |
| peak_hour_mw | numeric | |
| availability_pct | numeric | |
| curtailment_mwh | numeric | |
| data | jsonb | NOT NULL |
| model_version | text | NOT NULL |
| source | text | NOT NULL |
| computed_at | timestamp with time zone | NOT NULL |
| input_snapshot_id | uuid | NOT NULL |
| id | uuid | NOT NULL |
| workspace_id | uuid | |
| variant_id | uuid | |
| plant_id | uuid | NOT NULL |
| hazard_type | text | NOT NULL |
| period_kind | text | NOT NULL |
| period_start | date | NOT NULL |
| exposure_score | numeric | NOT NULL |
| exposure_band | text | |
| contributing_factors | jsonb | NOT NULL |
| model_version | text | NOT NULL |
| source | text | NOT NULL |
| computed_at | timestamp with time zone | NOT NULL |
| input_snapshot_id | uuid | NOT NULL |
| id | uuid | NOT NULL |
| workspace_id | uuid | |
| variant_id | uuid | |
| plant_id | uuid | NOT NULL |
| generator_id | uuid | NOT NULL |
| hazard_type | text | NOT NULL |
| period_kind | text | NOT NULL |
| period_start | date | NOT NULL |
| exposure_score | numeric | NOT NULL |
| exposure_band | text | |
| contributing_factors | jsonb | NOT NULL |
| model_version | text | NOT NULL |
| source | text | NOT NULL |
| computed_at | timestamp with time zone | NOT NULL |
| input_snapshot_id | uuid | NOT NULL |
| id | uuid | NOT NULL |
| workspace_id | uuid | NOT NULL |
| plant_id | uuid | NOT NULL |
| variant_id | uuid | |
| output_dim | text | NOT NULL |
| invalidated_at | timestamp with time zone | NOT NULL |
| invalidated_by_override_id | uuid | |
| context | jsonb |
| paid | portfolio | plant | variant | cap (eff / ref) | updated |
|---|---|---|---|---|---|
| 65c55339… | Test | 63688Topaz Generating | ★baseline | 605 | 2026-06-29 |
| 2a52af7d… | Test | 63910Bluegrass Solar | ★baseline | 79.6 | 2026-06-29 |
| 0885d5f5… | Test | 64430American Beech Solar LLC | ★baseline | 140 | 2026-06-29 |
| 175e55ba… | Test | 68998Long Point Solar | ★baseline | 120 | 2026-06-29 |
| 11fbb06d… | Test | 62406City of Gallup Solar | ★baseline | 8 | 2026-06-29 |
| a8bb6274… | Test | 60299HMV Minster Energy Storage System | ★baseline | 7 | 2026-06-29 |
| 4fb17c28… | Test | 69096Jericho | ★baseline | 5 | 2026-06-29 |
| c2c33578… | Test | 69787AC IL - Hillsboro | ★baseline | 5 | 2026-06-29 |
| e3663fc0… | Test | 67747Nachtigall 1836-WD | ★baseline | 4.6 | 2026-06-29 |
| ff8e24c5… | Test | 63727Slate Hybrid | ★baseline | 440.3 | 2026-06-18 |
| time | actor | action | resource_id | diff |
|---|---|---|---|---|
| 2026-06-29 | 617e3094… | portfolio_asset.add | 65c55339… |
|
| 2026-06-29 | 617e3094… | portfolio_asset.add | 2a52af7d… |
|
| 2026-06-29 | 617e3094… | portfolio_asset.add | 0885d5f5… |
|
| 2026-06-29 | 617e3094… | portfolio_asset.add | 175e55ba… |
|
| 2026-06-29 | 617e3094… | portfolio_asset.add | 11fbb06d… |
|
| 2026-06-29 | 617e3094… | portfolio_asset.add | a8bb6274… |
|
| 2026-06-29 | 617e3094… | portfolio_asset.add | 4fb17c28… |
|
| 2026-06-29 | 617e3094… | portfolio_asset.add | c2c33578… |
|
| 2026-06-29 | 617e3094… | portfolio_asset.add | e3663fc0… |
|
| 2026-06-18 | 617e3094… | portfolio_asset.add | ff8e24c5… |
|