Skip to content

Latest commit

 

History

History
906 lines (699 loc) · 49.3 KB

File metadata and controls

906 lines (699 loc) · 49.3 KB

FreeSynergy.Node – CHANGELOG

Diese Datei wird zwischen Claude Chat und Claude Code / Editor hin- und hergereicht. Jede Änderung wird hier dokumentiert. Beim Hochladen sieht Claude sofort, was sich geändert hat.


2026-03-07 – Claude Code – fs-tui: Dashboard-Umbau (Sidebar, Projekt-Liste, Edit/Delete)

Geänderte Dateien

  • cli/crates/fs-tui/Cargo.tomltoml = { workspace = true } hinzugefügt (TOML-Parsing)
  • cli/crates/fs-tui/src/app.rsDashFocus-Enum, ProjectInfo-Struct, dirty()-Builder, edit_slug in NewProjectForm, NewProjectForm::from_project(), AppState um projects/selected_project/dash_focus/dash_confirm erweitert
  • cli/crates/fs-tui/src/lib.rsload_projects() + parse_project_toml() lesen *.project.toml beim Start
  • cli/crates/fs-tui/src/i18n.rs – Neue Schlüssel: dash.hint.services, dash.hint.confirm, dash.no_projects, dash.new_project, welcome.edit_project, form.submit.edit, sidebar.projects (DE+EN)
  • cli/crates/fs-tui/src/ui/dashboard.rs – Komplettumbau: Sidebar (22 Spalten) + Fokus-System (Sidebar/Services), Header zeigt aktives Projekt, Bestätigungsdialog fürs Löschen
  • cli/crates/fs-tui/src/ui/new_project.rs – Edit-Modus: Titel + Submit-Button abhängig von edit_slug
  • cli/crates/fs-tui/src/events.rshandle_dashboard() neu mit 2-Fokus-System, delete_selected_project(), submit_project() lädt Projektliste neu

