Files
boc/docs/arc/ARC-001-canonical-domain-model.md
T
Bernt bae705aa97 ARCHITECTURE: NFC roadmap, edge AI, audit logging
- Add NFC ePassport roadmap (ICAO 9303, eIDAS)
- Add TensorFlow.js edge face detection (BlazeFace)
- Add structured audit logger (GDPR-compliant)
- Risk scoring support

Part of KYC Apple Native UX v1.1.0
2026-06-29 16:24:48 +00:00

16 KiB
Raw Blame History

ARC-001 — Canonical Domain Model

Status: Accepted
Datum: 2026-06-01
Beslutsfattare: AAMOS Architecture Team


Kontext

AAMOS är ett verksamhetsoperativsystem vars primära designkrav är att moduler (Ekonomi, CRM, HR, Projekt, Kvalitet, Inköp, Kontrakt) kan samexistera, utbyta data och bygga på varandras entiteter utan att skapa n×m-mappningsproblem.

Utan ett kanoniskt objektsystem uppstår ofrånkomligen:

  • Semantisk drift — samma begrepp (t.ex. "Person") modelleras på 4 olika sätt i 4 moduler, vilket omöjliggör korsmodulärsökning och AI-kontext
  • Integrationsskuld — varje ny modul måste skriva egna adaptrar mot alla befintliga moduler
  • Auditbrist — när ett objekt existerar på flera ställen blir spårbarhet svårt att garantera

Ekonomimodulen är referensimplementationen. Alla val i detta ADR speglas redan (eller ska speglas) i Ekonomimodulens databasschema.


Beslut

AAMOS definierar tolv universella kanoniska objekt. Varje modul MÅSTE använda dessa objekt som primärreferenser och får inte definiera alternativa entiteter för samma semantiska koncept.

Fundamentala fält (alla objekt)

Varje kanoniskt objekt bär alltid dessa fält:

Fält Typ Beskrivning
id UUID v7 Globalt unikt, tidsordnat
tenant_id UUID Isoleringsdomän (se ARC-003)
created_at timestamptz ISO 8601, UTC
updated_at timestamptz ISO 8601, UTC, auto-update
created_by UUID Referens till Person.id eller system-ID
deleted_at timestamptz|null Soft-delete, null = aktiv
metadata jsonb Fri nyckel-värde-extension (modul-specifika fält)
version integer Optimistic locking, inkrementeras vid varje UPDATE

UUID v7 används för att primary key-index förblir klusterordnade i PostgreSQL och förhindrar page splits vid hög insertfrekvens.


Objekt 1 — Entity

Abstrakt basobjekt. Alla övriga kanoniska objekt ärver Entity-kontraktet (de fundamentala fälten ovan). Entity instansieras aldrig direkt — det är ett kontrakt, inte en tabell.

Syfte: Definiera det minsta kontraktet som gör ett objekt spårbart, isolerat och versionerat.

Relationer:

  • Varje konkret objekt implementerar Entity-kontraktet
  • Entity-kontraktet gör det möjligt för generiska tjänster (audit, sök, event-routing) att hantera alla objekt uniformt

Objekt 2 — Organization

Bolag, juridisk person, koncern, avdelning, team, kostnadsställe.

Fält Typ Beskrivning
name text Officiellt namn
org_number text|null Organisationsnummer (landsspecifikt)
org_type enum company, department, team, group, subsidiary
parent_id UUID|null Självrefererande hierarki
country_code char(2) ISO 3166-1 alpha-2
tax_id text|null Momsregistreringsnummer
currency_code char(3) ISO 4217 (primärvaluta)
status enum active, inactive, merged, dissolved
external_refs jsonb {erp_id, crm_id, ...}

Relationer:

  • Organization → Organization (parent_id, hierarkisk)
  • Organization ↔ Person (many-to-many via memberships)
  • Organization → Location (many)
  • Organization → Contract (many)

Ekonomimodulen-mappning:
accounts.owner_org_id → Organization.id
journal_entries.entity_id → Organization.id (när motpart är bolag)


Objekt 3 — Person

Anställd, kontaktperson, ägare, kund, leverantörskontakt, systemanvändare.

Fält Typ Beskrivning
first_name text
last_name text
display_name text Beräknat eller angivet
email text|null Primär e-post
phone text|null E.164-format
national_id encrypted_text|null Personnummer — krypterat i vila
person_type enum employee, contact, customer, owner, system
primary_org_id UUID|null → Organization.id
user_account_id UUID|null → auth-systemets User.id
gdpr_consent jsonb Samtyckesregister per ändamål

Relationer:

  • Person → Organization (many-to-many via memberships)
  • Person → Location (many, adress-koppling)
  • Person → Task (assignee)
  • Person → Contract (signatory)

Ekonomimodulen-mappning:
suppliers.contact_person_id → Person.id
expense_reports.submitted_by → Person.id


Objekt 4 — Asset

Anläggningstillgång, resursobjekt, produkt, inventariepost, licenspost.

