Skip to content

About

Mímisbrunnr — the well of wisdom at Yggdrasil's roots, where Mímir drinks and Odin traded an eye for a taste of it. The reference-data store of the Norse Architecture: entities, view models, TSV seeders (nietras Sep), and migrations for canonical data — ISO country/currency codes, IANA time zones (Norse.ReferenceData.Data)

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Mímisbrunnr

Mímisbrunnr — the well of wisdom at Yggdrasil's roots, guarded by Mímir, where Odin traded an eye for a single drink of it.

Mímisbrunnr — the well of wisdom at Yggdrasil's roots, guarded by Mímir, where Odin traded an eye for a single drink of it

Image credit: @norsemythologyclips — go follow them.

The reference-data store of the Norse Architecture — Norse.Reference.Data: the generated, browser-supported Reference.Data.Contracts and Reference.Data.Namespaces surfaces, the Reference.Data.EntityFramework entities and view models, TSV seeders (HyperTabular), and the Reference.Data.EntityFramework.Migrations/.PostgreSQL/.SqlServer family for canonical external-standard data. First tenants: ISO country codes, ISO currency codes, and IANA time zones. In the dependency chain it rides on Urðarbrunnr's EF foundation and everything below; Mímir rides on it.

The dependency graph

Arrows point at the thing depended on. Dashed arrows are the realm's own source generator mounted as a build-time analyzer, not a compile dependency — its output compiles into the consuming assembly, so package consumers receive generated code, never the generator. The shape below is deliberately congruent with Himinbjörg's chart: this is the persistence-consumer stencil every norse_{context} realm follows.

flowchart BT
	subgraph Mimisbrunnr["Mímisbrunnr — Norse.Reference.Data"]
		MigrationsPg["Reference.Data.EntityFramework.Migrations.PostgreSQL"]
		Migrations["Reference.Data.EntityFramework.Migrations"]
		EntityFramework["Reference.Data.EntityFramework"]
		RefPrimitives["Reference.Data.Contracts"]
		Namespaces["Reference.Data.Namespaces"]
		Generator["Reference.Data.Contracts.Generator"]
	end
	subgraph Asgard
		Backend["Abstractions.Backend"]
		Emit["Abstractions.Emit"]
	end
	subgraph Urdarbrunnr["Urðarbrunnr — Norse.Persistence"]
		PEFPg["EntityFramework.PostgreSQL"]
		PEFMigrations["EntityFramework.Migrations"]
		PEF["EntityFramework"]
	end
	subgraph Svartalfheim["Svartálfheim"]
		Primitives["Norse.Primitives"]
	end
	EntityFramework --> RefPrimitives
	EntityFramework --> Backend
	EntityFramework --> PEF
	RefPrimitives --> Primitives
	Migrations --> EntityFramework
	Migrations --> PEFMigrations
	Migrations --> Primitives
	MigrationsPg --> Migrations
	MigrationsPg --> PEFPg
	RefPrimitives -.-> Generator
	Namespaces -.-> Generator
	Generator --> Emit
Loading

Reference.Data.EntityFramework.Migrations.SqlServer mirrors the PostgreSQL leg edge for edge (Reference.Data.EntityFramework.Migrations + Urðarbrunnr's EntityFramework.SqlServer) and is left off the chart for legibility, same as Himinbjörg's. Design-time-only references (NorseDesignRef on EntityFramework.Design, carried by both provider legs) stay off runtime charts. tools/SeedTool is dev-only tooling, never packed, and charts nothing.

Status

The first seed case — UN M49 reference data (Region/CountryOrArea) — has its raw-source-to-TSV conversion tooling live: tools/SeedTool (a dev-only console app, never packed or AOT-published) reads seeds/raw/UNSD — Methodology.csv via HyperTabular (header-first, every column resolved by name) and produces the curated seeds/region.tsv/seeds/country-or-area.tsv, both committed as this realm's real seed data. The EF entities (Region, CountryOrArea, the RegionNode hierarchy), ReferenceDbContext, the InitialCreate migration (temporal apparatus and all), NorseReferenceMigrationContributor, and ReferenceDataSeedContributor are all live and load these TSVs into norse_reference (specced in Glitnir's docs/Mimisbrunnr/). Everything beyond this first seed case (currency, language, script, locale, timezone — see the ERD sketch below) remains unconverged; design happens first: brainstorm → spec → plan, recorded in Glitnir's docs/Mimisbrunnr/, before any further project is scaffolded here.