Was sich geändert hat

  • Projekt-Sidebar: Dashboard zeigt alle Projekte aus projects/*/. ↑↓ wechselt Projekte, Tab springt zur Services-Tabelle
  • Neues Projekt aus Dashboard: n öffnet das Formular, nach Speichern kehrt man zurück
  • Projekt bearbeiten: e öffnet das Formular mit vorausgefüllten Feldern (edit_slug merkt sich den Slug)
  • Projekt löschen: x zeigt Bestätigungsdialog (gelb), J/Y löscht, N bricht ab; Verzeichnis wird entfernt
  • Focus-Highlight: Aktiver Bereich (Sidebar/Services) wird Cyan hervorgehoben
  • Header: Zeigt FSN · Name @ domain des ausgewählten Projekts

Nächster Schritt

  • Services-Aktionen implementieren (Deploy, Restart, Stop, Logs-Overlay)

2026-03-07 – Claude Code – fs-tui: Dropdown, Button-Fix, Maus-Klick, TOML-Speichern

Geänderte Dateien

  • cli/crates/fs-tui/src/app.rsslugify public gemacht, field_value() + set_select_by_index() hinzugefügt
  • cli/crates/fs-tui/src/ui/welcome.rs – Button-Breite dynamisch aus Textlänge berechnet (kein Abschneiden mehr)
  • cli/crates/fs-tui/src/ui/new_project.rs – Dropdown-Overlay für Select-Felder (List-Widget), Sprachname als Klartext (Deutsch, English, …)
  • cli/crates/fs-tui/src/events.rs – Maus-Klick auf Formularfelder + Dropdown-Klick, Submit-Handler schreibt {slug}.project.toml, handle_new_project bekommt root-Parameter
  • cli/crates/fs-tui/src/lib.rsproject_toml_exists() erkennt vorhandene Projekte → direkt zum Dashboard

Was sich geändert hat

  • Dropdown: Language-Feld zeigt beim Fokus eine Auswahlliste (▶ Deutsch, English, Français, Español, Italiano, Português)
  • Button-Breite: Welcome-Screen-Buttons berechnen ihre Breite aus dem Text — kein Abschneiden mehr
  • Maus auf Felder: Klick auf ein Feld fokussiert es direkt; Klick auf Dropdown-Eintrag wählt aus
  • TOML speichern: Auf dem letzten Tab → Enter erstellt projects/{slug}/{slug}.project.toml und wechselt zum Dashboard
  • Vorhandenes Projekt: Beim Start wird projects/ nach *.project.toml gescannt — wenn gefunden, direkt Dashboard statt Welcome

Nächster Schritt

  • Dashboard: Neues Projekt anlegen + Bearbeiten + Löschen von bestehenden Projekten

2026-03-07 – Claude Code – fs-tui: Form-Umbau, Ctrl-Navigation, Smart Defaults

Geänderte Dateien

  • cli/crates/fs-tui/src/app.rs – Server-Tab entfernt (2 Tabs: Projekt + Optionen). Description in Projekt-Tab. dirty-Flag pro Feld. on_field_changed() + sync_email_from_domain() für Auto-Defaults. slugify(). ctrl_hint: bool in AppState
  • cli/crates/fs-tui/src/events.rs – ESC schließt Modal (nicht mehr Tab-by-Tab). Ctrl+←/→ = Tab wechseln. Ohne Ctrl = Cursor im Text. ctrl_hint wird bei jedem Tastendruck aktualisiert
  • cli/crates/fs-tui/src/i18n.rsform.hint.ctrl hinzugefügt. form.hint aktualisiert (^=Strg). Server-Schlüssel entfernt, form.project.description neu
  • cli/crates/fs-tui/src/ui/new_project.rs – Hint-Bar: wechselt auf Ctrl-Shortcuts wenn ctrl_hint=true
  • projects/FreeSynergy.Net/freesynergy.project.yml – gelöscht (nicht mehr gebraucht)
  • projects/FreeSynergy.Net/freesynergy.federation.yml – gelöscht

Was sich geändert hat

  • Server-Tab aus Neues-Projekt-Formular entfernt (gehört in Host-Konfiguration, nicht in Projekt)
  • Projekt-Tab: Name + Domain (auto) + Beschreibung + E-Mail (auto)
  • Optionen-Tab: Sprache + Installationsverzeichnis + Version
  • Smart Defaults: Domain wird aus Projektname abgeleitet (Slugify), E-Mail aus Domain (admin@domain) — solange der User das Feld nicht selbst bearbeitet hat
  • ESC schließt Modal sofort (Daten bleiben in State erhalten)
  • Ctrl+← / Ctrl+→ wechseln zwischen Tabs
  • Hint-Bar zeigt Ctrl-Shortcuts wenn Strg gedrückt wird

Nächster Schritt

  • Submit-Handler: Verzeichnis + project.toml schreiben

2026-03-07 – Claude Code – fs-tui: UX-Verbesserungen (Zentrierung, Maus, Validierung)

Geänderte Dateien

  • cli/crates/fs-tui/src/ui/welcome.rs – Sysinfo-Box: Max(74) + Fill(1) statt Percentage → zentriert. Branding: „FreeSynergy.Node · by KalEl"
  • cli/crates/fs-tui/src/app.rstab_missing_count(), Event-Loop: Event::Mousehandle_mouse()
  • cli/crates/fs-tui/src/events.rs – Maus: ScrollUp/Down für Logs + Select. ESC geht Tab-weise zurück. Tab-Wechsel blockiert wenn Pflichtfelder fehlen
  • cli/crates/fs-tui/src/lib.rsEnableMouseCapture / DisableMouseCapture

Was sich geändert hat

  • Sysinfo-Box ist zentriert
  • Maus: Scrollrad für Logs/Select, Klick auf Sprach-Button
  • Pflichtfelder müssen vor Tab-Wechsel ausgefüllt sein
  • ESC geht schrittweise zurück (Daten bleiben erhalten)
  • Branding im Header

Nächster Schritt

  • Submit-Handler: Verzeichnis + project.toml + host.toml schreiben

2026-03-07 – Claude Code – fs-tui: New-Project-Formular vollständig

Geänderte Dateien

  • cli/crates/fs-tui/src/app.rsScreen::NewProject, FormTab, FormFieldType, FormField, NewProjectForm mit 10 Feldern (3 Tabs), Cursor-Navigation, Select-Cycling, Validierung. Neu: delete_char(), cursor_home(), cursor_end(), select_prev()
  • cli/crates/fs-tui/src/events.rs – Vollständiges Tastatur-Handling für Screen::NewProject: Tab/BackTab (Feld-Navigation), ←→ (Tab wechseln / Cursor), ↑↓ (Select-Cycling), Enter (nächster Tab / Submit), Backspace/Delete/Home/End, Esc (zurück zu Welcome). Welcome-Screen: Enter → Screen::NewProject
  • cli/crates/fs-tui/src/ui/new_project.rs – Neu: Formular mit ratatui Tabs-Widget (3 Tabs), Pflichtfeld-Marker *, Cursor als , Hinweis-Text, ⚠ auf Tabs mit fehlenden Feldern, Submit-Button auf Options-Tab
  • cli/crates/fs-tui/src/ui/welcome.rs – Sysinfo-Block mit fixer Spaltenbreite (18/18/14 Zeichen), bündig ausgerichtet
  • cli/crates/fs-tui/src/i18n.rs – Alle form.* Schlüssel (DE + EN): form.tab.*, form.project.*, form.server.*, form.options.*, form.hint, form.required, form.submit

Was sich geändert hat

  • Welcome → Enter auf „Neues Projekt" → Formular mit 3 Tabs öffnet sich
  • Pflichtfelder (markiert mit *): name, domain, path, email (Tab Projekt); host_ip, dns_provider, dns_api_token (Tab Server)
  • Optionale Felder (Tab Optionen): description, language (Select), version
  • Sprache jederzeit mit L umschalten (auch im Formular)
  • Submit nur aktiv wenn alle Pflichtfelder ausgefüllt
  • Tabs zeigen ⚠ wenn zugehörige Pflichtfelder leer sind

Offene Probleme

  • Keine — cargo build sauber

Nächster Schritt

  • Submit-Handler: Projekt-Verzeichnis anlegen, project.toml schreiben (Phase 2)

2026-03-07 – Claude Code – KDL in Deploy-Loop + setup.fields für fehlende Module

Geänderte Dateien

  • cli/crates/fs-engine/src/deploy.rs – Phase 5 nach dem Service-Deploy: write_zentinel_kdl() schreibt {data_root}/{proxy_name}/config/zentinel.kdl. Neue Datei → generate_full_config(), vorhandene Datei → upsert_managed_section() (nur FSN-Block wird ersetzt)
  • modules/chat/tuwunel/tuwunel.toml[[setup.fields]] für tuwunel_allow_registration (bool, default false) und tuwunel_allow_federation (bool, default true) hinzugefügt
  • modules/collab/cryptpad/cryptpad.toml[[setup.fields]] für cryptpad_admin_email (email) hinzugefügt
  • modules/mail/stalwart/stalwart.toml[[setup.fields]] für stalwart_admin_password (secret, auto_generate) hinzugefügt

Was sich geändert hat

  • fsn deploy schreibt nach jedem Deploy automatisch die Zentinel KDL-Konfiguration. Manuell editierte Bereiche (oberhalb/unterhalb der FSN-Marker) bleiben unberührt.
  • Alle 14 Module haben jetzt .toml Dateien (waren schon vorhanden). 9 Module haben [[setup.fields]] — der fsn init-Wizard fragt die richtigen Secrets automatisch ab.

Stand der Module mit setup.fields

Modul Felder
postgres vault_db_password (secret, auto)
dragonfly vault_dragonfly_password (secret, auto)
umap
forgejo vault_forgejo_secret_key, vault_forgejo_db_password
openobserver vault_zo_root_user_email, vault_zo_root_user_password
pretix vault_pretix_secret_key, vault_pretix_db_password
vikunja vault_vikunja_jwt_secret, vault_vikunja_db_password, vault_vikunja_redis_password
outline 4 Felder (secret keys + S3)
tuwunel allow_registration, allow_federation
cryptpad admin_email
stalwart admin_password

Offene Probleme

  • Keine — cargo build sauber

Nächster Schritt

  • fsn init testen mit einem echten Projekt
  • TUI: Deploy-Aktion wirklich async ausführen

2026-03-07 – Claude Code – fs-tui: Terminal-UI-Dashboard (ratatui)

Neue Dateien

  • cli/crates/fs-tui/Cargo.toml – neues Crate, Dependencies: ratatui/crossterm/sysinfo/fs-core/fs-engine
  • cli/crates/fs-tui/src/lib.rs – Einstieg run(root): Terminal-Init, Service-Erkennung, Event-Loop-Start
  • cli/crates/fs-tui/src/app.rsAppState, Screen/Lang/ServiceStatus-Enums, Event-Loop (run_loop)
  • cli/crates/fs-tui/src/i18n.rs – Compile-time DE/EN Strings (t(lang, key)), ca. 30 Schlüssel pro Sprache
  • cli/crates/fs-tui/src/sysinfo.rsSysInfo::collect(): Hostname, User, IP, RAM, CPU, Uptime, Podman-Version, Arch
  • cli/crates/fs-tui/src/events.rs – Tastaturhandling: Welcome (Tab=Sprache, Enter, q), Dashboard (↑↓, d/r/x/l, q), Logs-Overlay
  • cli/crates/fs-tui/src/ui/mod.rs – Screen-Dispatch + Overlay-Rendering
  • cli/crates/fs-tui/src/ui/welcome.rs – Welcome-Screen (Header, Systeminfo-Grid 2-spaltig, Buttons)
  • cli/crates/fs-tui/src/ui/dashboard.rs – Dashboard (Header + [DE] Button, Sidebar, Services-Tabelle mit Status-Badges)
  • cli/crates/fs-tui/src/ui/logs.rs – Logs-Overlay (Modal-Popup, Podman-Logs, Scroll)
  • cli/crates/fs-tui/src/ui/widgets.rs – Hilfsfunktionen: lang_button, status_span, popup_area, button_line
  • cli/crates/fs-cli/src/commands/tui.rspub async fn run(root) → fs_tui::run(root)

Geänderte Dateien

  • cli/Cargo.tomlfs-tui zu workspace members; ratatui/crossterm/sysinfo zu workspace.dependencies
  • cli/crates/fs-cli/Cargo.tomlfs-tui = { workspace = true }
  • cli/crates/fs-cli/src/cli.rsCommand::Tui + Dispatch zu commands::tui::run
  • cli/crates/fs-cli/src/commands/mod.rspub mod tui;

Was die TUI kann (Phase 1)

  • Welcome-Screen (kein Projekt): Systeminfo (Host, User, IP, RAM, CPU, Podman, Uptime, Arch), Sprachauswahl via Tab (DE/EN live), Buttons „Neues Projekt" / „Vorhandenes Projekt" (ausgegraut)
  • Dashboard (Projekt vorhanden): Sidebar, Services-Tabelle (Name, Typ, Domain, Status mit Farbe), Cursor-Navigation ↑↓
  • Aktionen: d=Deploy-Markierung, r=Restart via podman, x=Remove, l=Logs-Overlay öffnen
  • Logs-Overlay: Podman-Logs (100 Zeilen), scrollbar, q=Schließen
  • Sprachenwechsel: Tab jederzeit, sofortige UI-Aktualisierung (DE/EN)
  • Auto-Refresh: Systeminfo alle 5 Sekunden

Offene Probleme / TODO für Phase 2

  • Deploy-Aktion (d) spawnt noch keinen echten Deploy — markiert nur als Unknown (Async-Task folgt)
  • fsn tui → Enter auf „Neues Projekt" → Wizard noch nicht inline (beendet aktuell die TUI, fsn init danach)
  • Service-Typ und Domain aus project.toml lesen (aktuell: Podman ps -a Ausgabe, Domain Placeholder)
  • Projekt-Switching (mehrere Projekte) folgt in Phase 2

Nächster Schritt

  • KDL in deploy.rs einbauen
  • postgres-Modul nach TOML konvertieren

2026-03-07 – Claude Code – Zentinel KDL-Generator (echtes Pingora-Format)

Geänderte Dateien

  • cli/crates/fs-engine/src/generate/kdl.rs – komplett neu geschrieben: echtes Zentinel KDL-Format (Pingora, nicht Caddy), upstreams {} und routes {} Top-Level-Blöcke, upsert_managed_section() (markers-basiertes In-Place-Update), generate_full_config() (Erstinstallation mit listeners-Block), collect_proxy_instances() (überspringt Database/Cache/Proxy), Alias-Domains bekommen eigene route-Blöcke
  • README.md – Zentinel korrekt als Pingora beschrieben (war noch Caddy-Referenz drin)
  • CHANGELOG.md – dieses Update

Was sich geändert hat

  • Altes Format (Caddy-Stil): domain { reverse_proxy name:port } — falsch
  • Neues Format (echtes Zentinel KDL): upstream "name" { targets { target { address "name:port" } } } + route "name" { matches { host "…" } upstream "name" }
  • Gesamte FSN-managed Section wird bei jedem Deploy neu generiert (zwischen # === FSN-MANAGED-START === / # === FSN-MANAGED-END ===)
  • Manuell editierte Bereiche außerhalb der Marker bleiben unberührt

Offene Probleme

  • Zentinel TCP-Syntax (Mail: SMTP/IMAP/JMAP) noch nicht implementiert — Pingora unterstützt TCP (laut Entwickler bestätigt), genaue KDL-Syntax noch unbekannt → wird als Stub ergänzt sobald bestätigt

Nächster Schritt

  • deploy.rs: kdl::upsert_managed_section() in den Deploy-Loop einbauen (nach Quadlet-Generation)
  • TUI mit ratatui

2026-03-07 – Claude Code – Datenstruktur: Module → Service + Ansible-Entfernung + Build-Fix

Geänderte Dateien

  • cli/crates/fs-core/src/config/service.rs – neu (umbenannt von module.rs): ServiceType-Enum (Iam, Proxy, Mail, Git, Wiki, Chat, Collab, Tasks, Tickets, Maps, Monitoring, Database, Cache, Bot, Custom), ServiceClass.meta (serde rename „module"), ServiceMeta.service_type (serde rename „type"), ServiceLoad.sub_services (alias „modules"), Backward-Compat-Aliases für alle umbenannten Felder
  • cli/crates/fs-core/src/config/project.rsServiceSlots (iam/mail/wiki/git/chat/collab/tasks/monitoring/extra), ProjectMeta bekommt version/language/languages, ProjectLoad.services (alias „modules"), ServiceEntry (war ModuleRef) mit alias für module_class, type ModuleRef = ServiceEntry für Rückwärtskompatibilität
  • cli/crates/fs-core/src/state/desired.rsDesiredState.services (war .modules), ServiceInstance bekommt service_type: ServiceType, sub_services (war sub_modules)
  • cli/crates/fs-core/src/config/mod.rspub mod service statt pub mod module, alle Exporte aktualisiert
  • cli/crates/fs-engine/src/resolve.rs.modules.services, .module.alias.meta.alias, class.load.servicesclass.load.sub_services, service_type zu ServiceInstance-Initializer hinzugefügt
  • cli/crates/fs-engine/src/constraints.rs – Import config::module::Localityconfig::service::Locality
  • cli/crates/fs-engine/src/setup.rs – Import config::module::SetupFieldconfig::service::SetupField
  • cli/crates/fs-web/src/api.rs – Import config::module::FieldTypeconfig::service::FieldType
  • cli/crates/fs-cli/src/commands/init.rs – Import config::module::FieldTypeconfig::service::FieldType
  • cli/crates/fs-cli/src/commands/deploy.rsmodules-Variable → services, DesiredState { services, .. }
  • cli/Cargo.tomlfs-ansible aus Workspace entfernt, libc hinzugefügt
  • playbooks/ – vollständig entfernt (25 Dateien, 11 Unterverzeichnisse)
  • .ansible-lint, .yamllint.yml, .ansible/, requirements.yml – entfernt
  • README.md – komplett neu geschrieben: Ansible raus, Rust CLI, Services statt Modules, Zentinel korrekt als Pingora, aktueller Status

Was sich konzeptuell geändert hat

  • Module → Service: Alle Typen intern umbenannt. TOML-Dateien auf Disk bleiben kompatibel (Backward-Compat via serde aliases).
  • Ansible vollständig entfernt: Deployment läuft jetzt ausschließlich über den Rust-CLI (fsn).
  • ServiceType-System: Typed Slots im Projekt ([services] iam="kanidm" mail="stalwart").

Offene Probleme

  • Keine — cargo build ist sauber

Nächster Schritt

  • Zentinel KDL-Generator (korrektes Pingora-KDL-Format mit upstreams {} und routes {})

2026-03-06 – Claude Code – Installer: CoreOS-Fix + Wizard-Reihenfolge + UX

Was fehlte / falsch war:

  • Fedora CoreOS hat ID=fedora in /etc/os-release → wurde als dnf erkannt → install_pkg schlug auf CoreOS fehl (kein dnf)
  • Repo wurde vor dem Wizard geklont → Benutzer musste warten, bevor er Fragen beantworten konnte
  • Modulauswahl las aus ${FS_ROOT}/modules/ → benötigte geklontes Repo (Henne-Ei-Problem)
  • DNS-Token: kein Feedback nach stiller Eingabe → Benutzer wusste nicht ob Token gespeichert wurde
  • [?] Präfix und "Enter to skip" für Pflichtfeld verwirrend
  • Kein Install-Verzeichnis im Wizard gefragt
  • Sub-Module (postgres, dragonfly) in Modulauswahl sichtbar

Geänderte Dateien:

  • fs-install.sh – CoreOS-Erkennung via rpm-ostree vor OS-Detection; install_pkg mit rpm-ostree-Case; hardcodierte FS_MODULES_BUILTIN-Liste (kein Repo nötig); Wizard läuft in Phase 1 (vor Downloads); statt [?]; DNS-Token-Bestätigung nach stiller Eingabe; Install-Verzeichnis im Wizard; Sub-Module ausgeblendet; show_setup_summary zeigt Token-Status

2026-03-06 – Claude Code – Installer: ACME-Email + DNS-Token in Vault

Was fehlte:

  • Installer hat nie nach der ACME-E-Mail gefragt → Let's Encrypt ohne Benachrichtigungsadresse
  • vault_hetzner_dns_token wurde in vault.yml.j2 als "CHANGE_ME" gerendert, obwohl der Token aus dem Installer-Wizard bekannt war → manuelle Deployments ohne -e @secrets.yml hätten keinen DNS-Token

Geänderte Dateien:

  • fs-install.sh – E-Mail-Frage nach Domain-Eingabe; E-Mail in Summary; in generate_project_yml() als project.contact.acme_email geschrieben; PROJECT_EMAIL Default in main()
  • playbooks/templates/vault.yml.j2 – DNS-Tokens nutzen {{ vault_hetzner_dns_token | default('CHANGE_ME') }} → echter Token wird bei erstem Install-Lauf direkt eingebaut

2026-03-06 – Claude Code – DNS-Vars-Fix in Stack-Playbooks

Was fehlte: Die Zentinel-Deploy-Hook deploy-dns.yml referenziert project_services, dns_provider und dns_api_token – diese Variablen wurden in keinem Stack-Playbook gesetzt. DNS-Hooks wären sofort mit undefined variable fehlgeschlagen.

Geänderte Dateien:

  • playbooks/deploy-stack.ymldns_provider (aus Host-Datei), dns_api_token (aus Vault), project_services (Liste aller Top-Level-Module) hinzugefügt
  • playbooks/undeploy-stack.yml – Host-Datei lesen + dieselben DNS-Vars gesetzt (für undeploy-dns.yml Hook beim Stoppen)
  • playbooks/remove-stack.yml – Gleicher Block wie undeploy (konsistent + future-proof)

Details:

  • dns_provider kommt aus host_cfg.host.proxy.zentinel.load.plugins.dns (z.B. "hetzner")
  • dns_api_token wird daraus abgeleitet: hetzner → vault_hetzner_dns_token, cloudflare → vault_cloudflare_api_token
  • project_services = Liste von {subdomain: <key>, aliases: []} für alle Module aus project_cfg.load.modules

2026-03-06 – Claude Code – Ansible Collections + Installer Fix

Neue Datei:

  • requirements.yml – Deklariert ansible.posix (≥1.5) und community.general (≥8.0)

Geänderte Datei:

  • fs-install.shinstall_collections() Funktion hinzugefügt; wird nach fetch_platform aufgerufen

Was das behebt: setup-server.yml benutzt ansible.posix.sysctl und community.general.pacman. Ohne Collections schlägt der Setup-Step komplett fehl. Jetzt werden sie automatisch via ansible-galaxy collection install -r requirements.yml installiert.


2026-03-06 – Claude Code – Playbook Architektur-Review: 11 Dateien

Kritischer Bug behoben – set_fact scope in deploy-module.yml: Ansible set_fact ist global. Sub-Module (z.B. forgejo-postgres) überschreiben beim rekursiven deploy-module.yml-Aufruf die Variablen des Parents (instance_name, module_cfg, container, module_environment). Folge: das Quadlet der App (z.B. forgejo) wurde mit dem Container-Namen des letzten Sub-Moduls generiert. Fix: nach dem Sub-Module-Loop werden module_cfg neu eingelesen und alle betroffenen Vars via module_entry (Loop-Variable – wird von set_fact NICHT überschrieben) neu gesetzt.

Gleicher Fix in update-module.yml und restart-module.yml (Sub-Modul-Rekursion kommt dort ebenfalls vor Parent-Operationen).

Sub-Module-Rekursion in allen Lifecycle-Tasks:

  • update-module.yml – Sub-Module werden jetzt zuerst aktualisiert
  • undeploy-module.yml – Sub-Module stoppen NACH dem Parent (Parent gibt Connections frei)
  • remove-module.yml – Sub-Module werden NACH dem Parent gelöscht
  • restart-module.yml – Sub-Module starten VOR dem Parent (Connections müssen bereit sein)

vault.yml konsistent in allen Stack-Playbooks geladen:

  • update-stack.yml – vault.yml + project_domain hinzugefügt
  • restart-stack.yml – vault.yml + project_domain hinzugefügt
  • undeploy-stack.yml – vault.yml hinzugefügt
  • remove-stack.yml – vault.yml + project_domain hinzugefügt

clean-module.yml: Löscht jetzt auch data/ und configs/ für verwaiste Module (vorher nur Quadlet-Dateien).

Geänderte Dateien (11): tasks/deploy-module.yml, tasks/update-module.yml, tasks/undeploy-module.yml, tasks/remove-module.yml, tasks/restart-module.yml, tasks/clean-module.yml, update-stack.yml, restart-stack.yml, undeploy-stack.yml, remove-stack.yml


2026-03-06 – Claude Code – Code-Review Fixes: 6 Fehler behoben

Geänderte Dateien:

  • modules/tickets/pretix/pretix.ymlvault_dragonfly_passwordservices.dragonfly.vault_cache_password; DB → services.postgres.*
  • modules/tasks/vikunja/vikunja.ymlvault_dragonfly_passwordservices.dragonfly.vault_cache_password
  • playbooks/templates/vault.yml.j2vault_pretix_db_password entfernt; vault_vikunja_mailer_* und vault_pretix_mail_* als optionale Leer-Felder ergänzt
  • modules/proxy/zentinel/zentinel-control-plane/zentinel-control-plane.ymlhealthcheck Block hinzugefügt
  • playbooks/tasks/generate-single-example.yml – Bug: tpl_environmentmodule_environment
  • playbooks/tasks/deploy-module.ymlcontainer_dependencies bei Quadlet-Generierung gesetzt

Was die Fixes beheben:

  1. pretix/vikunja: Dragonfly-Verbindung funkioniert jetzt (richtiger Variablenname)
  2. pretix: DB-Passwort stimmt mit postgres-Container überein
  3. zentinel-control-plane: Healthcheck war als einziges Modul fehlend
  4. Config-Beispiele enthalten jetzt alle Umgebungsvariablen (waren leer)
  5. Systemd-Startup-Reihenfolge: Sub-Module starten VOR der App (After=/Requires=)

2026-03-06 – Claude Code – Blocker-Fixes: vault.yml-Generierung, cache-Passwort, umap DB

Neue Datei:

  • playbooks/templates/vault.yml.j2 – Vault-Template mit auto-generierten Passwörtern (einmalig, idempotent)

Geänderte Dateien:

  • playbooks/install-project.yml – Generiert projects/<name>/vault.yml wenn nicht vorhanden (chmod 600)
  • playbooks/tasks/resolve-service.yml – Fügt vault_cache_password ins services-Dict ein (war vergessen)
  • modules/maps/umap/umap.ymlDATABASE_URL und REDIS_URL nutzen jetzt services.*.vault_* statt eigene vault-Variablen

Was die Fixes beheben:

  1. vault.yml wird beim install einmalig auto-generiert; Passwörter sind sofort einsatzbereit
  2. services.cache.vault_cache_password ist jetzt auflösbar (Forgejo, Outline, Vikunja, Pretix)
  3. umap's postgres-Passwort stimmt jetzt mit dem postgres-Container überein (war: vault_umap_db_password vs. vault_db_password)

2026-03-05 – Claude Code – Bugfixes: services-Dict, environment-Template, postgres

Neue Datei:

  • playbooks/tasks/resolve-service.yml – Liest Sub-Modul-YAML (port, db_name) und baut services-Dict

Geänderte Dateien:

  • playbooks/tasks/deploy-module.yml – Baut services-Dict vor Sub-Modul-Deployment (sub-modules + externe Abhängigkeiten)
  • playbooks/templates/container.quadlet.j2 – Bug: environment.items()module_environment.items() (environment ist reserviertes Ansible-Keyword)
  • playbooks/templates/container.env.j2 – Bug: tpl_environment.items()module_environment.items()
  • modules/database/postgres/postgres.yml – Bug: {{ vars.db_name }}{{ module_vars.db_name }} (vars ist reserviert)

Was die Fixes beheben:

  • services.kanidm.domain, services.postgres.container_name etc. sind jetzt auflösbar – OIDC-Konfigurationen aller Module funktionieren
  • Quadlet-Dateien schreiben jetzt korrekt die Modul-Env-Variablen (statt Shell-Umgebungsvariablen)
  • .env-Dateien für Systemd werden korrekt generiert
  • Postgres-Container startet mit korrekten DB_NAME / DB_USER

Symlink: playbooks/tasks/tasks/resolve-service.yml → ansible-lint-Workaround

ansible-lint: 0 Fehler, 0 Warnungen (74 Dateien, Production Profile) ansible --syntax-check: deploy-stack, sync-stack, update-stack – alle sauber


2026-03-04 – Claude Code – Zentinel KDL Marker-System implementiert

Geänderte Datei:

  • modules/proxy/zentinel/playbooks/deploy-kdl.yml – Komplett neu geschrieben

Neue Dateien:

  • modules/proxy/zentinel/templates/zentinel-global.kdl.j2 – Globale Einstellungen (nur bei Erstanlage)
  • modules/proxy/zentinel/templates/zentinel-block-l7.kdl.j2 – L7 HTTPS Route (ein Service)
  • modules/proxy/zentinel/templates/zentinel-block-mail.kdl.j2 – Stalwart TCP + HTTPS
  • modules/proxy/zentinel/templates/zentinel-block-sandbox.kdl.j2 – CryptPad Sandbox-Domain
  • modules/proxy/zentinel/templates/zentinel-block-static.kdl.j2 – Root-Domain / Landing Page

Entfernte Datei:

  • modules/proxy/zentinel/templates/zentinel.kdl.j2 – Ersetzt durch Block-Templates

Was sich ändert:

  • Vorher: Komplette KDL-Datei wurde bei jedem Deploy überschrieben (Control-Plane-Änderungen gingen verloren)
  • Jetzt: Jeder Service hat seinen eigenen FSN-MANAGED-START/END Block; Deployer berührt nur diese Blöcke
  • Neue Services: Block wird hinzugefügt
  • Geänderte Services: Block wird aktualisiert (in-place)
  • Entfernte Services: Block wird automatisch gelöscht (Reconcile)
  • Alles außerhalb der Marker: unberührt (Control-Plane owned)
  • Hot-Reload: Zentinel wird nur reloaded wenn die Datei sich tatsächlich geändert hat (sha256-Diff)

ansible-lint: 0 Fehler, 0 Warnungen (73 Dateien, Production Profile)


2026-03-04 – Claude Code – README.md erstellt

Neue Datei:

  • README.md – Public-facing Projektbeschreibung für GitHub

Inhalt:

  • Philosophie und Projektziel (Dezentralisierung, freiwillige Kooperation)
  • Modulübersicht (alle 14 Module mit Kategorie und Beschreibung)
  • Drei-Schichten-Architektur (modules / hosts / projects)
  • Deployment-Flow von fs-install.sh bis DNS
  • Sicherheitsmodell (rootless, nur Zentinel extern)
  • Projektstatus-Tabelle mit aktuellem Stand
  • Requirements und Quick Start
  • Hinweis auf FreeSynergy.Net als Referenz-Deployment
  • Verlinkung auf LICENSE und contributors.md


2026-03-04 – Claude Code – DNS Rename-Cleanup (Reconcile + Explicit Cleanup)

Neue / geänderte Dateien

playbooks/tasks/dns-cleanup-module.yml (neu) Löscht alle DNS-Records eines Moduls anhand der State-File. Verwendet record_id aus dem State-File für direkten DELETE-Aufruf (kein Zone-Lookup nötig). Idempotent: 404 vom Provider wird als Erfolg gewertet.

Variablen: dns_state_file, dns_cleanup_module, dns_provider, dns_api_token

modules/proxy/zentinel/playbooks/deploy-dns.yml (Reconcile hinzugefügt) Vor jedem Deploy werden veraltete Records automatisch bereinigt:

  1. State-File laden → alle Records für proxy/zentinel ermitteln
  2. Erwartete FQDNs aus aktueller Config berechnen
  3. Records die in State-File stehen aber NICHT mehr erwartet werden → DELETE
  4. State-File aktualisieren → dann normale Record-Erstellung (A, AAAA, CNAME)

Effekt: Service von chatmatrix umbenennen, deploy-stack.yml ausführen → chat.freesynergy.net wird automatisch gelöscht, matrix.freesynergy.net erstellt.

Neue Symlinks (ansible-lint Workaround)

  • modules/proxy/zentinel/playbooks/tasks/dns-cleanup-module.yml
  • playbooks/tasks/tasks/dns-cleanup-module.yml

Architektur

  • Reconcile on deploy (automatisch): Rename-Cleanup beim nächsten deploy-stack.yml
  • Explicit cleanup (dns-cleanup-module.yml): Für manuelles Löschen / remove-stack.yml
  • State-File ist die Quelle der Wahrheit für "was haben wir erstellt"

Noch offen

  • remove-stack.yml / undeploy-stack.yml: noch kein expliziter dns-cleanup-module.yml Aufruf

2026-03-01 – Claude Code – Install-Wizard + DNS State Tracking

Neue / geänderte Dateien

fs-install.sh (kompletter Rewrite) Interaktiver Setup-Wizard für neue Installationen:

  • list_available_modules() – scannt modules/ Verzeichnis (zeigt alle verfügbaren Module)
  • select_dns_provider() – Auswahl Hetzner/Cloudflare + Token-Eingabe via read -rs
  • select_acme_provider() – Auswahl letsencrypt/smallstep-ca
  • select_modules() – nummerierte Liste, Eingabe als space-separated Nummern oder all
  • detect_server_ip() – automatisch via ip route get 1.1.1.1
  • generate_project_yml() – schreibt projects/NAME/NAME.project.yml
  • generate_host_yml() – schreibt hosts/HOSTNAME.host.yml (DNS + ACME Provider eingebaut)
  • show_setup_summary() – zeigt Zusammenfassung vor Deployment
  • import_config() – importiert externes project.yml (--config FILE)
  • collect_secrets() – Provider-aware, nutzt DNS_TOKEN aus Wizard wieder

Drei Modi in main():

  1. --config FILE → Import + direkt deployen
  2. --project FILE → Bereits platziert, nur deployen
  3. Kein Flag → Interaktiver Wizard

Neue Flags: --config FILE

playbooks/tasks/dns-create-record.yml (State Tracking hinzugefügt)

  • Schreibt nach erfolgreicher Erstellung in .dns-managed.yml
  • Erfasst: zone, type, name, fqdn, value, provider, record_id, module

playbooks/tasks/dns-remove-record.yml (State Tracking hinzugefügt)

  • Entfernt nach erfolgreicher Löschung den Eintrag aus .dns-managed.yml

modules/proxy/zentinel/playbooks/deploy-dns.yml (State Tracking aktiviert)

  • Übergibt dns_state_file und dns_state_module an die Task-Files

modules/proxy/zentinel/playbooks/undeploy-dns.yml (Bugfix + State Tracking)

  • dns_api_url entfernt (war noch aus altem Interface übrig)
  • dns_zone: "{{ project_domain }}" hinzugefügt (war fehlend)
  • dns_state_file + dns_state_module hinzugefügt

DNS State File (.dns-managed.yml)

Neue Tracking-Datei unter projects/<name>/.dns-managed.yml:

records:
  - zone: "freesynergy.net"
    type: "A"
    name: "chat"
    fqdn: "chat.freesynergy.net"
    value: "1.2.3.4"
    provider: "hetzner"
    record_id: "abc123"
    module: "proxy/zentinel"

Wird automatisch bei deploy/undeploy aktuell gehalten. Zweck: sicheres Cleanup bei Modul-Rename / -Remove (state file als Quelle statt aktueller Config).

Noch offen

  • stalwart/playbooks/deploy-dns.yml: MX/SPF/SRV Records noch nicht implementiert
  • Cloudflare-Support: geplant für v0.2
  • Rename-Scenario: undeploy liest noch aus Projekt-Config, nicht aus State-File (TODO: dns-cleanup-module.yml – löscht alle Records eines Moduls via State-File)

2026-03-01 – Claude Code – author-Feld in allen Modulen umbenannt

Geänderte Dateien

  • modules/tickets/pretix/pretix.ymlauthor: "FSN Platform" -> author: "FreeSynergy.Node"
  • modules/tasks/vikunja/vikunja.ymlauthor: "FSN Platform" -> author: "FreeSynergy.Node"
  • modules/database/postgres/postgres.ymlauthor: "FSN Platform" -> author: "FreeSynergy.Node"
  • modules/mail/stalwart/stalwart.ymlauthor: "FSN Platform" -> author: "FreeSynergy.Node"
  • modules/chat/tuwunel/tuwunel.ymlauthor: "FSN Platform" -> author: "FreeSynergy.Node"
  • modules/observability/otel-collector/otel-collector.ymlauthor: "FSN Platform" -> author: "FreeSynergy.Node"
  • modules/collab/cryptpad/cryptpad.ymlauthor: "FSN Platform" -> author: "FreeSynergy.Node"
  • modules/wiki/outline/outline.ymlauthor: "FSN Platform" -> author: "FreeSynergy.Node"
  • modules/observability/openobserver/openobserver.ymlauthor: "FSN Platform" -> author: "FreeSynergy.Node"
  • modules/git/forgejo/forgejo.ymlauthor: "FSN Platform" -> author: "FreeSynergy.Node"
  • modules/maps/umap/umap.ymlauthor: "FSN Platform" -> author: "FreeSynergy.Node"
  • modules/cache/dragonfly/dragonfly.ymlauthor: "FSN Platform" -> author: "FreeSynergy.Node"
  • modules/proxy/zentinel/zentinel.ymlauthor: "FSN Platform" -> author: "FreeSynergy.Node"
  • modules/auth/kanidm/kanidm.ymlauthor: "FSN Platform" -> author: "FreeSynergy.Node"
  • modules/proxy/zentinel/zentinel-control-plane/zentinel-control-plane.ymlauthor: "FSN Platform" -> author: "FreeSynergy.Node"

Offene Probleme

  • Keine

Naechster Schritt

  • Keine weiteren Schritte erforderlich

2026-03-01 – Claude Code – DNS-Implementierung (Hetzner API)

Neue/geänderte Dateien

playbooks/tasks/dns-create-record.yml (implementiert)

  • Hetzner DNS API: Zone-Lookup → Record-Check (idempotent) → Record-Create
  • Variable dns_zone (neu, Pflicht): Root-Domain z.B. "freesynergy.net"
  • Variable record_name: voller FQDN, relativer Name wird automatisch abgeleitet
  • Cloudflare: fail-fast Hinweis (geplant für spätere Version)
  • Idempotent: überspringt vorhandene Records (gleicher Typ + Name)

playbooks/tasks/dns-remove-record.yml (implementiert)

  • Hetzner DNS API: Zone-Lookup → Record-Find → DELETE
  • Idempotent: kein Fehler wenn Record nicht existiert
  • Cloudflare: fail-fast Hinweis

modules/proxy/zentinel/playbooks/deploy-dns.yml (aktualisiert)

  • dns_zone: "{{ project_domain }}" hinzugefügt (neues Pflichtfeld)
  • dns_api_url entfernt (Hetzner-URL wird im Task hardkodiert)

Interface (dns-create / dns-remove)

record_type:  "A"                    # A, AAAA, CNAME, MX, TXT, SRV
record_name:  "mail.freesynergy.net" # voller FQDN
record_value: "1.2.3.4"             # IP, FQDN, Text
dns_zone:     "freesynergy.net"      # Root-Zone (NEU)
dns_provider: "hetzner"             # hetzner | cloudflare
dns_api_token: "{{ vault_hetzner_dns_token }}"
dns_ttl:      300                    # optional

ansible-lint: 0 Fehler, 0 Warnungen (68 Files, Profile 'production')

Noch offen

  • stalwart/playbooks/deploy-dns.yml: MX/SPF/SRV Records noch nicht implementiert
  • Cloudflare-Support: geplant

2026-03-01 – Claude Code – Verzeichnis umbenannt + Umbenennung: FSN Platform → FreeSynergy.Node

Konzept-Entscheidung

  • FreeSynergy.Node = Name des Programms/der Software (Abk. FSN Node)
  • FreeSynergy.Net = Name des Netzes/der Plattform/der Website (Abk. FSN Net)
  • Beide abgekürzt: FSN – bestehende Abkürzungen bleiben gültig
  • GitHub-Repository: git@github.com:Lord-KalEl/FreeSynergy.Node.git
  • Standard-Installationspfad auf Servern: ~/FreeSynergy.Node
  • SCIM (Kanidm): ~80% fertig, soll eingebaut werden wo es Sinn ergibt

Geänderte Dateien (Umbenennung)

  • CHANGELOG.md, CLAUDE.md, RULES.md, TODO.md – Titel + alle Vorkommen
  • hosts/example.host.yml – Kommentar-Header
  • fs-install.sh – alle Vorkommen + GitHub-URL + Default-Installationspfad
  • playbooks/*.yml (10 Dateien) – name: Felder
  • modules/**/*.yml (15 Dateien) – author: Felder
  • RULES.md/opt/fs-platform//opt/FreeSynergy.Node/, GitHub-URL
  • Memory-Dateien aktualisiert