Fält Typ Beskrivning
name text
asset_type enum fixed_asset, inventory, product, license, resource, intangible
serial_number text|null
acquisition_date date|null
acquisition_cost numeric(18,4)|null
currency_code char(3)|null
owner_org_id UUID|null → Organization.id
location_id UUID|null → Location.id
status enum active, disposed, under_maintenance, transferred
depreciation_policy jsonb|null Avskrivningsregler (Ekonomi)

Relationer:

  • Asset → Organization (owner)
  • Asset → Location (plats)
  • Asset → Transaction (inköp, avskrivning)
  • Asset → Contract (leasing, garanti)

Ekonomimodulen-mappning:
fixed_assets tabell är en direkt implementation av Asset med utökad depreciation_policy.


Objekt 5 — Location

Adress, arbetsplats, lagerplats, land, leveransadress.

Fält Typ Beskrivning
name text|null T.ex. "Huvudkontor Stockholm"
location_type enum address, workplace, warehouse, country, virtual
street text|null
city text|null
postal_code text|null
country_code char(2) ISO 3166-1
region text|null Stat/landsdel
coordinates point|null PostGIS POINT(lon lat)
parent_id UUID|null Hierarki (land → stad → adress)

Relationer:

  • Location → Organization (many)
  • Location → Person (hemadress, arbetsplats)
  • Location → Asset (plats)

Objekt 6 — Project

Projekt, uppdrag, kostnadsbärare, kampanj, budgetpost.

Fält Typ Beskrivning
name text
code text|null Projektnamn/nummer för referens
project_type enum internal, client, rnd, infrastructure, overhead
status enum planning, active, on_hold, completed, cancelled
owner_id UUID → Person.id
org_id UUID → Organization.id
budget numeric(18,4)|null
currency_code char(3)|null
start_date date|null
end_date date|null
parent_project_id UUID|null Delprojekt-hierarki

Relationer:

  • Project → Organization (ägande)
  • Project → Person (projektledare, team)
  • Project → Task (nedbrytning)
  • Project → Transaction (kostnader, intäkter)
  • Project → Contract (kontrakt kopplade till projekt)

Ekonomimodulen-mappning:
cost_centers.project_id → Project.id
budget_lines.project_id → Project.id


Objekt 7 — Task

Arbetsuppgift, aktivitet, ärende, batchjobb, processuppgift.

Fält Typ Beskrivning
title text
description text|null
task_type enum manual, automated, approval, review, notification
status enum pending, in_progress, blocked, completed, cancelled
priority enum low, medium, high, critical
assignee_id UUID|null → Person.id
project_id UUID|null → Project.id
parent_task_id UUID|null Subtask-hierarki
due_date timestamptz|null
completed_at timestamptz|null
workflow_instance_id UUID|null → Workflow.id

Relationer:

  • Task → Person (assignee, creator)
  • Task → Project (tillhörighet)
  • Task → Workflow (processdrivet)
  • Task → Document (bilagor)

Objekt 8 — Workflow

Processinstans. Kopplas till Workflow Engine (framtida).

Fält Typ Beskrivning
workflow_definition_id text Referens till process-definition
workflow_version text Versionerad processdefinition
status enum pending, running, waiting, completed, failed, cancelled
context jsonb Runtime-kontext för processinstansen
started_at timestamptz|null
completed_at timestamptz|null
initiator_id UUID → Person.id eller system
current_step text|null Stegidentifierare

Relationer:

  • Workflow → Task (genererade uppgifter)
  • Workflow → Document (processade dokument)
  • Workflow → Transaction (utlösta transaktioner)

Ekonomimodulen-mappning:
Fakturaflöde (inkommen faktura → godkännande → betalning) är en Workflow-instans.


Objekt 9 — Document

Faktura, kvitto, kontrakt, rapport, fil, attest.

Fält Typ Beskrivning
title text
document_type enum invoice, receipt, contract, report, attachment, specification, certificate
mime_type text|null application/pdf, image/jpeg, etc.
storage_key text|null S3/blob-sökväg
checksum text|null SHA-256 av filinnehållet
size_bytes bigint|null
source_system text|null Ursprungssystem
related_entity_id UUID|null Polymorf referens
related_entity_type text|null T.ex. Transaction, Contract
classification enum public, internal, confidential, restricted (se ARC-003)
extracted_data jsonb|null AI-extraherade fält (se ARC-002)

Relationer:

  • Document → Transaction (underlag)
  • Document → Contract (kontraktsdokument)
  • Document → Workflow (processunderlag)

Ekonomimodulen-mappning:
supplier_invoices.document_id → Document.id
expense_reports.receipt_document_ids → Document.id[]


Objekt 10 — Transaction

Ekonomisk händelse. JournalEntry är en Transaction med transaction_type = journal_entry.

Fält Typ Beskrivning
transaction_type enum journal_entry, payment, invoice, credit_note, accrual, depreciation, transfer
amount numeric(18,4) Absolutbelopp
currency_code char(3) ISO 4217
base_currency_amount numeric(18,4)|null Omräknat till baskvaluta
exchange_rate numeric(12,8)|null
status enum draft, posted, voided, pending_approval
transaction_date date Transaktionsdatum (affärsdatum)
value_date date|null Valuteringsdatum
reference text|null Externt referensnummer
counterparty_id UUID|null → Organization.id eller Person.id
project_id UUID|null → Project.id
document_id UUID|null → Document.id (underlag)
lines jsonb Transaktionsrader med konton och belopp

