#<center><H1>Nenjim<br>Documentation</H1></center>

> **Dokumentstatus:** Journal-format version 1, den immutable Java-model, den interne tekstparser, det read-only
> `JournalService`, den eksplicit refresh-baserede `JournalServiceManager` og første version af det centrale
> component Registry er implementeret. Contexts, resolution, discovery, runtime loading og removal er fortsat
> fremtidig funktionalitet.

**Indholdsfortegnelse:**
<!-- TOC -->
  * [1. Introduktion til Nenjim](#1-introduktion-til-nenjim)
  * [2. Versionering og Afhængigheder](#2-versionering-og-afhængigheder)
  * [3. Opdateringer og Sikkerhed](#3-opdateringer-og-sikkerhed)
  * [4. Betalingssystem og Integration med AssetAZ](#4-betalingssystem-og-integration-med-assetaz)
  * [5. Backing Store og Fleksibilitet](#5-backing-store-og-fleksibilitet)
  * [6. Standardiseret og Automatiseret Pakkehåndtering](#6-standardiseret-og-automatiseret-pakkehåndtering)
  * [7. Betydningen af Semantisk Versionering](#7-betydningen-af-semantisk-versionering)
  * [8. Componenter og det centrale Registry](#8-componenter-og-det-centrale-registry)
  * [9. Integration med AssetAZ og økonomisk aktivitet](#9-integration-med-assetaz-og-økonomisk-aktivitet)
<!-- TOC -->

## 1. Introduktion til Nenjim
Nenjim skal på sigt kunne håndtere forskellige versioner af softwareartifakter samtidigt. Det nu implementerede
fundament er Journal-laget: et strengt tekstformat og en immutable model, som kan fastholde, hvad der var kendt om
en artifakt på et bestemt tidspunkt. Det første Registry kan desuden katalogisere de nuværende hardcodede
componenter. Dependency-resolution, Contexts, downloading og classloading kommer senere.

## 2. Versionering og Afhængigheder
Nenjim beskriver moduler, artifakter, releases, relationer og versionspolitik i Journaler. Almindelig Java-kode skal
ikke indbygge Nenjim- eller versionsspecifikke navne for at bruge et API. Et Context beskriver de ønskede valg, og
Nenjim resolver senere disse valg og Journalernes metadata til en eksakt artifakt- og dependency-graf.

### 2.1 Én Journal per artifakt

En Journal beskriver præcis én artifakt. API, tests og referenceimplementation har derfor hver sin Journal; roller
som `API`, `IMPLEMENTATION` og `TEST` gemmes ikke som et `TYPE`-felt. Journalens identitet udledes af metadata:

```text
<GROUP>-<MODULE>-<ARTIFACT>
```

Eksempelkoordinater er `com_r35157_nenjim-hubd-api`, `com_r35157_nenjim-hubd-tests` og
`com_r35157_nenjim-hubd-impl_ref`. En komplet release-reference tilføjer en eksakt Semantic Version:

```text
com_r35157_nenjim-hubd-api:1.0.3
```

Der findes intet separat `JOURNAL_ID`.

### 2.2 Metadata og release-indhold

`[METADATA]` indeholder coordinate-delene og en obligatorisk single-quoted `DESCRIPTION`. Den valgfrie
`INFORMATION_URI` er også single-quoted, skal være en syntaktisk gyldig absolut `URI`, og kan bruge enhver scheme,
for eksempel `https:`, `ftp:` eller `ipfs:`. Nenjim åbner eller fortolker ikke URI'en automatisk.

Hver `[RELEASE major.minor.patch]` indeholder sin egen single-quoted `LICENSE`, `PUBLISHED_AT`, `CONTENT_SIZE` og
mindst én `CONTENT_DIGEST`. Format 1 accepterer valideret `sha256` og CIDv1 (`cid1`). Licensen er fri tekst, gemmes
uden normalisering og kan være forskellig mellem releases; fremtidig licensfiltrering er ikke implementeret.

### 2.3 Komplette snapshots og Journal-kæden

Hver Journal-fil er et komplet immutable snapshot af al aktuel viden om artifakten og dens kendte releases. En
revision er aldrig en delta og arver intet implicit. En nyere revision kan ændre metadata, policy, dependencies og
selv korrigere eller fjerne tidligere kendt release-information. Et no-op snapshot er også gyldigt.

`JOURNAL_VERSION` er et strengt stigende UTC-timestamp med millisekundpræcision:

```text
uuuuMMddHHmmssSSS'Z'
```

Genesis-revisionen udelader `PREVIOUS_JOURNAL_DIGEST`. Hver efterfølger refererer til SHA-256 over forgængerens
komplette UTF-8-tekst præcis som leveret, inklusive whitespace og linjeskift. Manglende forgængere, forks, flere
genesis-revisioner, fremmede artifaktkæder og ikke-stigende versioner afvises.

`PUBLISHED_AT` er release-tid og er uafhængig af Journalens publiceringstid. Historiske queries vælger et helt
snapshot ud fra Journal-kæden; de filtrerer ikke det nyeste snapshot efter `PUBLISHED_AT`.

### 2.4 Version expressions

En `SemanticVersion` (`1.0.3`) er én eksakt release. En `VersionExpression` beskriver et sæt acceptable releases:

* `1.0.3` og `[1.0.3]` er samme eksakte selector.
* `[1.0]` betyder hele den stabile `1.0.x`-serie, ikke eksakt `1.0.0`.
* `[1.0.3-->1.0.7]` inkluderer begge grænser; `)` ekskluderer øvre grænse.
* `[1.0-->1.2]` inkluderer hele `1.2.x`; `[1.0-->1.2)` gør ikke.
* `[1.0-->` stopper før `2.0.0`; `(1.0-->` starter ved `1.1.0`.
* Komma adskiller en union af expressions.

Endpoints skal mindst indeholde major og minor. Matematiske operatorer som `>=`, prereleases, build-metadata,
tomme elementer, omvendte ranges og implicitte cross-major open ranges afvises.

### 2.5 Dependencies

Dependencies hører til en bestemt artifaktrelease og bruger altid en explicit scheme. Format 1 implementerer kun:

```text
DEPENDS_ON=nenjim:com_r35157_nenjim-hubd-api=[1.0-->
EXCLUDES=nenjim:com_r35157_nenjim-hubd-api=1.0.5:'Known incompatibility'
PREFERRED=nenjim:com_r35157_nenjim-hubd-api=1.0.3:'Built together'
```

`DEPENDS_ON` er basissættet. `EXCLUDES` er en hård relationel begrænsning. `PREFERRED` er kun et hint og skal være
en delmængde af `DEPENDS_ON - EXCLUDES`. Flere exclusion/preference-linjer for samme target kombineres som union,
men deres individuelle beskrivelser bevares. Ukendte schemes, herunder `maven:`, afvises i format 1.

### 2.6 Artifact policy

Den valgfrie `[POLICY]` bevarer individuelle regler og beskrivelser:

* `BLACKLIST` er en hård global regel: matchende releases må ikke vælges.
* `DISCOURAGED` er et negativt hint: releasen kan stadig vælges.
* `RECOMMENDED` er et positivt hint til én eksakt release, som findes i samme snapshot.

Overlap er tilladt, og hårde regler vinder over hints. En fremtidig resolver bør søge en gyldig graf med flest muligt
kompatible anbefalinger; højeste versionsnummer er fallback, ikke en ubetinget regel. Det kan senere føre til
konvergens fra en højere lokal release til en lavere anbefalet release, men den adfærd er ikke implementeret nu.

### 2.7 Parser og immutable model

Parseren kræver `FORMAT_VERSION=1` som første faktiske entry, men tillader blanke linjer og `#`-kommentarer.
`#` inde i single quotes er tekst. Quoted værdier understøtter `\'` og `\\`. Ukendte, malformed, duplikerede eller
forkert placerede felter/sektioner afvises med source, linjenummer og årsag. Hele dokumentet valideres før servicens
state ændres. Alle publicerede modeller og collections er immutable og defensivt kopieret.

### 2.8 JournalService, JournalServiceManager og disk-layout

En `Service` er det domæne-API, som applikationer og andre services bruger i daglig drift. `JournalService` er derfor
filesystem-uafhængigt og read-only: det kan vise coordinates, kronologiske revisionslister, latest, exact og
newest-at-or-before snapshots samt en eksakt release fra et valgt snapshot. Det eksponerer ikke start/stop,
filesystem paths, refresh, parser eller mutation.

En `ServiceManager` ejes af en composition/lifecycle owner og håndterer start, stop, configuration/data location,
refresh og adgang til den tilhørende Service. `JournalServiceManager` ejer den normaliserede Journal-root. Ved start
læser referenceimplementationen komplette UTF-8-filer kronologisk, validerer placement/navne og gør først sit
`JournalService` tilgængeligt, når hele initial loading er lykkedes. Refresh er explicit og idempotent; der er ingen
watcher eller background polling, og stop ændrer ikke Journal-filer.

`JournalServiceImpl` vedligeholder internt kæderne og udfører atomisk ingestion med exact-text SHA-256. Identisk tekst
er idempotent; anderledes tekst med samme coordinate og Journal-version er en conflict. Parser, ingestion og mutable
chain state er implementation details og findes ikke i public signatures. Public API-pakkerne er opdelt således:

```text
com.r35157.nenjim.service.journal               JournalService, JournalServiceManager
com.r35157.nenjim.service.journal.model         sammensatte immutable domænemodeller
com.r35157.nenjim.service.journal.valuetypes    små værdidefinerede typer
com.r35157.nenjim.service.journal.exception     Journal-specifikke exceptions
com.r35157.nenjim.service.journal.impl.ref      referenceimplementation og interne helpers
```

```text
data/nenjim/journals/
└── <artifact-coordinate>/
    ├── <journal-version>.journal
    └── <journal-version>.journal.example
```

Kun `.journal` er runtime-input. `.journal.example` dokumenterer formatet og indlæses ikke. Roden skal allerede
eksistere og være læsbar; service-manageren opretter, overskriver eller sletter ikke Journal-filer.

## 3. Opdateringer og Sikkerhed
Det implementerede Journal-lag kan repræsentere nye sikkerhedsoplysninger som en nyere immutable revision, for
eksempel via `BLACKLIST` eller en ændret `RECOMMENDED`. Automatisk synchronization, selection, reconciliation og
upgrade/downgrade er fremtidigt arbejde.

## 4. Betalingssystem og Integration med AssetAZ
Betaling og AssetAZ-integration er langsigtet vision og er ikke en del af Journal-formatet eller denne implementation.

## 5. Backing Store og Fleksibilitet
Den nuværende `JournalServiceManagerImpl` læser kun det dokumenterede lokale disk-layout. Artifact downloading, IPFS retrieval,
remote Journals og andre backing stores er ikke implementeret. En `ipfs:`-værdi i `INFORMATION_URI` er metadata,
ikke en retrieval-instruks.

## 6. Standardiseret og Automatiseret Pakkehåndtering
Journalen modellerer dependency-krav og indholdsidentiteter, men downloader ikke bytes og verificerer ikke downloadet
indhold. Dependency-graph resolution, automatisk release-selection og Maven-resolution er fremtidigt arbejde.

## 7. Betydningen af Semantisk Versionering
Format 1 accepterer kun stabile eksakte releases med alle tre numeriske komponenter. Det forudsætter ikke, at en
resolver altid vælger den numerisk højeste version: hard constraints afgrænser de gyldige valg, og policy/dependency
hints kan på sigt foretrække en lavere kompatibel release.

## 8. Componenter og det centrale Registry

En Nenjim component er en færdigkonstrueret byggeklods, som er klar til brug. Rollen som service, applikation,
algoritme eller adapter bestemmes af den applikation, som bruger componenten; Registry-API'et bruger derfor det
fælles ord `component` og ikke `plugin`. `NenjimComponent` er en ren marker interface. En startbar component kan
desuden implementere `NenjimApplication`, som kun lover `start()` og ikke en fælles stop-operation.

En `NenjimComponentId` er registration metadata i ét Registry og er ikke en egenskab ved objektet. ID-formatet er
lower-case ASCII med dot-separated segments og valgfrie interne bindestreger, f.eks. `nenjim.registry.service` og
`assetaz.price-source.raydium-pool.eve-usdt`. Det samme objekt må registreres under flere forskellige ID'er, og én
registration bliver automatisk synlig gennem alle component interfaces, som objektet implementerer. Registry- og
application-view af Registry-objektet har derfor samme ID og samme object identity.

`NenjimRegistryService` er det read-only katalog, som almindelige consumers modtager gennem constructor injection.
Det kan returnere et immutable registration-order snapshot af ID'er for et component interface eller slå ét ID op
gennem et forventet interface. Et manglende ID giver `null`; et eksisterende ID med forkert interface er en caller
programming error. Public API'et kan ikke registrere eller fjerne componenter.

`NenjimRegistryServiceManagerImpl` konstruerer og starter Registry'et, registrerer Registry og manager først og
konstruerer derefter den nuværende hardcodede component graph i dependency order. Den package-private admin-view er
kun managerens registrationshandle og er hverken en component eller public API. Registration starter ikke et
objekt, og Registry'et forbliver internt åbent for senere registration efter startup.

Applikationen ejer sine konkrete valg og sin activation. Tickerens initiale configuration vælger eksplicit
`assetaz.price-source.raydium-pool.eve-usdt` gennem Registry'et; den hardcodede price source er registreret, men
inaktiv. Manageren starter kun den nuværende eksplicitte, dependency-safe liste: Ticker, Production Evelyn, Test
Evelyn, Production IOU Burner og Mission Control. Alarmen og øvrige tidligere udkommenterede applikationer bliver
ikke automatisk aktiveret. `com.r35157.nenjim.hubd.Main` er kun det yderste Java-bootstrap; `Main.main(...)` starter
manageren gennem `NenjimApplication` og er ikke selv en component eller applikation.

Det implementerede Registry er ét katalog og er ikke et authorization-system. Contexts, artifact-version semantics,
resolution, classloading, automatic discovery, public runtime loading/registration, removal, persistence, events,
automatic selection/start-all, usage tracking og permissions er fremtidigt arbejde. Journal publishing, remote
synchronization og signature validation er ligeledes ikke implementeret.

## 9. Integration med AssetAZ og økonomisk aktivitet
Økonomi, publicering og distribution er fremtidig vision. Format 1 beskriver alene artifaktviden; det indeholder
ingen betalings-, salgs- eller transaktionsadfærd.

## 10. Installation af en NenjimHub
For at NenjimHub'en kan køre godt, skal den leve i et samspil med nogle andre komponenter. Dette kan sættes op på
forskellige måder. Efterfølgende er et eksempel på en opsætning i en Virtuel Maskine, eller en lille fysisk host.
Bemærk at ECC ram er kritisk for stabiliteten, specielt hvis NenjimHub'en skal arbejde med finansielle aktiviteter.
Efterfølgende er en beskrivelse af hvordan man laver en opsætning som virker. Du kan lave specielle rettelser, hvis
du forstår hvad du laver. Det vil dog være en god idé at følge en standard opsætning, så alt bliver lidt nemmere
at styre.

## 10.1 Reference opsætning af Fysisk eller Virtuel Maskine (VM) til NenjimHub
Her beskrives hvordan man laver en standard opsætning af en NenjimHub. Denne opsætning vil også blive refereret til
som reference opsætningen, sådan at man har et fælles udgangspunkt at tale ud fra.

## 10.1.2 Minimale system krav
Det er klart at jo mere NenjimHub'en skal lave, jo større er hardware kravene, men med en 'NenjimHub Reference
Configuration', får du en opsætning der kan starte op og som du kan bygge videre fra.
Derfor er kravene til opsætningen meget moderate.
* CPU: 64bit x86
* RAM: 2GB (Helst ECC)
* Storage: 2x16GB (for RAID)
* Networking: Public IPv4 access

## 10.1.3 Basis Operativ System installation
Hvis du installerer som en VM (Proxmox), så brug følgende:
* Aktiver Qemu Agent
* Virtual Machine type: q35
* BIOS: OVMF (UEFI - med EFI disk + Pre-Enrolled keys)
* Storage: 2 x 16GB (SSD emulation + Discard)
* CPU: 2 CPU cores (type: x86-64-v2-AES)
* Memory: 2GB (Minimum 1GB + Ballooning)
* Network: Adgang til et netværk med DHCP service (Fravælg Proxmox firewall)

Installer basis Operativ System:
- Boot installations medie for Debian-13
- Vælg defaults med mindre andet angivet nedenfor
- User setup:
  - Full name: System Operator
  - Username: sysop
- Partition disks:
  - Manual
    - Lav nye tomme partitions tabeller
      - Disk 1:
        - Partition 1
          - Size: 512MB
          - Name: EFI1
          - Use as: EFI System Partition
          - Bootable: on
        - Partition 2
          - Size: 8GB
          - Name: ROOT1
          - Use as: Ext4
          - Label: ROOT
        - Partition 3
          - Size: 8.7GB (Resten af disken)
          - Name: ZFS1
          - Use as: do not use
      - Disk 2:
        - Partition 1
            - Size: 512MB
            - Name: EFI2
            - Use as: do not use
        - Partition 2
            - Size: 8GB
            - Name: ROOT2
            - Use as: do not use
        - Partition 3
            - Size: 8.7GB (Resten af disken)
            - Name: ZFS2
            - Use as: do not use
- Acceptér ikke at opsætte swap endnu.
- Software selection:
  - SSH server
  - standard system utilities
- Reboot after installation

Install additional tools:
```
$ su -
# apt-get update; apt-get install -y htop zram-tools sudo tmux
# usermod -aG sudo sysop
(Log ud og ind igen)
# sudo bash
# vi /etc/default/zramswap
(Ret PRIORITY=1)
# sed -ri'.bak' '/^deb/ { /contrib/! s/$/ contrib/ }' /etc/apt/sources.list
# apt-get update
# mokutil --sb-state || sudo apt -y install mokutil && mokutil --sb-state
# apt install -y dkms sbsigntool shim-signed mokutil
# mokutil --import /var/lib/dkms/mok.pub
(Indtast en midlertidig adgangskode)
# apt-get install -y linux-headers-amd64 zfsutils-linux zfs-dkms zfs-zed
# reboot
(Når den blå skærm kommer, vælg 'Enroll MOK' og brug nu det password du valgte ovenover)
```

Opret ZFS pool:
```
$ sudo bash
# zpool create zfspool -O xattr=sa -o ashift=12 -O compression=lz4 -O checksum=sha512 -O dedup=on -O atime=off mirror /dev/sda3 /dev/sdb3
```

Opret swap:
```
$ sudo bash
# zfs create -V 4G -o compression=zle \
      -o logbias=throughput -o sync=always \
      -o primarycache=metadata -o secondarycache=none \
      -o com.sun:auto-snapshot=false zfspool/swap
# mkswap -f /dev/zvol/zfspool/swap
# echo /dev/zvol/zfspool/swap none swap sw,pri=0 0 0 >> /etc/fstab
# swapon -av
```

Installér docker (using official repository instead of Debian repository):
```
$ sudo bash
# apt install -y apt-transport-https ca-certificates curl gpg
# curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker.gpg
# echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker.gpg] https://download.docker.com/linux/debian trixie stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# apt update
# apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# usermod -aG docker sysop
(Log out and in again)
```

Flyt docker storage til ZFS:
```
$ sudo bash
# systemctl stop docker
# zfs create -V 3G zfspool/var_lib_docker
# mkfs.ext4 /dev/zvol/zfspool/var_lib_docker
# rm -rf /var/lib/docker
# mkdir /var/lib/docker
# echo "/dev/zvol/zfspool/var_lib_docker /var/lib/docker ext4 defaults 0 2" >> /etc/fstab
# systemctl daemon-reload
# mount /var/lib/docker
# chmod 710 /var/lib/docker
# systemctl enable docker ; systemctl start docker
```

Installer ZeroTier:
```
$ sudo bash

# curl -fsSL 'https://raw.githubusercontent.com/zerotier/ZeroTierOne/main/doc/contact%40zerotier.com.gpg' | gpg --import
(Importer ZeroTier's signeringsnøgle)

# gpg --fingerprint contact@zerotier.com
(Check nøglen)

#if z=$(curl -fsSL 'https://install.zerotier.com/' | gpg --decrypt); then
  echo "$z" | sudo bash
else
  echo "Signaturtjek mislykkedes – kører ikke scriptet." >&2
  exit 1
fi
(Henter og dekryperer (verificerer) install-scriptet og kører det kun hvis signaturen er OK)
```

Konfigurer ZeroTier net:
- Login på 'https://my.zerotier.com'
- Opret et nye netværk 'Create A Network'
(Som skal forbinde terminaler og AssetAZHub)
- Klik på det nye netværk
- Basic/Name: 'assetaz-&lt;ditid&gt;'
(f.eks 'assetaz-mortengh')
- Vælg et IP range, f.eks 192.168.192.* 
- Forbind AssetAZHub til netværket (netværks id'et kan ses på websiden):
  - # zerotier-cli join a8bea75acfa45477
- Autoriser den nye maskine på nettet. Dette gøres ved at trykke på 'Edit' ved maskinen på websiden, som nu
   burde kunne se den. Autoriser den, giv den et navn og evt. en beskrivelse.
- Tryk 'Add IP' og giv den en IP adresse inden for det range du har valgt oven over (f.eks 192.168.192.1). Tryk 'Save'
- Se at AssetAZHub' nu kan pinge sig selv:
  # ping 192.168.192.1

Forbind terminal (f.eks en Android telefon)
- Installer ZeroTier-One
- Forbind til det samme net som hub'en.
- Autoriser terminalen inde på ZeroTiers web side og set terminalen ip adresse til noget kendt f.eks 192.168.192.2.
  (Så kører hub'en på *.1 og terminalen på *.2)

Opsæt locale

Opret Docker baby swarm cluster
```
```