Nicht geändert

  • projects/ – Projekt-Konfigurationen bleiben unverändert
  • Historische Pfadangaben fs-platform/ in CHANGELOG-Einträgen (korrekte Historie)

Verzeichnis-Umbenennung

  • mv /home/kal/Server/fs-platform → /home/kal/Server/FreeSynergy.Node
  • /home/kal/Server/.ansible-lint – Pfade aktualisiert (FreeSynergy.Node/)
  • /home/kal/Server/.vscode/settings.json – Pfade aktualisiert (FreeSynergy.Node/)
  • ansible-lint: 0 Fehler, 0 Warnungen (68 Files, Profile 'production')

2026-02-28 – Claude Code – Checksum-Verifikation + GitHub-Vorbereitung

Geänderte Dateien

fs-install.sh

  • Default-Repo-URL eingebaut: FS_DEFAULT_REPO="https://github.com/Lord-KalEl/FreeSynergy.Node" → Kein interaktives Fragen mehr wenn offizielles Repo gewünscht; override via --repo
  • print_checksum_info() hinzugefügt:
    • Wenn als Datei ausgeführt: zeigt SHA256 des Scripts + Link zu Releases
    • Wenn via bash <(curl ...) gepiped: zeigt 2-Schritt-Verification-Anleitung
  • Header-Kommentar aktualisiert: erklärt Quick-Install vs. Verified-Install
  • Vollständige URL im Header: https://raw.githubusercontent.com/Lord-KalEl/FreeSynergy.Node/main/fs-install.sh

