7 Commits

Author SHA1 Message Date
librelad
d941f59388 feat(app): generic installApp driver + dispatcher fallback (Wave A)
The 31 containers/<app>/<app>.sh files each defined install<App>() with
the SAME 10-step sequence — ~4,000 lines of duplicated boilerplate.
Replaces all that with one generic driver + hook surface.

scripts/app/install/app_install.sh:
  installApp <slug> [config_variables]
    — Dispatches on $<slug> (c/u/s/r/i) the same way the per-app .sh
      files did. Same convention; dockerInstallApp's existing
      `declare $app=i` callsite needs no change.
    — Runs the standard sequence: dockerConfigSetupToContainer →
      dockerComposeSetupFile → optional .env copy → fixPermissions →
      dockerComposeUpdateAndStartApp → standard post-install steps
      (appUpdateSpecifics, setupHeadscale, databaseInstallApp,
      webuiContainerSetup, monitoring registration) → final message.
    — Hooks (all declare-f-gated, silent no-op when absent):
        <slug>_install_pre / _post_setup / _post_compose / _post_start
        <slug>_install_message_data   (echoes extra args for menu)
        <slug>_install_post
        <slug>_uninstall_pre / _post
        <slug>_stop_post
        <slug>_restart_post
      Hooks live in containers/<app>/tools/<app>_tools.sh (auto-sourced
      per the modular-per-app-tools convention).

function_install_app.sh:
  When no install<App>() function exists, fall through to
  `installApp <app_name>` instead of erroring. So an app with no .sh
  at all becomes a zero-byte addition — drop in <app>.config +
  docker-compose.yml + <app>.svg, done.

containers/linkding/linkding.sh:
  Deleted (canary). Linkding's body was 100% standard sequence;
  fallback handles it identically. Smoke-tested with stubbed helpers
  — dispatcher fires, generic runs full flow, monitoring integration
  + final-message hook plumbing all intact.

