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.
cli/crates/fs-tui/Cargo.toml–toml = { workspace = true }hinzugefügt (TOML-Parsing)cli/crates/fs-tui/src/app.rs–DashFocus-Enum,ProjectInfo-Struct,dirty()-Builder,edit_sluginNewProjectForm,NewProjectForm::from_project(),AppStateumprojects/selected_project/dash_focus/dash_confirmerweitertcli/crates/fs-tui/src/lib.rs–load_projects()+parse_project_toml()lesen*.project.tomlbeim Startcli/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öschencli/crates/fs-tui/src/ui/new_project.rs– Edit-Modus: Titel + Submit-Button abhängig vonedit_slugcli/crates/fs-tui/src/events.rs–handle_dashboard()neu mit 2-Fokus-System,delete_selected_project(),submit_project()lädt Projektliste neu
- Projekt-Sidebar: Dashboard zeigt alle Projekte aus
projects/*/.↑↓wechselt Projekte,Tabspringt 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_slugmerkt sich den Slug) - Projekt löschen:
xzeigt Bestätigungsdialog (gelb),J/Ylöscht,Nbricht ab; Verzeichnis wird entfernt - Focus-Highlight: Aktiver Bereich (Sidebar/Services) wird Cyan hervorgehoben
- Header: Zeigt
FSN · Name @ domaindes ausgewählten Projekts
- Services-Aktionen implementieren (Deploy, Restart, Stop, Logs-Overlay)
cli/crates/fs-tui/src/app.rs–slugifypublic gemacht,field_value()+set_select_by_index()hinzugefügtcli/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_projectbekommtroot-Parametercli/crates/fs-tui/src/lib.rs–project_toml_exists()erkennt vorhandene Projekte → direkt zum Dashboard
- 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.tomlund wechselt zum Dashboard - Vorhandenes Projekt: Beim Start wird
projects/nach*.project.tomlgescannt — wenn gefunden, direkt Dashboard statt Welcome
- Dashboard: Neues Projekt anlegen + Bearbeiten + Löschen von bestehenden Projekten
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: boolin AppStatecli/crates/fs-tui/src/events.rs– ESC schließt Modal (nicht mehr Tab-by-Tab). Ctrl+←/→ = Tab wechseln. Ohne Ctrl = Cursor im Text.ctrl_hintwird bei jedem Tastendruck aktualisiertcli/crates/fs-tui/src/i18n.rs–form.hint.ctrlhinzugefügt.form.hintaktualisiert (^=Strg). Server-Schlüssel entfernt,form.project.descriptionneucli/crates/fs-tui/src/ui/new_project.rs– Hint-Bar: wechselt auf Ctrl-Shortcuts wennctrl_hint=trueprojects/FreeSynergy.Net/freesynergy.project.yml– gelöscht (nicht mehr gebraucht)projects/FreeSynergy.Net/freesynergy.federation.yml– gelöscht
- 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
- Submit-Handler: Verzeichnis + project.toml schreiben
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.rs–tab_missing_count(), Event-Loop:Event::Mouse→handle_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 fehlencli/crates/fs-tui/src/lib.rs–EnableMouseCapture/DisableMouseCapture
- 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
- Submit-Handler: Verzeichnis + project.toml + host.toml schreiben
cli/crates/fs-tui/src/app.rs–Screen::NewProject,FormTab,FormFieldType,FormField,NewProjectFormmit 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ürScreen::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::NewProjectcli/crates/fs-tui/src/ui/new_project.rs– Neu: Formular mit ratatuiTabs-Widget (3 Tabs), Pflichtfeld-Marker*, Cursor als█, Hinweis-Text, ⚠ auf Tabs mit fehlenden Feldern, Submit-Button auf Options-Tabcli/crates/fs-tui/src/ui/welcome.rs– Sysinfo-Block mit fixer Spaltenbreite (18/18/14 Zeichen), bündig ausgerichtetcli/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
- 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
Lumschalten (auch im Formular) - Submit nur aktiv wenn alle Pflichtfelder ausgefüllt
- Tabs zeigen ⚠ wenn zugehörige Pflichtfelder leer sind
- Keine —
cargo buildsauber
- Submit-Handler: Projekt-Verzeichnis anlegen, project.toml schreiben (Phase 2)
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ürtuwunel_allow_registration(bool, default false) undtuwunel_allow_federation(bool, default true) hinzugefügtmodules/collab/cryptpad/cryptpad.toml–[[setup.fields]]fürcryptpad_admin_email(email) hinzugefügtmodules/mail/stalwart/stalwart.toml–[[setup.fields]]fürstalwart_admin_password(secret, auto_generate) hinzugefügt
fsn deployschreibt nach jedem Deploy automatisch die Zentinel KDL-Konfiguration. Manuell editierte Bereiche (oberhalb/unterhalb der FSN-Marker) bleiben unberührt.- Alle 14 Module haben jetzt
.tomlDateien (waren schon vorhanden). 9 Module haben[[setup.fields]]— derfsn init-Wizard fragt die richtigen Secrets automatisch ab.
| 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 |
- Keine —
cargo buildsauber
fsn inittesten mit einem echten Projekt- TUI: Deploy-Aktion wirklich async ausführen
cli/crates/fs-tui/Cargo.toml– neues Crate, Dependencies: ratatui/crossterm/sysinfo/fs-core/fs-enginecli/crates/fs-tui/src/lib.rs– Einstiegrun(root): Terminal-Init, Service-Erkennung, Event-Loop-Startcli/crates/fs-tui/src/app.rs–AppState,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 Sprachecli/crates/fs-tui/src/sysinfo.rs–SysInfo::collect(): Hostname, User, IP, RAM, CPU, Uptime, Podman-Version, Archcli/crates/fs-tui/src/events.rs– Tastaturhandling: Welcome (Tab=Sprache, Enter, q), Dashboard (↑↓, d/r/x/l, q), Logs-Overlaycli/crates/fs-tui/src/ui/mod.rs– Screen-Dispatch + Overlay-Renderingcli/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_linecli/crates/fs-cli/src/commands/tui.rs–pub async fn run(root) → fs_tui::run(root)
cli/Cargo.toml–fs-tuizu workspace members; ratatui/crossterm/sysinfo zu workspace.dependenciescli/crates/fs-cli/Cargo.toml–fs-tui = { workspace = true }cli/crates/fs-cli/src/cli.rs–Command::Tui+ Dispatch zucommands::tui::runcli/crates/fs-cli/src/commands/mod.rs–pub mod tui;
- 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
- 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 initdanach)- Service-Typ und Domain aus project.toml lesen (aktuell: Podman
ps -aAusgabe, Domain Placeholder) - Projekt-Switching (mehrere Projekte) folgt in Phase 2
- KDL in deploy.rs einbauen
- postgres-Modul nach TOML konvertieren
cli/crates/fs-engine/src/generate/kdl.rs– komplett neu geschrieben: echtes Zentinel KDL-Format (Pingora, nicht Caddy),upstreams {}undroutes {}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 eigeneroute-BlöckeREADME.md– Zentinel korrekt als Pingora beschrieben (war noch Caddy-Referenz drin)CHANGELOG.md– dieses Update
- 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
- 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
- deploy.rs:
kdl::upsert_managed_section()in den Deploy-Loop einbauen (nach Quadlet-Generation) - TUI mit ratatui
cli/crates/fs-core/src/config/service.rs– neu (umbenannt vonmodule.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 Feldercli/crates/fs-core/src/config/project.rs–ServiceSlots(iam/mail/wiki/git/chat/collab/tasks/monitoring/extra),ProjectMetabekommtversion/language/languages,ProjectLoad.services(alias „modules"),ServiceEntry(warModuleRef) mit alias fürmodule_class,type ModuleRef = ServiceEntryfür Rückwärtskompatibilitätcli/crates/fs-core/src/state/desired.rs–DesiredState.services(war.modules),ServiceInstancebekommtservice_type: ServiceType,sub_services(warsub_modules)cli/crates/fs-core/src/config/mod.rs–pub mod servicestattpub mod module, alle Exporte aktualisiertcli/crates/fs-engine/src/resolve.rs–.modules→.services,.module.alias→.meta.alias,class.load.services→class.load.sub_services,service_typezuServiceInstance-Initializer hinzugefügtcli/crates/fs-engine/src/constraints.rs– Importconfig::module::Locality→config::service::Localitycli/crates/fs-engine/src/setup.rs– Importconfig::module::SetupField→config::service::SetupFieldcli/crates/fs-web/src/api.rs– Importconfig::module::FieldType→config::service::FieldTypecli/crates/fs-cli/src/commands/init.rs– Importconfig::module::FieldType→config::service::FieldTypecli/crates/fs-cli/src/commands/deploy.rs–modules-Variable →services,DesiredState { services, .. }cli/Cargo.toml–fs-ansibleaus Workspace entfernt,libchinzugefügtplaybooks/– vollständig entfernt (25 Dateien, 11 Unterverzeichnisse).ansible-lint,.yamllint.yml,.ansible/,requirements.yml– entferntREADME.md– komplett neu geschrieben: Ansible raus, Rust CLI, Services statt Modules, Zentinel korrekt als Pingora, aktueller Status
- 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").
- Keine —
cargo buildist sauber
- Zentinel KDL-Generator (korrektes Pingora-KDL-Format mit
upstreams {}undroutes {})
Was fehlte / falsch war:
- Fedora CoreOS hat
ID=fedorain/etc/os-release→ wurde alsdnferkannt →install_pkgschlug 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 viarpm-ostreevor OS-Detection;install_pkgmitrpm-ostree-Case; hardcodierteFS_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_summaryzeigt Token-Status
Was fehlte:
- Installer hat nie nach der ACME-E-Mail gefragt → Let's Encrypt ohne Benachrichtigungsadresse
vault_hetzner_dns_tokenwurde in vault.yml.j2 als"CHANGE_ME"gerendert, obwohl der Token aus dem Installer-Wizard bekannt war → manuelle Deployments ohne-e @secrets.ymlhätten keinen DNS-Token
Geänderte Dateien:
fs-install.sh– E-Mail-Frage nach Domain-Eingabe; E-Mail in Summary; ingenerate_project_yml()alsproject.contact.acme_emailgeschrieben;PROJECT_EMAILDefault inmain()playbooks/templates/vault.yml.j2– DNS-Tokens nutzen{{ vault_hetzner_dns_token | default('CHANGE_ME') }}→ echter Token wird bei erstem Install-Lauf direkt eingebaut
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.yml–dns_provider(aus Host-Datei),dns_api_token(aus Vault),project_services(Liste aller Top-Level-Module) hinzugefügtplaybooks/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_providerkommt aushost_cfg.host.proxy.zentinel.load.plugins.dns(z.B."hetzner")dns_api_tokenwird daraus abgeleitet: hetzner →vault_hetzner_dns_token, cloudflare →vault_cloudflare_api_tokenproject_services= Liste von{subdomain: <key>, aliases: []}für alle Module ausproject_cfg.load.modules
Neue Datei:
requirements.yml– Deklariertansible.posix(≥1.5) undcommunity.general(≥8.0)
Geänderte Datei:
fs-install.sh–install_collections()Funktion hinzugefügt; wird nachfetch_platformaufgerufen
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.
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 aktualisiertundeploy-module.yml– Sub-Module stoppen NACH dem Parent (Parent gibt Connections frei)remove-module.yml– Sub-Module werden NACH dem Parent gelöschtrestart-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ügtrestart-stack.yml– vault.yml + project_domain hinzugefügtundeploy-stack.yml– vault.yml hinzugefügtremove-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
Geänderte Dateien:
modules/tickets/pretix/pretix.yml–vault_dragonfly_password→services.dragonfly.vault_cache_password; DB →services.postgres.*modules/tasks/vikunja/vikunja.yml–vault_dragonfly_password→services.dragonfly.vault_cache_passwordplaybooks/templates/vault.yml.j2–vault_pretix_db_passwordentfernt;vault_vikunja_mailer_*undvault_pretix_mail_*als optionale Leer-Felder ergänztmodules/proxy/zentinel/zentinel-control-plane/zentinel-control-plane.yml–healthcheckBlock hinzugefügtplaybooks/tasks/generate-single-example.yml– Bug:tpl_environment→module_environmentplaybooks/tasks/deploy-module.yml–container_dependenciesbei Quadlet-Generierung gesetzt
Was die Fixes beheben:
- pretix/vikunja: Dragonfly-Verbindung funkioniert jetzt (richtiger Variablenname)
- pretix: DB-Passwort stimmt mit postgres-Container überein
- zentinel-control-plane: Healthcheck war als einziges Modul fehlend
- Config-Beispiele enthalten jetzt alle Umgebungsvariablen (waren leer)
- Systemd-Startup-Reihenfolge: Sub-Module starten VOR der App (
After=/Requires=)
Neue Datei:
playbooks/templates/vault.yml.j2– Vault-Template mit auto-generierten Passwörtern (einmalig, idempotent)
Geänderte Dateien:
playbooks/install-project.yml– Generiertprojects/<name>/vault.ymlwenn nicht vorhanden (chmod 600)playbooks/tasks/resolve-service.yml– Fügtvault_cache_passwordins services-Dict ein (war vergessen)modules/maps/umap/umap.yml–DATABASE_URLundREDIS_URLnutzen jetztservices.*.vault_*statt eigene vault-Variablen
Was die Fixes beheben:
vault.ymlwird beiminstalleinmalig auto-generiert; Passwörter sind sofort einsatzbereitservices.cache.vault_cache_passwordist jetzt auflösbar (Forgejo, Outline, Vikunja, Pretix)- umap's postgres-Passwort stimmt jetzt mit dem postgres-Container überein (war:
vault_umap_db_passwordvs.vault_db_password)
Neue Datei:
playbooks/tasks/resolve-service.yml– Liest Sub-Modul-YAML (port, db_name) und bautservices-Dict
Geänderte Dateien:
playbooks/tasks/deploy-module.yml– Bautservices-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_nameetc. 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
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 + HTTPSmodules/proxy/zentinel/templates/zentinel-block-sandbox.kdl.j2– CryptPad Sandbox-Domainmodules/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)
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
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:
- State-File laden → alle Records für
proxy/zentinelermitteln - Erwartete FQDNs aus aktueller Config berechnen
- Records die in State-File stehen aber NICHT mehr erwartet werden → DELETE
- State-File aktualisieren → dann normale Record-Erstellung (A, AAAA, CNAME)
Effekt: Service von chat → matrix 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.ymlplaybooks/tasks/tasks/dns-cleanup-module.yml
- 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"
remove-stack.yml/undeploy-stack.yml: noch kein expliziterdns-cleanup-module.ymlAufruf
fs-install.sh (kompletter Rewrite)
Interaktiver Setup-Wizard für neue Installationen:
list_available_modules()– scanntmodules/Verzeichnis (zeigt alle verfügbaren Module)select_dns_provider()– Auswahl Hetzner/Cloudflare + Token-Eingabe viaread -rsselect_acme_provider()– Auswahl letsencrypt/smallstep-caselect_modules()– nummerierte Liste, Eingabe als space-separated Nummern oderalldetect_server_ip()– automatisch viaip route get 1.1.1.1generate_project_yml()– schreibtprojects/NAME/NAME.project.ymlgenerate_host_yml()– schreibthosts/HOSTNAME.host.yml(DNS + ACME Provider eingebaut)show_setup_summary()– zeigt Zusammenfassung vor Deploymentimport_config()– importiert externes project.yml (--config FILE)collect_secrets()– Provider-aware, nutzt DNS_TOKEN aus Wizard wieder
Drei Modi in main():
--config FILE→ Import + direkt deployen--project FILE→ Bereits platziert, nur deployen- 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_fileunddns_state_modulean die Task-Files
modules/proxy/zentinel/playbooks/undeploy-dns.yml (Bugfix + State Tracking)
dns_api_urlentfernt (war noch aus altem Interface übrig)dns_zone: "{{ project_domain }}"hinzugefügt (war fehlend)dns_state_file+dns_state_modulehinzugefügt
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).
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)
modules/tickets/pretix/pretix.yml–author: "FSN Platform"->author: "FreeSynergy.Node"modules/tasks/vikunja/vikunja.yml–author: "FSN Platform"->author: "FreeSynergy.Node"modules/database/postgres/postgres.yml–author: "FSN Platform"->author: "FreeSynergy.Node"modules/mail/stalwart/stalwart.yml–author: "FSN Platform"->author: "FreeSynergy.Node"modules/chat/tuwunel/tuwunel.yml–author: "FSN Platform"->author: "FreeSynergy.Node"modules/observability/otel-collector/otel-collector.yml–author: "FSN Platform"->author: "FreeSynergy.Node"modules/collab/cryptpad/cryptpad.yml–author: "FSN Platform"->author: "FreeSynergy.Node"modules/wiki/outline/outline.yml–author: "FSN Platform"->author: "FreeSynergy.Node"modules/observability/openobserver/openobserver.yml–author: "FSN Platform"->author: "FreeSynergy.Node"modules/git/forgejo/forgejo.yml–author: "FSN Platform"->author: "FreeSynergy.Node"modules/maps/umap/umap.yml–author: "FSN Platform"->author: "FreeSynergy.Node"modules/cache/dragonfly/dragonfly.yml–author: "FSN Platform"->author: "FreeSynergy.Node"modules/proxy/zentinel/zentinel.yml–author: "FSN Platform"->author: "FreeSynergy.Node"modules/auth/kanidm/kanidm.yml–author: "FSN Platform"->author: "FreeSynergy.Node"modules/proxy/zentinel/zentinel-control-plane/zentinel-control-plane.yml–author: "FSN Platform"->author: "FreeSynergy.Node"
- Keine
- Keine weiteren Schritte erforderlich
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_urlentfernt (Hetzner-URL wird im Task hardkodiert)
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 # optionalstalwart/playbooks/deploy-dns.yml: MX/SPF/SRV Records noch nicht implementiert- Cloudflare-Support: geplant
- 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
CHANGELOG.md,CLAUDE.md,RULES.md,TODO.md– Titel + alle Vorkommenhosts/example.host.yml– Kommentar-Headerfs-install.sh– alle Vorkommen + GitHub-URL + Default-Installationspfadplaybooks/*.yml(10 Dateien) –name:Feldermodules/**/*.yml(15 Dateien) –author:FelderRULES.md–/opt/fs-platform/→/opt/FreeSynergy.Node/, GitHub-URL- Memory-Dateien aktualisiert
projects/– Projekt-Konfigurationen bleiben unverändert- Historische Pfadangaben
fs-platform/in CHANGELOG-Einträgen (korrekte Historie)
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')
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) undsudobleiben mit Bestätigung
- Ein öffentliches Repo für alles (kein privater Projekt-Repo)
- Standard-Branding = FSN; Forks ersetzen
FS_DEFAULT_REPO+ Branding - Passwörter:
read -s→hosts/secrets.yml(git-ignored, chmod 600) - Version-Checks (
check-constraints.yml): geplant für v0.2, aktuell Stub
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, danngit clone(odergit pullfalls schon vorhanden)collect_secrets()– sammelt Tokens/Passwörter interaktiv viaread -s; schreibt nachhosts/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.modulesaus der Projektdatei - Module mit
source:→ansible.builtin.gitclone/pull - Module ohne
source:→ prüft ob Verzeichnis existiert, sonst Fehler - Unterstützt optionales
source_version:(Tag oder Branch) - Auch verwendbar von
update-stack.ymlfü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- Passwörter in
hosts/secrets.yml(bereits vonhosts/.gitignoreabgedeckt) ansible-playbook -e @hosts/secrets.ymlreicht 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
sourcenötig, bleiben unverändert
- ansible-lint: 0 Fehler, 0 Warnungen (68 Dateien, Profile 'production')
- ansible-playbook --syntax-check: alle 10 Playbooks bestanden
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.
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.
- ansible-lint: 0 Fehler, 0 Warnungen (67 Dateien, Profile 'production')
## [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
projects/FreeSynergy.Net/{branding,sites– Gelöscht (kaputtes Verzeichnis, leere Bash-Brace-Expansion).yamllint.yml–comments-indentation: false+octal-valueshinzugefügt (ansible-lint Kompatibilität).ansible-lint– Neu erstellt:kinds:für Task-Dateien,exclude_paths:für virtuelle Pfadeplaybooks/tasks/deploy-module.yml–vars:→module_vars:,environment:→module_environment:,loop_var: module_entry→sub_module_entry(reserved keywords behoben)playbooks/tasks/run-module-hooks.yml–name[template]: Jinja-Template ans Ende der Namen verschobenplaybooks/install-project.yml–name[template]: "Project installed: {{ project_name }}"playbooks/tasks/generate-single-example.yml–environment:→tpl_environment:(reserved keyword)playbooks/templates/container.env.j2–environment.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: true→failed_when: falsemodules/**/playbooks/*.yml(alle) –{{ vars.config_dir }}→{{ module_vars.config_dir }}modules/proxy/zentinel/playbooks/deploy-dns.yml–{{ vars.dns_* }}→ direkte Variablenmodules/proxy/zentinel/playbooks/undeploy-dns.yml– gleichmodules/auth/kanidm/playbooks/deploy-setup.yml–changed_when: truebeirecover-accountBefehlenmodules/git/forgejo/playbooks/deploy-setup.yml–changed_when: truebeimcreate admin userBefehlmodules/*.yml(18 Dateien) –---Document-Start hinzugefügt (yamllint)
- yamllint: 0 Fehler, 0 Warnungen (alle 54 Dateien)
- ansible-lint: 0 Fehler, 0 Warnungen (68 Dateien, Profile 'production')
dns-create-record.ymlunddns-remove-record.ymlsind Stubs (noch nicht implementiert)check-constraints.ymlist ein Stub (noch nicht implementiert)- Playbooks allgemein sind noch Stubs – siehe TODO.md
- Playbook-Implementierung beginnen (sync-stack.yml, deploy-stack.yml)
- DNS-Plugin-System implementieren
- Constraint-Checks implementieren
.vscode/settings.json–yaml.schemasURL korrigiert:https://json.schemastore.org/ansible-tasks.json→https://raw.githubusercontent.com/ansible/schemas/main/f/ansible-tasks.json(SchemaStore-URL lieferte keinen Inhalt; direkte GitHub-URL funktioniert)
playbooks/deploy-stack.yml
Set host variablesohnewhen-Bedingung →host_cfgwäre undefined wenn keine Host-Datei vorhanden → Jinja-Fehler zur Laufzeit- Fix: aufgeteilt in
when: host_files.matched > 0+ Fallbackwhen: 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 + loopstattassert(konnte bei dict-Keys nie feuern) - Fix: Variable →
project_cfg, Duplicate-Check →assert
playbooks/setup-server.yml
when: user_check is failedfunktioniert NIE nachfailed_when: false→ User wurde nie angelegt- Fix:
when: user_check.rc != 0
playbooks/tasks/generate-single-example.yml
- Nutzte
module_environmentohne das Modul zu laden → undefined wenn voninstall-project.yml - Fix:
include_varsfür Modul-Datei +example_module_cfg.environment | default({})
playbooks/tasks/update-module.yml
include_vars: name: module→container,module_environment,module_varsfehlten beim späteren Aufruf vongenerate-quadlet.yml- Fix:
name: module_cfg+set_fact(identisch zudeploy-module.yml) module.module.version→module.version
playbooks/tasks/run-module-hooks.yml
- Kein Guard wenn
module_pathundefined → Jinja-Fehler bei orphaned Services - Fix:
when: module_path is defined+| default(0)/| default([])
- ansible-lint: 0 Fehler, 0 Warnungen (67 Dateien, Profile 'production')
- ansible-playbook --syntax-check: alle 9 Playbooks bestanden
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.
/home/kal/Server/.ansible-lint– Neu erstellt:kinds:mitfs-platform/-Prefix-Varianten für korrekte Datei-Klassifizierung aus dem Workspace-Root herausplaybooks/tasks/run-module-hooks.yml– Zweitename[template]-Korrektur:{{ instance_name }}aus den Task-Namen entfernt (zwei Templates mit Text dazwischen = Fehler)playbooks/tasks/tasks/– Symlinks erstellt für ansible-lintload-failure-Workaround:deploy-module.yml→../deploy-module.ymlgenerate-quadlet.yml→../generate-quadlet.ymlrun-module-hooks.yml→../run-module-hooks.ymlrecord-deployed-version.yml→../record-deployed-version.yml
modules/mail/stalwart/playbooks/tasks/– DNS-Stub-Symlinks:dns-create-record.yml→../../../../../playbooks/tasks/dns-create-record.ymldns-remove-record.yml→../../../../../playbooks/tasks/dns-remove-record.yml
modules/proxy/zentinel/playbooks/tasks/– DNS-Stub-Symlinks (gleiche Targets)
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.
- 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
dns-create-record.ymlunddns-remove-record.ymlsind Stubs (noch nicht implementiert)check-constraints.ymlist ein Stub (noch nicht implementiert)- Playbooks allgemein sind noch Stubs – siehe TODO.md
- Playbook-Implementierung beginnen (sync-stack.yml, deploy-stack.yml)
- DNS-Plugin-System implementieren
- Constraint-Checks implementieren
Erstes Release. Alle Module, Playbooks, Branding und Landing Page.