~/.claude/settings.json (Claude Code Permissions)

  • Häufige sichere Operationen auto-approved: git status/log/diff/show/add/commit/init, gh repo view/list, sha256sum, command -v
  • Remote-Operationen (git push, gh repo create) und sudo bleiben mit Bestätigung

Konzept-Entscheidungen

  • Ein öffentliches Repo für alles (kein privater Projekt-Repo)
  • Standard-Branding = FSN; Forks ersetzen FS_DEFAULT_REPO + Branding
  • Passwörter: read -shosts/secrets.yml (git-ignored, chmod 600)
  • Version-Checks (check-constraints.yml): geplant für v0.2, aktuell Stub

2026-02-28 – Claude Code – Bootstrap-Installer + fetch-modules

Neue Dateien

fs-install.sh (komplett überarbeitet) Funktioniert jetzt als eigenständiges Bootstrap-Script – kann direkt vom Server gedownloaded und ausgeführt werden, ohne dass der Repo vorhanden ist.

Neues Verhalten:

  • check_git() – prüft/installiert Git (war vorher nicht vorhanden)
  • fetch_platform() – fragt nach GitHub URL des Platform-Repos, dann git clone (oder git pull falls schon vorhanden)
  • collect_secrets() – sammelt Tokens/Passwörter interaktiv via read -s; schreibt nach hosts/secrets.yml (git-ignored, chmod 600)
  • Passwörter werden NIEMALS als CLI-Argument akzeptiert (Shell-History-Risiko)
  • Nicht-sensitive Parameter via Args: --repo, --target, --project, --skip-setup, --skip-deploy, --help
  • Aufruf-Reihenfolge: setup-server → fetch-modules → install-project → deploy-stack