Wave B (next): delete the .sh for every other 'pure-boilerplate' app
(~15 candidates per the survey). Wave C: extract custom logic from
the 7 fat apps into hooks before deleting their .sh.

Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-27 01:43:08 +01:00
librelad
52e0227bb6 chore(cleanup): retire appGenerate — dead-on-arrival app-skeleton wizard
`libreportal app generate <name>` (and the menu's "g. Generate App" entry)
was broken three independent ways and incompatible with the per-app
architecture the project actually uses now:

  1. Copies from $install_containers_dir/template/ which doesn't exist —
     the only template/ in the tree was in scripts/unused/OLD_CONTAINERS/
     and was never installed into the live tree. cp -r would just fail.

  2. Every sed call used BSD/macOS syntax `sed -i '' -e …`. On Linux
     (every distro this targets) the empty '' becomes a positional file
     argument, so the substitutions never ran. 8 calls, all broken.

  3. Even if it had run, the produced skeleton would have been a
     pre-modular-tools / pre-per-port-subdomain app shape: no tools/,
     no scripts/ subdir, HOST_NAME=test in the .config. Every active
     containers/<app>/ today carries the modular layout the rest of the
     framework expects.

Plus the recent cleanups (the prompt loop fix in 9ffc8e4, the per-port
subdomain refactor in 2e4f420) had been peeling pieces off it without
the root question — does the function still belong? — getting asked.

Delete the whole surface:
  - scripts/app/app_generate.sh (157 lines, the function body)
  - scripts/unused/OLD_CONTAINERS/template/ (the never-installed source
    files appGenerate would have copied — stale enough to still carry
    HOST_NAME=test, CFG_<X>_HOST_NAME, and 248 lines of compose template)
  - menu entry "g. Generate App" + its dispatch in menu_main.sh
  - "generate" case branch in cli_app_commands.sh
  - `libreportal app generate` line in cli_app_header.sh
  - The corresponding entries auto-drop from files_app.sh +
    function_manifest.sh via regen.

New apps are added the way the catalog already grew — by hand-crafting
containers/<app>/{<app>.sh, <app>.config, docker-compose.yml,
tools/<app>.tools.json, scripts/<app>_*.sh}. Copying an existing app's
folder + renaming is the closest thing to a "generator" and it's a one-
command operation.

Net: -556 lines, no behaviour lost (the function never worked).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-26 23:48:35 +01:00
librelad
898068a390 refactor(apps): make app tools + helpers fully self-contained per app
Each app now carries everything under containers/<app>/: Tools-tab actions in
tools/ (declaration <app>.tools.json + function <app>_<tool_id>.sh) and logic
helpers in scripts/ (e.g. <app>_auth.sh). The container scan live-sources every
.sh under the app (maxdepth 3, prunes only resources/) and webui_tools.sh
auto-merges the .tools.json, so an app is a true drop-in — no central edit, no
array regen.

- Empty the central webui_tools.sh heredoc; all 34 tools across 11 apps now
  come from per-app declarations (verified byte-identical to the old output).
- Retire the orphaned mattermost tool scripts to scripts/unused (there is no
  containers/mattermost; its install fn already lived in unused).
- Update the dispatch comment/error path, the auth-adapter doc, and
  DEVELOPMENT.md to the new convention.
- Regenerate static arrays (files_app.sh no longer lists app/containers/*).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-25 22:45:33 +01:00
librelad
3bc91eef55 refactor(tools): modular per-app tools convention (containers/<app>/tools/) + migrate adguard
Establish the self-contained tools convention and prove it on a core app:
- discovery now reads containers/<app>/tools/<app>.tools.json (the tools/ subfolder);
  tool functions live at containers/<app>/tools/*.sh, auto-sourced by the container
  scan (depth 3) — no scripts/app/ entry, no array regen.
- adguard migrated: its 2 Tools-tab actions (reset_password, apply_dns_updater) moved
  to containers/adguard/tools/ + tools/adguard.tools.json, and dropped from the
  central webui_tools.sh heredoc. adguard_auth.sh stays in scripts/app/ — it's a logic
  helper, NOT a tool (the key distinction: only DECLARED tools move).

Central + per-app styles coexist (pihole etc. still central), so the remaining apps
can migrate one at a time with nothing breaking. Verified: heredoc valid sans adguard,
per-app merge re-adds adguard's 2 tools, scripts array dropped the moved fns.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-25 22:30:49 +01:00
librelad
ef67ab9b71 refactor(infra): move hosting apps out to LibrePortal-Infra
getlibreportal (downloads host) + weblibreportal (website) — including the website
Eleventy source and the publish tool functions — now live in the separate
LibrePortal-Infra repo (Webstar/LibrePortal-Infra). They're the project's own
outward-facing hosting, not something users install, so the base stays clean.

Removed from base: containers/{getlibreportal,weblibreportal}, the
scripts/app/containers/<app>/<app>_publish.sh tool functions, and their entries in
webui_tools.sh; regenerated the sourced-file arrays; dropped the dead .gitignore
docroot lines. scripts/release/make_release.sh stays here (it builds the base
release). docs/DEVELOPMENT.md now points publishing at LibrePortal-Infra.

LibrePortal-Infra overlays onto an install and picks up releases/catalogue from the
base tree — see its README.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-25 21:15:38 +01:00
librelad
8800f524d4 feat(tools): WebUI/CLI publish tool for getlibreportal + weblibreportal
Surface the publish step through the existing Tools system (apps-tools.json -> Tools
tab + 'libreportal app tool <app> publish'), so the docroot can be (re)built from
the WebUI instead of a manual cd + script.

- webui_tools.sh: declare a 'publish' tool (no inputs) for getlibreportal + weblibreportal.
- scripts/app/containers/getlibreportal/getlibreportal_publish.sh (appGetlibreportalPublish):
  runs the host's publish.sh into the served data dir, as the container user (owns it).
- scripts/app/containers/weblibreportal/weblibreportal_publish.sh (appWeblibreportalPublish):
  builds Eleventy as the manager (owns the install tree), then syncs the result into
  the container-user-owned docroot — handling the build-vs-write owner split.
- Both guard for the build prerequisites (repo source / npm / dist) and fail with a
  clear message; regenerated the sourced-file arrays.

Honest status: scaffolding only — wiring verified (dispatch names match, files sourced,
JSON valid) but the end-to-end tool RUN is untested, and it's build-box-only (needs the
repo checkout + npm + a built dist/). These hosting apps are dev-only and headed for a
separate repo; this just sets the automation up so it's ready to iterate on.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-25 21:02:53 +01:00
librelad
875a60f90f LibrePortal v0.1.0 — initial release
A free, open, self-hosted app platform (GNU AGPLv3): one-click app deploys,
Traefik reverse proxy with automatic SSL, rootless Docker support, gluetun
VPN routing, and a web dashboard to manage it all.

Free & open forever to self-host; optional paid hosted services fund it.
See PROMISE.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-21 20:37:54 +01:00