Relationer:

  • Transaction → Organization (motpart)
  • Transaction → Person (utförare)
  • Transaction → Document (verifikat)
  • Transaction → Project (kostnadsbärare)
  • Transaction → Asset (anläggningstillgångsrörelser)

Ekonomimodulen-mappning:
journal_entries är Transactions med transaction_type = journal_entry.
Ledger Engine håller transaktionsrader i lines-jsonb eller separata rader beroende på volym.


Objekt 11 — Event

Systemevent, domänevent. Detta är Hermes Event Fabric-payloaden.

Fält Typ Beskrivning
event_type text Namnrymd: aamos.ekonomi.transaction.posted
event_version text Semver av event-schemat
source_service text Originerande tjänst
correlation_id UUID Spårnings-ID genom systemet
causation_id UUID|null ID på det event som orsakade detta
subject_type text Typ av ämnesobjekt
subject_id UUID ID på ämnesobjektet
payload jsonb Eventnyttolast
published_at timestamptz Publiceringstidpunkt

Namnrymdskonvention:
aamos.<modul>.<objekt>.<verb> — t.ex. aamos.ekonomi.transaction.posted, aamos.crm.contact.created

Relationer:

  • Event refererar till vilket som helst kanoniskt objekt via subject_id
  • Events persisteras i JSONL-fallback för replay

Objekt 12 — Contract

Avtal, SLA, leverantörsavtal, anställningsavtal, ramavtal, licens.

Fält Typ Beskrivning
title text
contract_type enum supplier, customer, employment, sla, license, framework, nda
status enum draft, pending_signature, active, expired, terminated, renewed
counterparty_org_id UUID|null → Organization.id
counterparty_person_id UUID|null → Person.id
owner_org_id UUID → Organization.id (intern part)
start_date date|null
end_date date|null
auto_renewal boolean
value numeric(18,4)|null Kontraktsvärde
currency_code char(3)|null
document_id UUID|null → Document.id (signerat PDF)
terms jsonb|null Strukturerade avtalsvillkor

Relationer:

  • Contract → Organization (parter)
  • Contract → Person (signatärer)
  • Contract → Document (kontraktsdokument)
  • Contract → Transaction (betalningsplan, fakturor)
  • Contract → Asset (leasade tillgångar)

Ekonomimodulens fullständiga mappning

Ekonomimodul          → Kanonisk typ
──────────────────────────────────────────
JournalEntry          → Transaction (type=journal_entry)
Supplier              → Organization (org_type=company)
Customer              → Organization (org_type=company)
SupplierInvoice       → Document (type=invoice) + Transaction
ExpenseReport         → Document (type=report) + Transaction[]
FixedAsset            → Asset (type=fixed_asset)
CostCenter            → Project (type=overhead/internal)
Employee              → Person (type=employee)
ApprovalFlow          → Workflow
Receipt               → Document (type=receipt)
SupplierContract      → Contract (type=supplier)

Konsekvenser

Positiva

  • Ny modul definierar bara sina egna extensions i metadata, inte nya bastyper
  • AI-kontextfönster kan laddas med enhetliga objektrepresentationer
  • Korsmodulär sökning och audit fungerar utan adaptrar
  • Event-routing är självbeskrivande via subject_type

Negativa / risker

  • Migrationsarbete: Ekonomimodulen måste verifiera att befintliga tabeller uppfyller kontraktet
  • UUID v7 kräver att databasen kan generera dem (pgcrypto eller app-sida)
  • metadata jsonb kan bli en dumpingsplats — kräver disciplin och review

Implementation

Fas 1 (Ekonomimodulen, nu)

  1. Verifiera att alla tabeller har tenant_id, version, deleted_at
  2. Lägg till metadata jsonb DEFAULT '{}' på tabeller som saknar det
  3. Dokumentera mappning i modulens README

Fas 2 (inför CRM)

  1. Skapa dedikerade tabeller för Organization och Person i core-schema
  2. Ekonomimodulen FK:ar till core.organizations och core.persons

Fas 3 (plattformsnivå)

  1. GraphQL/REST-lager för kanoniska objekt
  2. Unified search-index över alla objekt
  3. AI-kontext-builder som hämtar kanonisk representation

Öppna frågor

  1. Ska kanoniska objekt bo i ett delat core-schema eller replikeras per modul?
    Förslag: Shared schema för Person, Organization, Location. Replika med CDC för moduler som behöver hög läsprestanda.

  2. UUID v7 vs ULID?
    UUID v7 är nu RFC-standard och stöds bättre i PostgreSQL-ekosystemet. ULID är alternativ om befintlig kod är svår att migrera.

  3. metadata-schemavalidering?
    Modul-specifika JSON Schema-fragment bör definieras och valideras vid INSERT/UPDATE.

  4. Event-schema-registret?
    Hermes bör ha ett schema-register som validerar event-payloads mot event_version. Se ARC-002.