Typischer Ablauf (One-Liner):

bash <(curl -fsSL https://raw.githubusercontent.com/.../fs-install.sh)

playbooks/fetch-modules.yml (neu) Lädt externe Module per git clone/git pull und verifiziert bundled Module.

  • Liest project_cfg.load.modules aus der Projektdatei
  • Module mit source:ansible.builtin.git clone/pull
  • Module ohne source: → prüft ob Verzeichnis existiert, sonst Fehler
  • Unterstützt optionales source_version: (Tag oder Branch)
  • Auch verwendbar von update-stack.yml für Code-Updates

Externe Module in der Projektdatei (optional):

load:
  modules:
    "my-service":
      module_class: "category/name"
      source: "https://github.com/user/module-name"
      source_version: "v1.2.0"   # optional, default: HEAD

Design-Entscheidungen

  • Passwörter in hosts/secrets.yml (bereits von hosts/.gitignore abgedeckt)
  • ansible-playbook -e @hosts/secrets.yml reicht Secrets an Ansible weiter
  • Module-Source in der Projekt-Datei (nicht im Modul-YAML): erlaubt Überschreibung ohne den bundled Code zu ändern
  • Bundled Module (alle aktuellen): kein source nötig, bleiben unverändert

Ergebnis

  • ansible-lint: 0 Fehler, 0 Warnungen (68 Dateien, Profile 'production')
  • ansible-playbook --syntax-check: alle 10 Playbooks bestanden

2026-02-28 – Claude Code – Cleanup: Artefakt-Verzeichnisse entfernt

Gelöschte Dateien/Verzeichnisse (6 total)

Artefakt-Verzeichnisse (Shell Brace-Expansion) Beim Aufruf von mkdir {playbooks,templates} (ohne ..) erzeugt die Shell statt zwei Verzeichnissen einen einzigen mit dem Literal-Namen {playbooks,templates}. Alle 5 waren leer und hatten keinerlei Funktion:

  • modules/chat/tuwunel/{playbooks,templates}/
  • modules/maps/umap/{playbooks,templates}/
  • modules/observability/otel-collector/{playbooks,templates}/
  • modules/tasks/vikunja/{playbooks,templates}/
  • modules/tickets/pretix/{playbooks,templates}/

Leeres Template-Verzeichnis

  • modules/mail/stalwart/templates/ – Stalwart braucht kein Template; Konfiguration erfolgt über die Web Admin UI nach dem ersten Start.

Beibehaltene Symlink-Strukturen (mit Erklärung)

playbooks/tasks/tasks/ (4 Symlinks → parent) Notwendiger ansible-lint Workaround: beim Linting von Task-Dateien in playbooks/tasks/ setzt ansible-lint playbook_dir = playbooks/tasks/. Referenzen wie {{ playbook_dir }}/tasks/generate-quadlet.yml würden dann auf playbooks/tasks/tasks/generate-quadlet.yml zeigen – ohne Symlinks: load-failure. Die Symlinks lösen das auf, ohne die Dateien zu duplizieren. .ansible-lint schließt das Verzeichnis vom Linting aus (kein doppeltes Prüfen).

stalwart/playbooks/tasks/ + zentinel/playbooks/tasks/ (je 2 DNS-Symlinks) Gleicher Grund: deploy-dns.yml referenziert {{ playbook_dir }}/tasks/dns-*.yml. Beim Linting zeigt playbook_dir auf das Modul-Playbooks-Verzeichnis, daher Symlinks in tasks/../../../../../playbooks/tasks/dns-*.yml.

Ergebnis

  • ansible-lint: 0 Fehler, 0 Warnungen (67 Dateien, Profile 'production')

Format

## [YYYY-MM-DD] – [Wer] – [Kurzbeschreibung]
### Geänderte Dateien
- `pfad/zur/datei.yml` – Was wurde geändert
### Offene Probleme
- Was noch nicht funktioniert
### Nächster Schritt
- Was als nächstes getan werden muss

2026-02-27 – Claude Code – Vollständige Fehlerkorrektur (Lint-Pass)

Geänderte Dateien

  • projects/FreeSynergy.Net/{branding,sites – Gelöscht (kaputtes Verzeichnis, leere Bash-Brace-Expansion)
  • .yamllint.ymlcomments-indentation: false + octal-values hinzugefügt (ansible-lint Kompatibilität)
  • .ansible-lint – Neu erstellt: kinds: für Task-Dateien, exclude_paths: für virtuelle Pfade
  • playbooks/tasks/deploy-module.ymlvars:module_vars:, environment:module_environment:, loop_var: module_entrysub_module_entry (reserved keywords behoben)
  • playbooks/tasks/run-module-hooks.ymlname[template]: Jinja-Template ans Ende der Namen verschoben
  • playbooks/install-project.ymlname[template]: "Project installed: {{ project_name }}"
  • playbooks/tasks/generate-single-example.ymlenvironment:tpl_environment: (reserved keyword)
  • playbooks/templates/container.env.j2environment.items()tpl_environment.items()
  • playbooks/tasks/check-constraints.yml – Neu erstellt (Stub, war in sync-stack.yml referenziert aber fehlte)
  • playbooks/tasks/dns-create-record.yml – Neu erstellt (Stub, war in DNS-Playbooks referenziert aber fehlte)
  • playbooks/tasks/dns-remove-record.yml – Neu erstellt (Stub, war in DNS-Playbooks referenziert aber fehlte)
  • modules/**/playbooks/*.yml (alle) – ignore_errors: truefailed_when: false
  • modules/**/playbooks/*.yml (alle) – {{ vars.config_dir }}{{ module_vars.config_dir }}
  • modules/proxy/zentinel/playbooks/deploy-dns.yml{{ vars.dns_* }} → direkte Variablen
  • modules/proxy/zentinel/playbooks/undeploy-dns.yml – gleich
  • modules/auth/kanidm/playbooks/deploy-setup.ymlchanged_when: true bei recover-account Befehlen
  • modules/git/forgejo/playbooks/deploy-setup.ymlchanged_when: true beim create admin user Befehl
  • modules/*.yml (18 Dateien) – --- Document-Start hinzugefügt (yamllint)

Ergebnis

  • yamllint: 0 Fehler, 0 Warnungen (alle 54 Dateien)
  • ansible-lint: 0 Fehler, 0 Warnungen (68 Dateien, Profile 'production')

Offene Probleme

  • dns-create-record.yml und dns-remove-record.yml sind Stubs (noch nicht implementiert)
  • check-constraints.yml ist ein Stub (noch nicht implementiert)
  • Playbooks allgemein sind noch Stubs – siehe TODO.md

Nächster Schritt

  • Playbook-Implementierung beginnen (sync-stack.yml, deploy-stack.yml)
  • DNS-Plugin-System implementieren
  • Constraint-Checks implementieren

2026-02-28 – Claude Code – Logikfehler in Playbooks + Editor YAML-Schema

Schema-Fix (VSCode)

  • .vscode/settings.jsonyaml.schemas URL korrigiert: https://json.schemastore.org/ansible-tasks.jsonhttps://raw.githubusercontent.com/ansible/schemas/main/f/ansible-tasks.json (SchemaStore-URL lieferte keinen Inhalt; direkte GitHub-URL funktioniert)

Logikfehler behoben (6 Dateien)

playbooks/deploy-stack.yml

  • Set host variables ohne when-Bedingung → host_cfg wäre undefined wenn keine Host-Datei vorhanden → Jinja-Fehler zur Laufzeit
  • Fix: aufgeteilt in when: host_files.matched > 0 + Fallback when: host_files.matched == 0

playbooks/sync-stack.yml

  • include_vars: name: project_config überschrieb die externe Variable (Pfad) mit YAML-Inhalt
  • Duplizierungs-Check nutzte fail + loop statt assert (konnte bei dict-Keys nie feuern)
  • Fix: Variable → project_cfg, Duplicate-Check → assert

playbooks/setup-server.yml

  • when: user_check is failed funktioniert NIE nach failed_when: false → User wurde nie angelegt
  • Fix: when: user_check.rc != 0

playbooks/tasks/generate-single-example.yml

  • Nutzte module_environment ohne das Modul zu laden → undefined wenn von install-project.yml
  • Fix: include_vars für Modul-Datei + example_module_cfg.environment | default({})

playbooks/tasks/update-module.yml

  • include_vars: name: modulecontainer, module_environment, module_vars fehlten beim späteren Aufruf von generate-quadlet.yml
  • Fix: name: module_cfg + set_fact (identisch zu deploy-module.yml)
  • module.module.versionmodule.version

playbooks/tasks/run-module-hooks.yml

  • Kein Guard wenn module_path undefined → Jinja-Fehler bei orphaned Services
  • Fix: when: module_path is defined + | default(0) / | default([])

Ergebnis

  • ansible-lint: 0 Fehler, 0 Warnungen (67 Dateien, Profile 'production')
  • ansible-playbook --syntax-check: alle 9 Playbooks bestanden

2026-02-27 – Claude Code – Editor-Kompatibilität (Ansible-Lint aus VSCode)

Problem

Der VSCode-Editor führt ansible-lint aus /home/kal/Server/ (Workspace-Root) aus, nicht aus fs-platform/. Dadurch griff die .ansible-lint-Konfiguration im Projektverzeichnis nicht, und der Editor zeigte Fehler, obwohl ansible-lint fs-platform/ sauber lief.

Geänderte / neue Dateien

  • /home/kal/Server/.ansible-lint – Neu erstellt: kinds: mit fs-platform/-Prefix-Varianten für korrekte Datei-Klassifizierung aus dem Workspace-Root heraus
  • playbooks/tasks/run-module-hooks.yml – Zweite name[template]-Korrektur: {{ instance_name }} aus den Task-Namen entfernt (zwei Templates mit Text dazwischen = Fehler)
  • playbooks/tasks/tasks/ – Symlinks erstellt für ansible-lint load-failure-Workaround:
    • deploy-module.yml../deploy-module.yml
    • generate-quadlet.yml../generate-quadlet.yml
    • run-module-hooks.yml../run-module-hooks.yml
    • record-deployed-version.yml../record-deployed-version.yml
  • modules/mail/stalwart/playbooks/tasks/ – DNS-Stub-Symlinks:
    • dns-create-record.yml../../../../../playbooks/tasks/dns-create-record.yml
    • dns-remove-record.yml../../../../../playbooks/tasks/dns-remove-record.yml
  • modules/proxy/zentinel/playbooks/tasks/ – DNS-Stub-Symlinks (gleiche Targets)

Hintergrund: Symlinks

ansible-lint löst {{ playbook_dir }}/tasks/X.yml beim Linten von Task-Dateien auf den eigenen Ordner auf (playbooks/tasks/tasks/). Diese Pfade existieren nicht real, deshalb load-failure. Da load-failure und syntax-check nicht skippbar sind, wurden Symlinks als struktureller Workaround erstellt.

Ergebnis

  • ansible-lint aus /home/kal/Server/: 0 Fehler, 0 Warnungen (67 Dateien, Profile 'production')
  • ansible-lint aus fs-platform/: 0 Fehler, 0 Warnungen
  • Editor zeigt keine ansible-lint-Fehler mehr

Offene Probleme

  • dns-create-record.yml und dns-remove-record.yml sind Stubs (noch nicht implementiert)
  • check-constraints.yml ist ein Stub (noch nicht implementiert)
  • Playbooks allgemein sind noch Stubs – siehe TODO.md

Nächster Schritt

  • Playbook-Implementierung beginnen (sync-stack.yml, deploy-stack.yml)
  • DNS-Plugin-System implementieren
  • Constraint-Checks implementieren

2026-02-28 – Claude Chat – Initial Commit (v0.0.1)

Erstes Release. Alle Module, Playbooks, Branding und Landing Page.