Three interlocking issues that made 26.11/26.12 effectively un-upgradable from pre-auth versions without manual pacman + symlink surgery. Caught while SSH-testing the .196 VM which landed on a rollback loop after every Update-now click. 1. auth.py imported werkzeug.security, but the target system runs core as bare system Python — neither flask nor werkzeug are pip-installed. Fresh 26.11+ boxes died on import. Replaced with a 50-line stdlib `furtka/passwd.py` using hashlib.pbkdf2_hmac for new hashes and parsing werkzeug's `scrypt:N:r:p$salt$hex` format for backward-read so existing users.json survives. 2. updater._health_check pinged /api/apps expecting 200. Post- auth, /api/apps returns 401 for unauth requests → HTTPError caught as URLError → retry loop → 30s timeout → rollback. Now any 2xx-4xx counts as "server alive"; only 5xx / connection errors fail. Server responding at all is proof it came back up. 3. _do_install released the fcntl lock between sync pre-validation and the systemd-run dispatch. A second POST could slip in, pass the lock check, return 202, and leave its install-bg child to die silently on the in-child lock. Now the API also reads install-state.json and refuses 409 on non-terminal stages — the state file is the reliable signal, the fcntl lock is defence in depth. Test coverage: - tests/test_passwd.py (new, 6 cases): roundtrip, salt uniqueness, format shape, werkzeug scrypt backward-compat against a real hash captured from the .196 box, malformed + non-string rejection. - tests/test_updater.py: +3 cases for _health_check — 4xx=healthy, 5xx=unhealthy, URLError retry loop. - tests/test_api.py: +2 cases for install 409 on non-terminal state + 202 after terminal. All 267 tests green, ruff check + format clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
28 KiB
Changelog
All notable changes to Furtka will be documented in this file.
The format is based on Keep a Changelog.
This project uses calendar versioning: YY.N-stage (e.g. 26.0-alpha = 2026, release 0, alpha stage).
Unreleased
26.13-alpha - 2026-04-21
Fixed
- Upgrade path from pre-auth releases actually works. 26.11-alpha
introduced
from werkzeug.security import ...infurtka/auth.py, but werkzeug isn't installed on the target system — core runs as system Python with stdlib only, andflask>=3.0inpyproject.tomlis never pip-installed on the box. Fresh boxes from the 26.11/26.12 ISO without a manually-installed werkzeug crashed on import; boxes upgrading from pre-26.11 got double-broken by that plus the health check below. Replaced the werkzeug dependency with a stdlib-onlyfurtka/passwd.pythat useshashlib.pbkdf2_hmacfor new hashes and parses werkzeug'sscrypt:N:r:p$salt$hexformat for backward compatibility — existingusers.jsonfiles created on the rare boxes that did have werkzeug keep working after this upgrade, no re-setup needed.from werkzeug.security import ...is gone from the import chain entirely;pyproject.toml's flask dep stays only for the live-ISO webinstaller. - Self-update no longer auto-rolls-back when crossing the auth
boundary.
updater._health_checkpinged/api/appsand demanded a 200, which meant every 26.10 → 26.11+ upgrade hit the post-restart check, got a 401 (auth guard), and treated that as "server dead" → rollback. Now any 2xx–4xx response counts as "server alive"; only connection-level failures or 5xx fail the check. 5xx still fails rollback because that means the new process is up but broken. - Install lock closes its race window.
POST /api/apps/installused to release the fcntl lock immediately after the sync pre-validation so the systemd-run child could re-acquire it — leaving a tiny gap where a second POST could slip in, pass the lock check, and return 202. Both child processes would start, one would win the in-child lock, the other would die silently. Now the API also readsinstall-state.jsonand refuses with 409 if the stage is non-terminal (pulling_image,creating_volumes,starting_container). The fcntl lock stays as belt-and-suspenders.
26.12-alpha - 2026-04-21
Changed
- App-Install geht async mit Live-Progress.
POST /api/apps/installreturnt jetzt202 Acceptednach der synchronen Pre-Validation (Source auflösen, Files kopieren,.envschreiben, Placeholder- und Path-Checks). Den eigentlichen Docker-Teil (compose pull→ volumes →compose up) dispatched der Handler alssystemd-run --unit=furtka-install-<app>Hintergrund-Job, der seine Phase in/var/lib/furtka/install-state.jsonschreibt. NeuesGET /api/apps/install/statusfür UI-Polling. Das Install-Modal zeigt jetzt live "Image wird heruntergeladen…" → "Speicherbereiche werden erstellt…" → "Container wird gestartet…" statt ~30 Sekunden totem "Installing…". Muster 1:1 parallel zu/api/catalog/sync/applyund/api/furtka/update/apply. Neue CLI- Subcommandfurtka app install-bg <name>(intern, von der API aufgerufen);furtka app installfür Terminal-User bleibt synchron. Die Reinstall-Taste in der App-Liste pollt ebenfalls den Install-Status und spiegelt die Phase im Button-Text.
26.11-alpha - 2026-04-21
Added
- Login-auth for the Furtka web UI. Every
/apps,/api/*,/, and/settings/route now requires a signed-in session. New/loginpage serves a username/password form;POST /loginvalidates against/var/lib/furtka/users.json(werkzeug PBKDF2- hashed), sets afurtka_sessioncookie (HttpOnly,SameSite= Strict, 7-day TTL), and redirects to/apps.POST /logoutrevokes the server-side session and clears the cookie. Unauthenticated HTML requests get a 302 to/login; unauthenticated API requests get 401 JSON. The old "No authentication on this UI yet" banner is gone; the/appsheader picks up aLogoutlink instead. - First-run setup fallback for upgrade-path boxes. Boxes
upgrading from 26.10-alpha have no
users.jsonyet — on the first visit/loginrenders a setup form (username + password + password-confirm) that creates the admin record on submit. Fresh installs skip this: the webinstaller writesusers.jsonduring the chroot post-install step using the step-1 password, so the first browser visit after boot goes straight to the login form. - Caddy proxy routes
/loginand/logout.assets/Caddyfilegets two newhandleblocks in the shared(furtka_routes)snippet so both the:80block and thehostname.local, hostnameHTTPS block forward the auth endpoints to the stdlib server on127.0.0.1:7000. Without this Caddy would serve a 404 from the static file server.
Fixed
tests/test_installer.pyruff-format nit — the 26.10-alpha release commit had a misformatted list literal that failedruff format --check. Caught when the Release page on Forgejo showed a red CI badge for the tag.pyproject.tomlversion string bumped from the stale 26.8-alpha to 26.11-alpha. Release pipeline usesGITHUB_REF_NAMEas source of truth for the artefact name, but having the two agree matters for local dev runs that readpyproject.toml.
26.10-alpha - 2026-04-21
Added
- Remove-USB-stick hint on the installer's post-install screen.
webinstaller/templates/install/rebooting.htmlnow shows a bold "Remove the USB stick now" line before the reboot, plus a muted fallback explaining the BIOS boot-menu keys (F11/F12/Esc) if the machine boots back into the installer anyway. Caught on the first bare-metal test (Medion i5-4gen, 2026-04-21) where the box didn't boot the installed system without manual BIOS-order changes. - New
pathsetting type for app manifests. Apps can now declare a setting with"type": "path"whose value is an absolute filesystem path on the host; docker-compose bind-mounts it via the usual.envsubstitution (${MEDIA_PATH}:/media). Unlocks media/data-heavy apps (Jellyfin, later Paperless/Nextcloud/Immich) where the user points at an existing folder instead of copying everything into a Docker volume. The install form renders path settings as a plain text input with a/mnt/…placeholder hint. - Server-side path validation. Both
install_from()andupdate_env()refuse values that aren't absolute, don't exist, aren't directories, or resolve (afterPath.resolve()) into a system-path deny-list (/,/etc,/root,/boot,/proc,/sys,/dev,/bin,/sbin,/usr/bin,/usr/sbin,/var/lib/furtka). Catches/mnt/../etc-style traversal too. Error messages surface in the existing install/edit modal error line.
26.9-alpha - 2026-04-21
Fixed
- Landing-page app tiles with an
open_urlnow open in a new tab (target="_blank" rel="noopener"), matching the Open button behaviour on/apps. Without this, clicking "Uptime Kuma" on the home screen replaced Furtka itself with the Kuma admin page. Internal links (theManage →fallback for apps without anopen_url) still open in the same tab. scripts/publish-release.shno longer fails the whole release when the ISO upload hits a Forgejo proxy 504. The core tarball + sha256 + release.json (which running boxes need for self-update) are uploaded first and the ISO is attempted last as a best-effort; a 504 now logs a warning and exits 0 so the release page still publishes. Surfaced by the 26.8-alpha cut: the tarball landed but the ~1 GB ISO upload timed out at the Forgejo reverse proxy.
Changed
furtka app list --jsonnow mirrors/api/appsfield-for-field — previously the CLI emitted a slim projection missingdescription_long,open_url, andsettings. Anyone piping the CLI output into jq for automation was seeing an incomplete view.
26.8-alpha - 2026-04-20
Added
- Live-installer ISO attached to the Forgejo release page.
.forgejo/workflows/release.ymlmoves to the self-hosted runner, builds both the self-update tarball and the ISO, andscripts/publish-release.shuploads the ISO as a fourth release asset (furtka-<version>.iso) alongside the existing tarball + sha256 + release.json. Fresh-install users can now grab the ISO from the release page instead of hunting throughbuild-iso.ymlartifact retention windows. ISO build step iscontinue-on-errorso an ISO flake doesn't hold back the core tarball that running boxes need for self-update. - Reboot + Shut down buttons on
/settings. Replaces the two "Coming next" placeholders with real actions backed byPOST /api/furtka/power({"action": "reboot" | "poweroff"}). Handler kicks a delayedsystemd-run --on-active=3s systemctl {reboot|poweroff}so the HTTP response reaches the browser before the kernel loses network. Each button opens a native confirm dialog first (reboot: "back in ~30 s", shut down: "need to press the physical power button"), then the UI swaps to a status line and — after a reboot — polls/furtka.jsonuntil the box is back, reloading the page automatically. No auth (same posture as install/remove). - Manifest
open_urlfield + Open button in/appsand on the landing page. Apps declare a URL template (e.g.smb://{host}/filesfor fileshare,http://{host}:3001/for Uptime Kuma); the UI substitutes{host}with the current browser's hostname at render time so the link follows however the user reached Furtka (furtka.local, raw IP, a future reverse-proxy hostname). The landing page's hardcodedif app.name === 'fileshare'special-case is gone — any app with anopen_urlin its manifest now gets a proper "Open" link. The core seedapps/fileshare/manifest.jsonbumps to v0.1.2 to carry it.
Changed
.btnCSS class introduced so an<a>rendered-as-button lines up with its<button>siblings in.buttons. Needed because "Open" is a real link (middle-click, copy URL, screen readers) and HTML doesn't let<button>carryhref.
Notes
26.7-alphawas tagged but never published — the tag push didn't triggerrelease.yml(Forgejo race with the concurrent main push).26.8-alphasupersedes it and carries the same content plus power actions.
26.6-alpha - 2026-04-20
Added
- Apps catalog synced independently of core. A new
daniel/furtka-appsForgejo repo carries the bundled app catalog; running boxes pull the latest release viafurtka-catalog-sync.timer(10 min post-boot + daily, ±6 h jitter) and extract atomically into/var/lib/furtka/catalog/. The resolver now prefers catalog apps over the seed/opt/furtka/current/apps/tree that ships inside the core release tarball, so apps can update without cutting a Furtka core release. Manual trigger: "Sync apps catalog" button on/apps, orsudo furtka catalog syncat the console. Fresh boxes with no network fall back to the seed, so offline first-boot still shows installable apps. Installed apps are never auto-swapped — users click Reinstall in/appsto move an existing install onto a newer catalog version (settings merge-preserved via the existinginstaller.install_frompath). - Catalog CLI:
furtka catalog sync [--check] [--json]+furtka catalog status [--json]. Same shape as the corefurtka updatecommands. - Catalog API endpoints:
POST /api/catalog/sync/check,POST /api/catalog/sync/apply(detached viasystemd-runfor symmetry with/api/furtka/update/apply),GET /api/catalog/status. The existing/api/bundledendpoint keeps working as a backwards-compat alias for/api/apps/available, which now returns the union of catalog + seed apps with a new"source"field on each entry ("catalog"|"bundled").
Changed
furtka._release_commonextracted fromfurtka.updater. Bothupdaterand the newcatalogmodule now share one implementation of the Forgejo-releases-API call, SHA256 verification, path-traversal-guarded tarball extraction, and CalVer comparison. Public updater surface unchanged._link_new_unitsnow auto-enables newly-linked.timerunits. On self-update, a fresh timer file (e.g.furtka-catalog-sync.timeradded in this release) needssystemctl enableto actually start firing — linking alone isn't enough. Fresh installs get their enable via the webinstaller's_FURTKA_UNITSlist as before.
Fixed
- SHA-256 CA fingerprint no longer overflows the
/settingsLocal HTTPS card on narrow viewports..kv ddgrid items now setmin-width: 0+overflow-wrap: anywhereso the colon-separated hex string breaks within the card's right edge instead of pushing past it.
26.5-alpha - 2026-04-20
Fixed
- HTTPS handshake regression on the installed box (#10). Phase 1 shipped two linked bugs: the
:443 { tls internal }site block had no hostname, so Caddy never issued a leaf cert and every SNI handshake died withSSL_ERROR_INTERNAL_ERROR_ALERT; and bothfurtka.httpsand the Caddyfile's/rootCA.crthandler referenced/var/lib/caddy/.local/share/caddy/pki/…, a path that doesn't exist because our systemd unit setsXDG_DATA_HOME=/var/lib. Force-HTTPS toggle made the brokenness user-visible by redirecting working HTTP to dead HTTPS. Fixed: the Caddyfile now ships a__FURTKA_HOSTNAME__.local, __FURTKA_HOSTNAME__ { tls internal }block with the placeholder substituted at install time (webinstaller/app.py) and on every self-update (furtka.updater._refresh_caddyfilereads/etc/hostname).auto_https disable_redirectskeeps Caddy's built-in redirect out of the way of the/settingstoggle. PKI paths corrected in bothfurtka/https.pyandassets/Caddyfile. Verified end-to-end on the 192.168.178.110 test VM: TLS 1.3 handshake completes, leaf cert issued,/rootCA.crtreturns 200.
Changed
- Wizard footer version is now dynamic.
webinstaller/app.pyresolves the Furtka version at startup via a Flask context processor — reads/opt/furtka/VERSIONon the live ISO (written byiso/build.shfrompyproject.tomlat build time), falls back topyproject.tomlin dev runs, then to literal"dev". The 26.4 footer was hand-pinned and drifted within hours of release; that follow-up item is now closed. - Docs realigned with 26.4-alpha reality.
apps/README.mdadded (manifest schema, volume namespacing,.env.exampleguardrails, SVG sanitiser limits, install/test flow). RootREADME.mdroadmap updated with Phase 1 HTTPS + smoke-VM pipeline as shipped items and 26.4-alpha in the release list.iso/README.mdcorrected: mDNS is wired (not "later milestone"), post-install default URL ishttp://furtka.local(notproksi.local), HTTPS is available viatls internalsince 26.4.website/README.mdnow documents the auto-deploy on push-to-main as the default path, manualdeploy.shas the SSH-hop fallback.
26.4-alpha - 2026-04-18
Added
- Local HTTPS via Caddy
tls internalon port 443. Caddy generates a per-box local root CA on first start; the Caddyfile now serves both:80and:443from the same routes. HTTP stays on by default — no regression for users who haven't trusted the CA yet. New "Local HTTPS" section in/settingsshows the CA's SHA-256 fingerprint, offers a one-click download ofrootCA.crt, links to the per-OS install guide at/https-install/, and exposes an opt-in "force HTTPS" toggle that only unhides itself once the current browser has already trusted the cert (so enabling it can't lock the user out of the settings page). Backend:GET /api/furtka/https/statusandPOST /api/furtka/https/forceinfurtka.https. The force toggle drops a Caddy import snippet into/etc/caddy/furtka.d/redirect.caddyfileand reloads Caddy; reload failure automatically rolls the snippet state back so a bad config can't wedge the next service start. - Impressum + Datenschutzerklärung on furtka.org (both DE and EN) covering §5 DDG and Art. 13 GDPR. Linked from the site footer on every page; bilingual with DE as the legally binding version.
- Auto-deploy of furtka.org on push-to-main. New
.forgejo/workflows/deploy-site.ymlruns on the self-hosted runner (which is forge-runner-01 — the webserver host), so the deploy is just a local rsync +hugo --minifyinto/var/www/furtka.org/. No SSH, no secrets. Manualwebsite/deploy.shremains for out-of-band deploys. - Post-build smoke VM on Proxmox test host 192.168.178.165. Every
build-isorun boots the freshly built ISO in a throwaway VM on pollux (8 GiB RAM / 2 vCPU — the 4 GB default OOM-ed the host during mkinitcpio), then curls:5000to confirm the webinstaller is alive. VMs in VMID range 9000–9099 tagged with the commit SHA; last 5 kept for post-mortem debugging. Optionalworkflow_dispatch"Smoke latest ISO" re-tests the cached ISO in ~2 min without rebuilding. Step-levelcontinue-on-errormeans a VM-side flake doesn't mark the ISO build red.
Fixed
- Settings page "Installed" field now refreshes after a self-update. The
/api/furtka/update/checkresponse already carriescurrent— the settings JS now drivesupd-currentfrom it the same way it drivesupd-latest, so clicking "Check for updates" after a successful update reflects the new installed version without a force-reload. - Auto-reload on update completion is now reliable. Clicking "Update now" arms a 45 s fallback
setTimeout(location.reload)in addition to the existing/update-state.jsonpolling loop. If the mid-apply API restart drops the poll connection beforestage: doneis ever observed (as seen on the 2026-04-16 VM test), the fallback still brings the page up on the new version. The fallback is cleared ondone(5 s reload wins) orrolled_back(user needs the error visible). - Version string in the webinstaller footer was pinned at
26.0-alphaand didn't track releases. Bumped to26.4-alphafor this release; follow-up will make it render frompyproject.tomldynamically.
26.3-alpha - 2026-04-16
Fixed
- Release workflow no longer depends on
jq. The previousapt-get install -y jqstep hung on a slow mirror for 15+ minutes and stalled the 26.2-alpha publish.publish-release.shnow assembles the release-create payload via a tinypython3 -cblock — Python is always available on the Forgejo Actions runner.apt-getpath removed entirely.
26.2-alpha - 2026-04-16
Fixed
- Updater "Check for updates" no longer 404s when every release is a pre-release.
check_update()queried Forgejo's/releases/latest, which silently excludes pre-releases (anything tagged-alpha/-beta/-rc) and returns 404 when there is no stable release. Switched to/releases?limit=1, which Forgejo sorts newest-first across all release kinds. During the alpha stage where every tag is a pre-release this is the only thing that works; once we tag a stable release, the same query still picks it up.
26.1-alpha - 2026-04-16
Added
-
Furtka self-update (Phase 2). Tagging a release on main fires
.forgejo/workflows/release.yml, which packagesfurtka/+apps/+ a root-levelVERSIONfile asfurtka-<tag>.tar.gz, uploads it plus a.sha256+release.jsonto the Forgejo releases page, and makes the release available to running boxes. New CLI:furtka update [--check]+furtka rollback. New endpoints:POST /api/furtka/update/check+/apply+GET /api/furtka/update/status. UI: "Furtka updates" card on/settingsshows installed vs latest, Update button runs the apply flow detached viasystemd-run, progress polls/update-state.jsonserved by Caddy so the mid-update API restart doesn't interrupt reporting. Atomic/opt/furtka/currentsymlink flip, auto-rollback on health-check failure post-restart, SHA256-verified downloads. -
Per-app container image updates (Phase 1).
POST /api/apps/<name>/updaterunsdocker compose pull, compares the running container's image digest to the just-pulled local image digest per service, and only restarts containers whose image actually changed. Update button on each installed-app row in/apps. Keepsimage: :latestpins simple — no compose-file mutations. -
Per-version install layout on
/opt/furtka/. Install now extracts the resource-manager payload to/opt/furtka/versions/<VERSION>/and creates/opt/furtka/currentas an atomic symlink; updates flip the symlink in place andsystemctl linkevery unit from the shippedassets/systemd/tree. Runtime JSON (status.json,furtka.json,update-state.json) moved to/var/lib/furtka/so self-updates never clobber it. -
On-box UI uplevel across three pages sharing one design system (
/style.cssserved by Caddy). Redesigned landing page with a "Your apps" tile grid driven by/api/apps, afileshareapp tile that deep-links tosmb://<host>.local/files, status tiles, and subtle "Coming next" links tofurtka.org./appspage renders real app icons inlined from each manifest'sicon.svg(defensive SVG sanitiser — strips script/on*/javascript: content, 16 KB cap). New/settingspage with About-this-box, Appearance, Furtka-updates, and Coming-next sections. Persistent top nav (Jakob's Law) on every page. Light-mode support viaprefers-color-scheme. -
Webinstaller step 2 (boot drive) now shows size / type / health chips plus a "Recommended" badge on the auto-selected drive instead of a raw numeric score.
-
Forgejo branch protection on
main— no direct pushes except owner-whitelisted, required status checks (CI / lint*,CI / test*,CI / validate-json*), applied via the idempotentops/forgejo/apply-branch-protection.shscript. -
In-browser app settings, so users no longer need SSH +
vimto configure an app before first install. Manifest gains optionalsettings(name/label/description/type/required/default) anddescription_longfields. Installing a bundled app opens a form rendered from the manifest; installed apps grow a "Settings" button that edits merged values (password fields blank = keep current). API:POST /api/apps/installnow accepts asettingsobject in the JSON body; newGET/POST /api/apps/<name>/settingsfor inspecting and updating an installed app. Password values never leave the server. -
nanoadded to the installer package list so users have a beginner-friendly editor at the console/SSH (wasvim-only, whichcommand not found'd under Arch 4.x because it was actually missing from the package set too). -
opensshadded explicitly to the installer package list andsshdadded to enabled services.archinstall: truein archinstall 4.x did not actually install openssh-server, so the documented recovery path (SSH → edit.env) silently failed. -
Forgejo Actions runner live on Proxmox VM (
forge-runner-01, Ubuntu 24.04) with DinD sidecar — CI green end-to-end. Setup scripts inops/forgejo-runner/. -
Walking-skeleton live ISO (
iso/build.sh). Overlays an Archrelengprofile with Flask + the webinstaller, bakes a systemd unit that auto-starts the wizard on boot, produces a hybrid BIOS/UEFI ISO viamkarchisoin a privilegedarchlinux:latestcontainer. Tested booting under OVMF in Proxmox — wizard screens 1–3 respond athttp://<vm-ip>:5000. -
Public website at furtka.org (
website/). Hugo static site, English + German, served from/var/www/furtka.orgonforge-runner-01via nginx. Upstream openresty proxy handles TLS. Intentionally minimal single-page copy while the project is pre-alpha. Deploy is./website/deploy.sh(rsync + remote Hugo build); one-time VM setup inops/nginx/setup-vm.sh.
Changed
- Every on-box asset (landing page, settings page, style.css, status/welcome scripts, systemd units, Caddyfile) moved from inline Python string constants in
webinstaller/app.pyinto real files underfurtka/assets/. The installer reads them from disk at install time; the self-updater ships them in the release tarball. - Settings-button label went from "Einstellungen" (prototyping leftover) to "Settings" — rest of the UI chrome is English.
- Keyboard layout at the TTY now follows the chosen installer language (
de→de,pl→pl,en→us) instead of hardcodingus. Previously German users couldn't type/,-, or=at the recovery console. fileshareapp:description_long+settings(SMB_USER, SMB_PASSWORD) for the new settings form. Docker-level healthcheck fromdperson/sambais disabled in the compose override — it timed out under normal operation and marked a working share "unhealthy" indocker ps.- Project name finalized: Furtka. Working title "Homebase" retired. Domain
furtka.orgregistered via Strato 2026-04-13. - Managed gateway NS hostnames updated from
ns1.homebase.cloud/ns2.homebase.cloudtons1.furtka.org/ns2.furtka.org. - Python package renamed from
homebase→furtkainpyproject.toml.
26.0-alpha - 2026-04-13
First tagged snapshot. Pre-alpha — the installer does not yet boot, but the design is locked and the prototype components are shaped.
Added
- Installer webapp prototype (
webinstaller/) — Flask app with 3-step wizard (hostname → drive → overview), serves drive list viadrives.py::list_scored_devices(). - Drive scoring module (
webinstaller/drives.py) — scores attached disks by type (NVMe/SSD/HDD), SMART health (smartctl -H), and size. Consumed by the installer and usable as a CLI. - Base archinstall configuration (
archinstall/user_configuration.json) — systemd-boot, ext4, Docker + Compose preinstalled, server profile, SSH. Credentials template atarchinstall/user_credentials.example.json(real credentials gitignored). - Installer wireframes (
docs/installer-wireframes.md) — Robert's hand-drawn 4-screen UX sketches. - Competitor analysis (
docs/competitors.md) — CasaOS, Umbrel, YunoHost reviewed across install flow, hardware detection, app store UX, reverse proxy/SSL, user complaints. Key finding: device-aware wizard + managed gateway are uncontested differentiators. - Wizard flow spec (
docs/wizard-flow.md) — 8-screen first-boot flow extending Robert's wireframe with YunoHost-style domain/SSL/diagnostic/confirm screens. Locked tech picks with rejected alternatives. - Project README — vision, principles, architecture, key decisions, landscape, roadmap.
Decisions locked
- Reverse proxy: Caddy (auto Let's Encrypt, simplest config)
- Identity provider: Authentik (bundled SSO, every app auto-wired at install)
- Managed gateway DNS: NS delegation to
ns1.furtka.org/ns2.furtka.org(wildcard cert via Let's Encrypt DNS-01) - Local HTTPS: Local CA installed by user once (no browser warnings on
*.proksi.local) - Base OS: Arch (rolling, Debian remains fallback)
- Containers: Docker + Compose
- License: AGPL-3.0