Reference data is system-versioned (2026-08-05)

Both root tables carry Urðarbrunnr's ITemporalEntity marker — and that marker plus a re-issued migration is the entire adoption. This repository contains zero hand-written temporal SQL. ISO/UN canon is static data that changes rarely, and the record of when it changed — a country renamed, a code redenominated, a region re-parented — is exactly what system-time history is for. There is no non-temporal side here: the realm holds no secret stores, counters, or prunable runtime state. The owned CountryOrAreaView jsonb document graph takes no marker of its own, because owned and JSON-mapped types sit outside the temporal contract and the view column's contents ride the owner's history like any other column.

On PostgreSQL the apparatus is a database-owned system_period, a {table}_history table under a WITHOUT OVERLAPS primary key, a SECURITY DEFINER versioning function with insert/update/delete triggers bound to it, and a {table}_timeline view; on SQL Server it is engine-native SYSTEM_VERSIONING = ON. Seeding never versions — an INSERT opens a version, it does not close one — so the TSV seed mints zero history rows and every seeded row is a current version. The first amendment to a seeded row is the first history row.

Initial sketch of reference data plan

erDiagram
  region {
    char(3) un_m49_code PK
    varchar name
    char(3) parent_m49 FK
    smallint level
  }

  country {
    char(2) iso_3166_1_alpha2 PK
    char(3) iso_3166_1_alpha3
    char(3) iso_3166_1_numeric
    char(3) un_m49_code FK
    varchar common_name
    varchar official_name
    bool is_independent
    bool is_active
  }

  subdivision {
    varchar iso_3166_2_code PK
    char(2) country_alpha2 FK
    varchar name
    varchar type
  }

  language {
    char(3) iso_639_3_code PK
    char(2) iso_639_1_code
    varchar name
    char(4) iso_15924_script FK
    varchar scope
    varchar lang_type
  }

  script {
    char(4) iso_15924_code PK
    varchar name
    smallint unicode_number
    varchar unicode_alias
  }

  locale {
    varchar bcp47_tag PK
    char(3) language_code FK
    char(4) script_code FK
    char(2) country_alpha2 FK
    varchar display_name
    varchar number_format
    varchar date_format
    varchar first_day_of_week
  }

  currency {
    char(3) iso_4217_code PK
    varchar name
    varchar symbol
    smallint minor_unit
    bool is_active
  }

  country_currency {
    char(2) country_alpha2 FK
    char(3) currency_code FK
    bool is_primary
  }

  country_language {
    char(2) country_alpha2 FK
    char(3) language_code FK
    varchar status
  }

  timezone {
    varchar iana_key PK
    varchar canonical_key FK
    char(2) country_alpha2 FK
    varchar region_hint
    bool is_canonical
  }

  utc_offset {
    varchar iana_key FK
    varchar offset_code
    smallint offset_minutes
    varchar abbreviation
    bool is_dst
    date valid_from
    date valid_until
  }

  calling_code {
    serial id PK
    char(2) country_alpha2 FK
    varchar e164_prefix
    bool is_primary
  }

  region ||--o{ region : "parent"
  region ||--o{ country : "contains"
  country ||--o{ subdivision : "has"
  country ||--o{ country_currency : "uses"
  country ||--o{ country_language : "speaks"
  country ||--o{ timezone : "observes"
  country ||--o{ calling_code : "assigned"
  currency ||--o{ country_currency : "used by"
  language ||--o{ country_language : "spoken in"
  language }o--|| script : "written in"
  script ||--o{ locale : "used by"
  language ||--o{ locale : "defines"
  country ||--o{ locale : "applies"
  timezone ||--o{ utc_offset : "has rules"
  timezone }o--o| timezone : "alias of"
Loading

Migrations CLI

Both provider migrations projects (src/Reference.Data.EntityFramework.Migrations.PostgreSQL, src/Reference.Data.EntityFramework.Migrations.SqlServer) carry a design-time factory that supplies an inert placeholder connection string, so the EF CLI runs entirely offline — no database, no network, ever. Applying migrations against a real database is the migrations service's job, not this CLI's.

First, restore the pinned dotnet-ef tool:

dotnet tool restore

Then, per provider:

dotnet ef migrations add <Name> --project src/Reference.Data.EntityFramework.Migrations.PostgreSQL --startup-project src/Reference.Data.EntityFramework.Migrations.PostgreSQL
dotnet ef migrations add <Name> --project src/Reference.Data.EntityFramework.Migrations.SqlServer --startup-project src/Reference.Data.EntityFramework.Migrations.SqlServer

Every add (and remove) auto-refreshes the provider's embedded schema/norse_reference.sql — that file is DDL emitted by the scaffolder, never hand-edited.

Platform law (squash migrations until the provider-defaults chassis settles) keeps exactly one InitialCreate per provider. A schema change is not a new migration stacked on top — delete the provider's Migrations/ folder and re-add InitialCreate:

rm src/Reference.Data.EntityFramework.Migrations.PostgreSQL/Migrations/*
dotnet ef migrations add InitialCreate --project src/Reference.Data.EntityFramework.Migrations.PostgreSQL --startup-project src/Reference.Data.EntityFramework.Migrations.PostgreSQL

(and the SqlServer twin).

Re-issuing InitialCreate mints a new migration id, which orphans any database that already applied the prior one — MigrateAsync sees the new id as pending and fails on CREATE TABLE region with "relation already exists", naming neither cause nor cure. Drop the norse_reference database (or Bifröst's norse-pg-primary volume) before the next run; migration plus seed restores full state by construction, which is exactly why this realm can afford the squash posture until the preview-7 V1 memorialization.

Temporal enablement was squashed in exactly that way, so the apparatus arrives at table birth alongside CREATE TABLE rather than bolted on by a stacked enable migration — nothing here carries a backfill UPDATE … SET system_period. The consequence for tests is worth stating outright: never assert on a migration name. The container facts assert on the PostgreSQL catalog (pg_class/pg_proc/pg_trigger), which survives every squash.

Why two repos

Mímisbrunnr and Mímir are one bounded context split across two repositories for a specific, verified reason: reference-data content (IANA reissuing time zone data, ISO adding or redenominating currencies) changes far more often than the service and component code that serves it, and the platform's release tooling only supports repo-scoped tags — packing and publishing happen for an entire repo at once, not per project. Splitting the repository is what lets Data cut a release without dragging Components/Web.Server/Worker along, and vice versa. This pair is a template for anyone whose own reference data has the same shape — not a pattern the platform applies by default.

The cosmos

Mímisbrunnr is one realm of the Norse Architecture. The whole platform composes at Bifröst — clone once, cross the bridge, and every session starts there so decisions get brainstormed across the entire landscape, not in isolation. Every design is tried in Glitnir, the design court, before code is forged here; this realm's specs and plans will live in the court's docs/Mímisbrunnr/ once they converge.

Soundtrack: Óðinn við Mímis brunn (Odin at the Well of Mímir)

Soundtrack: Óðinn við Mímis brunn (Odin at the Well of Mímir)

About

Mímisbrunnr — the well of wisdom at Yggdrasil's roots, where Mímir drinks and Odin traded an eye for a taste of it. The reference-data store of the Norse Architecture: entities, view models, TSV seeders (nietras Sep), and migrations for canonical data — ISO country/currency codes, IANA time zones (Norse.ReferenceData.Data)

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages