steps/<key>.felhom.yml: gate rule 4b, writer, backfill (8) (R-664)
gates / gates (push) Successful in 2s
gates / gates (push) Successful in 2s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -1,3 +1,16 @@
|
||||
## Every step keeps its own `.felhom.yml` (2026-09-24 night, R-664)
|
||||
|
||||
**No `image:` line moved.** Controller v0.269.0 reads them.
|
||||
|
||||
- `steps/<step_key(to)>.felhom.yml` beside every step's compose: the box judges a step with ITS probe, memory
|
||||
request and applied record, not the head's. `ladder.step_meta_file`, `ladder.strip_ladder_block` (a step's copy
|
||||
carries no ladder).
|
||||
- **Gate rule 4b:** a step without its `.felhom.yml`, or one without a healthcheck while the template has one, is
|
||||
refused. Decoys: the file missing; a file with the right NAME and no healthcheck (red-proof: rule off → both pass
|
||||
wrongly). Suite 86 cases OK.
|
||||
- **Writer:** `--write-ladder` also keeps the superseded step's `.felhom.yml`. **Backfill** (`steps_meta_backfill.py`,
|
||||
one-off): 8 files, each from the newest commit whose compose names that step's images.
|
||||
|
||||
## Every step keeps its own definition — the box can climb one step at a time (2026-09-24, `09` §6.4 part 5, R-653, R-656, R-663)
|
||||
|
||||
**No `image:` line moved.** The box half ships in controller v0.268.0.
|
||||
|
||||
@@ -22,6 +22,8 @@ WHAT IT CHECKS, per template that carries `update_ladder:` (format and field rul
|
||||
4. every entry but the newest carries its OWN definition at `steps/<step_key(to)>.yml`, whose
|
||||
images per service are EXACTLY that entry's `to` (`09` §6.4 part 5: the box pins that file, one
|
||||
step per press). The name alone is not the fact: the file's own `image:` lines are read.
|
||||
4b. ... and its own `.felhom.yml` at `steps/<step_key(to)>.felhom.yml` (R-664), with a healthcheck
|
||||
when the template has one.
|
||||
|
||||
A template WITHOUT a ladder passes here — it has never been moved since the gate existed, and its
|
||||
first move is refused by the twin unless that move brings the first entry.
|
||||
@@ -65,6 +67,13 @@ def check_app(app_dir):
|
||||
got = ladder.images_in(open(sp, encoding="utf-8").read())
|
||||
if got != to:
|
||||
problems.append("%s names %s, but entry %d's `to` is %s" % (ladder.step_file(to), got, i + 1, to))
|
||||
# rule 4b (R-664, 2026-09-24): the step's own .felhom.yml — the box judges the step with it.
|
||||
smp = os.path.join(app_dir, ladder.step_meta_file(to))
|
||||
if not os.path.isfile(smp):
|
||||
problems.append("entry %d of %d has no %s — the box would judge the step with the head's probe (R-664)"
|
||||
% (i + 1, len(entries), ladder.step_meta_file(to)))
|
||||
elif "healthcheck:" not in open(smp, encoding="utf-8").read() and "healthcheck:" in open(os.path.join(app_dir, ".felhom.yml"), encoding="utf-8").read():
|
||||
problems.append("%s carries no healthcheck: while the template does — not a real step file" % ladder.step_meta_file(to))
|
||||
if entries:
|
||||
current = ladder.images_in(open(comp, encoding="utf-8").read())
|
||||
head = entries[-1].get("to")
|
||||
|
||||
@@ -210,3 +210,19 @@ def step_key(to):
|
||||
def step_file(to):
|
||||
"""The step definition's path RELATIVE to the template directory."""
|
||||
return "steps/%s.yml" % step_key(to)
|
||||
|
||||
|
||||
def step_meta_file(to):
|
||||
"""The step's own `.felhom.yml` (R-664, 2026-09-24): its probe, memory limits and applied record — the
|
||||
box judges the step with it. RELATIVE to the template directory."""
|
||||
return "steps/%s.felhom.yml" % step_key(to)
|
||||
|
||||
|
||||
def strip_ladder_block(felhom_text):
|
||||
"""A `.felhom.yml` without its update_ladder block (and the header comment the writer puts above it):
|
||||
a step's own copy carries no ladder — only the template's is read for one."""
|
||||
lines = felhom_text.splitlines()
|
||||
for i, l in enumerate(lines):
|
||||
if l.startswith("# update_ladder") or l.startswith("update_ladder:"):
|
||||
return "\n".join(lines[:i]).rstrip("\n") + "\n"
|
||||
return felhom_text
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
"""steps_meta_backfill.py — ONE-OFF (2026-09-24 night, R-664): write `steps/<key>.felhom.yml` beside every step
|
||||
file, from the NEWEST commit whose compose names that step's images — the .felhom.yml served WITH that
|
||||
definition — without its update_ladder block. Never overwrites."""
|
||||
import os, subprocess, sys
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
import ladder # noqa: E402
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
def git(*a):
|
||||
return subprocess.run(["git", "-C", ROOT] + list(a), capture_output=True, text=True, check=True).stdout
|
||||
|
||||
|
||||
def main():
|
||||
n = 0
|
||||
for app in sorted(os.listdir(os.path.join(ROOT, "templates"))):
|
||||
d = os.path.join(ROOT, "templates", app)
|
||||
fy = os.path.join(d, ".felhom.yml")
|
||||
if not os.path.isfile(fy):
|
||||
continue
|
||||
entries, _, errs = ladder.parse(open(fy, encoding="utf-8").read())
|
||||
if errs or len(entries) < 2:
|
||||
continue
|
||||
commits = git("log", "--format=%H", "--", "templates/%s" % app).split()
|
||||
for i, e in enumerate(entries[:-1]):
|
||||
dst = os.path.join(d, ladder.step_meta_file(e["to"]))
|
||||
if os.path.exists(dst):
|
||||
continue
|
||||
for c in commits:
|
||||
try:
|
||||
comp = git("show", "%s:templates/%s/docker-compose.yml" % (c, app))
|
||||
except subprocess.CalledProcessError:
|
||||
continue
|
||||
if ladder.images_in(comp) == e["to"]:
|
||||
meta = git("show", "%s:templates/%s/.felhom.yml" % (c, app))
|
||||
open(dst, "w", encoding="utf-8").write(ladder.strip_ladder_block(meta))
|
||||
print("WROTE %-10s entry %d -> %s from %s" % (app, i + 1, ladder.step_meta_file(e["to"]), c[:12]))
|
||||
n += 1
|
||||
break
|
||||
else:
|
||||
print("MISS %-10s entry %d" % (app, i + 1))
|
||||
print("steps_meta_backfill: %d written" % n)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -437,16 +437,23 @@ def test_record_cases(clone):
|
||||
two = ladder_of(tr_entry({"navidrome": prev}, mid, {"navidrome": TR_D1}),
|
||||
tr_entry(mid, frm, {"navidrome": TR_D1}))
|
||||
step_rel = "templates/navidrome/" + _l.step_file(mid)
|
||||
meta_rel = "templates/navidrome/" + _l.step_meta_file(mid)
|
||||
meta_body = lambda t: _l.strip_ladder_block(io.open(os.path.join(clone, NF), encoding="utf-8").read())
|
||||
step_body = lambda t: swap_image("navidrome", old, mid["navidrome"])(io.open(os.path.join(clone, NC), encoding="utf-8").read())
|
||||
case_tr_static("FACT: a two-step ladder with NO steps/ file for the first step", clone,
|
||||
[(NF, two)], 1, ("has no definition",))
|
||||
case_tr_static("GENUINE: a two-step ladder whose first step carries its definition", clone,
|
||||
[(NF, two), (step_rel, step_body)], 0)
|
||||
[(NF, two), (step_rel, step_body), (meta_rel, meta_body)], 0)
|
||||
case_tr_static("DECOY: the steps/ file has the right NAME and names the head's image", clone,
|
||||
[(NF, two), (step_rel, lambda t: io.open(os.path.join(clone, NC), encoding="utf-8").read())],
|
||||
[(NF, two), (step_rel, lambda t: io.open(os.path.join(clone, NC), encoding="utf-8").read()), (meta_rel, meta_body)],
|
||||
1, ("names",))
|
||||
case_tr_static("DECOY: the step's definition sits beside the template under another name", clone,
|
||||
[(NF, two), ("templates/navidrome/steps/0.2.0.yml", step_body)], 1, ("has no definition",))
|
||||
# R-664: the step's own .felhom.yml
|
||||
case_tr_static("FACT: the step has its compose but no .felhom.yml", clone,
|
||||
[(NF, two), (step_rel, step_body)], 1, ("R-664",))
|
||||
case_tr_static("DECOY: the step's .felhom.yml exists by NAME and holds no healthcheck", clone,
|
||||
[(NF, two), (step_rel, step_body), (meta_rel, lambda t: "display_name: Navidrome\n")], 1, ("not a real step file",))
|
||||
|
||||
def main():
|
||||
gate = os.path.join(ROOT, "scripts", "check-engine-major.py")
|
||||
|
||||
@@ -122,6 +122,9 @@ class WriterTest(unittest.TestCase):
|
||||
sp = os.path.join(self.tmp, "templates", "navidrome", ladder.step_file({"navidrome": "deluan/navidrome:" + NEXT}))
|
||||
self.assertTrue(os.path.isfile(sp), out)
|
||||
self.assertEqual(open(sp).read(), at_step1, "the step file must be the definition AS SERVED, fixes included")
|
||||
smp = os.path.join(self.tmp, "templates", "navidrome", ladder.step_meta_file({"navidrome": "deluan/navidrome:" + NEXT}))
|
||||
self.assertTrue(os.path.isfile(smp), "the step's own .felhom.yml (R-664) was not written")
|
||||
self.assertNotIn("update_ladder:", open(smp).read())
|
||||
import subprocess
|
||||
r = subprocess.run([sys.executable, os.path.join(HERE, "check-test-record.py"), "--root", self.tmp,
|
||||
"navidrome"], capture_output=True, text=True)
|
||||
|
||||
@@ -832,6 +832,10 @@ def write_ladder(argv) -> int:
|
||||
sp.parent.mkdir(parents=True, exist_ok=True)
|
||||
sp.write_text(comp)
|
||||
print(f"STEP {app}: the superseded step {cur} keeps its definition at {ladder.step_file(cur)}")
|
||||
smp = tdir / ladder.step_meta_file(cur)
|
||||
if not smp.exists(): # R-664: and its own .felhom.yml, without the ladder
|
||||
smp.write_text(ladder.strip_ladder_block(fy_p.read_text()))
|
||||
print(f"STEP {app}: … and its .felhom.yml at {ladder.step_meta_file(cur)}")
|
||||
# move the compose, per service, on that service's own image: line
|
||||
out, svc = [], None
|
||||
for line in comp.splitlines():
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Emby"
|
||||
description: "Személyes média szerver élő TV és DVR támogatással"
|
||||
category: "media"
|
||||
subdomain: "emby"
|
||||
slug: "emby"
|
||||
# catalog_since: the date THIS repo last changed this app's pinned images. Any commit that
|
||||
# changes an image: line must set this to the same day (see CLAUDE.md).
|
||||
catalog_since: "2026-09-22"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "512M"
|
||||
mem_limit: "2048M"
|
||||
pi_compatible: false
|
||||
needs_hdd: true
|
||||
|
||||
# --- Backup classification (referential coupling; see felhom.eu documentation/audits/SPIKE-backup-classification-2026-07-14.md) ---
|
||||
backup:
|
||||
userdata:
|
||||
- path: media
|
||||
class: excluded # pure reader of the shared tree (:ro); state lives in volumes
|
||||
|
||||
# --- Deploy fields (first deployment only) ---
|
||||
deploy_fields:
|
||||
- env_var: DOMAIN
|
||||
label: "Domain"
|
||||
type: domain
|
||||
description: "A szerver domain neve"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: SUBDOMAIN
|
||||
label: "Aldomain"
|
||||
type: subdomain
|
||||
default: "emby"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: HDD_PATH
|
||||
label: "Médiatár útvonal"
|
||||
type: path
|
||||
required: true
|
||||
placeholder: "/mnt/felhom-drives/hdd_1"
|
||||
description: "A külső merevlemez elérési útja"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Személyes média szerver élő TV és DVR támogatással"
|
||||
docs_url: "https://emby.media/support/articles/Home.html"
|
||||
|
||||
use_cases:
|
||||
- 'Filmek, sorozatok, zene és fotók kezelése egy helyen'
|
||||
- 'Élő TV nézés és felvétel (DVR) TV tunerrel'
|
||||
- 'Automatikus transzkódolás bármilyen eszközhöz'
|
||||
- 'Szülői felügyelet és felhasználói profilok'
|
||||
- 'Szinkronizálás offline megtekintéshez mobilon'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg az emby.DOMAIN címet a böngészőben'
|
||||
- 'Kövesd a beállítás varázslót'
|
||||
- 'Hozd létre az admin fiókot'
|
||||
- 'Add hozzá a médiatárat a /media mappából'
|
||||
- 'Telepítsd az Emby alkalmazást eszközeidre'
|
||||
|
||||
prerequisites:
|
||||
- 'Külső HDD szükséges a médiafájlok tárolásához'
|
||||
- 'Legalább 2 GB szabad RAM ajánlott'
|
||||
- 'Emby Premiere előfizetés a prémium funkciókhoz (opcionális)'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 8096
|
||||
path: "/emby/system/ping"
|
||||
expect:
|
||||
status: 200
|
||||
|
||||
# --- English copy (localisation slice 5, R-560) --------------------------------------------
|
||||
# The Hungarian above is UNCHANGED. A box on English reads this block field by field; a missing
|
||||
# field shows the Hungarian one; a controller older than 0.257.0 ignores the block entirely.
|
||||
i18n:
|
||||
en:
|
||||
description: 'A personal media server with live TV and recording'
|
||||
app_info:
|
||||
tagline: 'A personal media server with live TV and recording'
|
||||
use_cases:
|
||||
- 'Films, series, music and photos in one place'
|
||||
- 'Watch and record live TV, with a TV tuner'
|
||||
- 'It re-encodes on the fly for whatever device you are on'
|
||||
- 'Parental controls and a profile for each person'
|
||||
- 'Sync to a phone to watch offline'
|
||||
first_steps:
|
||||
- 'Open emby.DOMAIN in your browser'
|
||||
- 'Follow the setup wizard'
|
||||
- 'Create the admin account'
|
||||
- 'Add your library from the /media folder'
|
||||
- 'Install the Emby app on your devices'
|
||||
prerequisites:
|
||||
- 'An external hard drive is needed to keep the media files on'
|
||||
- 'At least 2 GB of free RAM is recommended'
|
||||
- 'An Emby Premiere subscription for the premium features (optional)'
|
||||
deploy_fields:
|
||||
- env_var: DOMAIN
|
||||
label: 'Domain'
|
||||
description: 'The server domain name'
|
||||
- env_var: SUBDOMAIN
|
||||
label: 'Subdomain'
|
||||
description: 'The subdomain this app answers on'
|
||||
- env_var: HDD_PATH
|
||||
label: 'Media library path'
|
||||
description: 'The path to the external hard drive'
|
||||
placeholder: '/mnt/felhom-drives/hdd_1'
|
||||
@@ -0,0 +1,94 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Ghost"
|
||||
description: "Professzionális blog és hírlevél platform"
|
||||
category: "productivity"
|
||||
subdomain: "blog"
|
||||
slug: "ghost"
|
||||
# catalog_since: the date THIS repo last changed this app's pinned images. Any commit that
|
||||
# changes an image: line must set this to the same day (see CLAUDE.md).
|
||||
catalog_since: "2026-09-22"
|
||||
# Bare "/" is the public blog; the admin panel / setup wizard lives at /ghost/.
|
||||
open_path: "/ghost/"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "150M"
|
||||
mem_limit: "512M"
|
||||
pi_compatible: false
|
||||
needs_hdd: false
|
||||
|
||||
# --- Deploy fields (first deployment only) ---
|
||||
deploy_fields:
|
||||
- env_var: DOMAIN
|
||||
label: "Domain"
|
||||
type: domain
|
||||
description: "A szerver domain neve"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: SUBDOMAIN
|
||||
label: "Aldomain"
|
||||
type: subdomain
|
||||
default: "blog"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Professzionális blog és hírlevél platform"
|
||||
docs_url: "https://ghost.org/docs/"
|
||||
|
||||
use_cases:
|
||||
- 'Professzionális blog indítása és üzemeltetése'
|
||||
- 'Hírlevél küldés beépített email funkcióval'
|
||||
- 'SEO-optimalizált tartalom publikálás'
|
||||
- 'Tagság és fizetős tartalom kezelés'
|
||||
- 'Markdown és vizuális szerkesztő'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a blog.DOMAIN/ghost/ címet a böngészőben'
|
||||
- 'Hozd létre az admin fiókot a beállítás varázslóban'
|
||||
- 'Írd meg és publikáld az első posztodat'
|
||||
- 'Személyre szabd a témát és beállításokat'
|
||||
|
||||
prerequisites:
|
||||
- 'x86 processzor szükséges'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 2368
|
||||
|
||||
# --- English copy (localisation slice 5, R-560) --------------------------------------------
|
||||
# The Hungarian above is UNCHANGED. A box on English reads this block field by field; a missing
|
||||
# field shows the Hungarian one; a controller older than 0.257.0 ignores the block entirely.
|
||||
i18n:
|
||||
en:
|
||||
description: 'A professional blog and newsletter platform'
|
||||
app_info:
|
||||
tagline: 'A professional blog and newsletter platform'
|
||||
use_cases:
|
||||
- 'Start and run a professional blog'
|
||||
- 'Send a newsletter with the built-in e-mail feature'
|
||||
- 'Publish content that search engines can read'
|
||||
- 'Memberships and paid content'
|
||||
- 'A Markdown editor and a visual one'
|
||||
first_steps:
|
||||
- 'Open blog.DOMAIN/ghost/ in your browser'
|
||||
- 'Create the admin account in the setup wizard'
|
||||
- 'Write and publish your first post'
|
||||
- 'Make the theme and the settings your own'
|
||||
prerequisites:
|
||||
- 'An x86 processor is needed'
|
||||
deploy_fields:
|
||||
- env_var: DOMAIN
|
||||
label: 'Domain'
|
||||
description: 'The server domain name'
|
||||
- env_var: SUBDOMAIN
|
||||
label: 'Subdomain'
|
||||
description: 'The subdomain this app answers on'
|
||||
@@ -0,0 +1,144 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml — App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
# Place alongside docker-compose.yml in each stack directory:
|
||||
# /opt/docker/stacks/immich/.felhom.yml
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Immich"
|
||||
description: "Fotók és videók kezelése (Google Photos alternatíva)"
|
||||
category: "media"
|
||||
subdomain: "photos"
|
||||
|
||||
# --- Asset slug ---
|
||||
slug: "immich"
|
||||
# catalog_since: the date THIS repo last changed this app's pinned images. Any commit that
|
||||
# changes an image: line must set this to the same day (see CLAUDE.md).
|
||||
catalog_since: "2026-09-22"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "2048M"
|
||||
mem_limit: "4096M"
|
||||
pi_compatible: false
|
||||
needs_hdd: true
|
||||
|
||||
# --- Backup classification (referential coupling; see felhom.eu documentation/audits/SPIKE-backup-classification-2026-07-14.md) ---
|
||||
backup:
|
||||
hdd:
|
||||
- path: appdata/immich
|
||||
class: mandatory # managed upload library — DB-referenced (SQ3: restore-without = broken)
|
||||
userdata:
|
||||
- path: media/photos
|
||||
class: optional # external library, :ro — precious but re-scanned (explicit overrides ro-default)
|
||||
|
||||
# --- Deploy fields ---
|
||||
deploy_fields:
|
||||
- env_var: DOMAIN
|
||||
label: "Domain"
|
||||
type: domain
|
||||
description: "A szerver domain neve"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: SUBDOMAIN
|
||||
label: "Aldomain"
|
||||
type: subdomain
|
||||
default: "photos"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: DB_PASSWORD
|
||||
label: "Adatbázis jelszó"
|
||||
type: secret
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: HDD_PATH
|
||||
label: "Adattárolási útvonal"
|
||||
type: path
|
||||
required: true
|
||||
placeholder: "/mnt/felhom-drives/hdd_1"
|
||||
description: "A külső merevlemez elérési útja, ahol a fotók és videók tárolódnak"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: 'Google Photos alternatíva - automatikus fotó mentés és rendszerezés'
|
||||
docs_url: 'https://immich.app/docs/overview/introduction'
|
||||
|
||||
use_cases:
|
||||
- 'Fotók és videók automatikus mentése telefonról'
|
||||
- 'Arc- és tárgyfelismerés gépi tanulással'
|
||||
- 'Térképes megjelenítés helyszín alapján'
|
||||
- 'Emlékek és visszatekintések automatikus generálása'
|
||||
- 'Albumok létrehozása és megosztása családtagokkal'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a photos.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre az admin fiókot'
|
||||
- 'Telepítsd az Immich alkalmazást a telefonodra (Android/iOS)'
|
||||
- 'Állítsd be az automatikus feltöltést az alkalmazásban'
|
||||
- 'Hívd meg a családtagokat külön fiókokkal'
|
||||
# MOUNT-READY, REGISTRATION PENDING: a megosztott média/photos mappa be van csatolva
|
||||
# /external/photos néven (csak olvasható), de az Immich CSAK akkor látja, ha az
|
||||
# adminfelületen (Administration → External Libraries) regisztrálod a /external/photos
|
||||
# útvonalat. Compose ezt NEM teszi meg automatikusan — ez egy telepítés utáni lépés.
|
||||
- 'Külső könyvtár (opcionális): Administration → External Libraries → add /external/photos'
|
||||
|
||||
prerequisites:
|
||||
- 'Külső HDD szükséges a fotók és videók tárolásához'
|
||||
- 'Legalább 4 GB szabad RAM ajánlott (gépi tanulás funkciókhoz)'
|
||||
- 'x86 processzor szükséges (nem fut Raspberry Pi-n)'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
# container: no exact match and FOUR `immich-*` containers, so the old prefix rule picked whichever the
|
||||
# container list happened to yield first — it could have been `immich-postgres` (R-630)
|
||||
container: immich-server
|
||||
checks:
|
||||
- type: api
|
||||
port: 2283
|
||||
path: "/api/server/ping"
|
||||
expect:
|
||||
status: 200
|
||||
|
||||
# --- English copy (localisation slice 5, R-560) --------------------------------------------
|
||||
# The Hungarian above is UNCHANGED. A box on English reads this block field by field; a missing
|
||||
# field shows the Hungarian one; a controller older than 0.257.0 ignores the block entirely.
|
||||
i18n:
|
||||
en:
|
||||
description: 'Photos and videos in one place (a Google Photos alternative)'
|
||||
app_info:
|
||||
tagline: 'A Google Photos alternative - your photos back themselves up and sort themselves'
|
||||
use_cases:
|
||||
- 'Photos and videos back themselves up from your phone'
|
||||
- 'It recognises faces and objects on its own'
|
||||
- 'See where a photo was taken, on a map'
|
||||
- 'Memories and look-backs, put together for you'
|
||||
- 'Build albums and share them with the household'
|
||||
first_steps:
|
||||
- 'Open photos.DOMAIN in your browser'
|
||||
- 'Create the admin account'
|
||||
- 'Install the Immich app on your phone (Android/iOS)'
|
||||
- 'Turn on automatic upload in the app'
|
||||
- 'Invite the household, each with their own account'
|
||||
- 'An external library (optional): Administration -> External Libraries -> add /external/photos'
|
||||
prerequisites:
|
||||
- 'An external hard drive is needed to keep the photos and videos on'
|
||||
- 'At least 4 GB of free RAM is recommended (for the machine learning features)'
|
||||
- 'An x86 processor is needed (it does not run on a Raspberry Pi)'
|
||||
deploy_fields:
|
||||
- env_var: DOMAIN
|
||||
label: 'Domain'
|
||||
description: 'The server domain name'
|
||||
- env_var: SUBDOMAIN
|
||||
label: 'Subdomain'
|
||||
description: 'The subdomain this app answers on'
|
||||
- env_var: DB_PASSWORD
|
||||
label: 'Database password'
|
||||
- env_var: HDD_PATH
|
||||
label: 'Data storage path'
|
||||
description: 'The path to the external hard drive where the photos and videos are kept'
|
||||
placeholder: '/mnt/felhom-drives/hdd_1'
|
||||
@@ -0,0 +1,103 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "n8n"
|
||||
description: "Workflow automatizálás vizuális szerkesztővel"
|
||||
category: "productivity"
|
||||
subdomain: "auto"
|
||||
slug: "n8n"
|
||||
# catalog_since: the date THIS repo last changed this app's pinned images. Any commit that
|
||||
# changes an image: line must set this to the same day (see CLAUDE.md).
|
||||
catalog_since: "2026-09-22"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "512M"
|
||||
mem_limit: "1536M"
|
||||
pi_compatible: false
|
||||
needs_hdd: false
|
||||
|
||||
# --- Deploy fields (first deployment only) ---
|
||||
deploy_fields:
|
||||
- env_var: DOMAIN
|
||||
label: "Domain"
|
||||
type: domain
|
||||
description: "A szerver domain neve"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: SUBDOMAIN
|
||||
label: "Aldomain"
|
||||
type: subdomain
|
||||
default: "auto"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: N8N_ENCRYPTION_KEY
|
||||
label: "Titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:16"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Vizuális workflow automatizálás - Zapier/IFTTT alternatíva"
|
||||
docs_url: "https://docs.n8n.io/"
|
||||
|
||||
use_cases:
|
||||
- 'Alkalmazások összekapcsolása vizuális workflow szerkesztővel'
|
||||
- 'Automatizálás: email, Telegram, webhook, fájl feldolgozás'
|
||||
- '400+ integráció (Google, Slack, Notion, GitHub, stb.)'
|
||||
- 'Időzített feladatok (cron) és webhook triggerek'
|
||||
- 'AI munkafolyamatok LLM integrációval'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg az auto.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre az admin fiókot'
|
||||
- 'Próbálj ki egy sablon workflow-t a Template galériából'
|
||||
- 'Hozd létre az első saját munkafolyamatot'
|
||||
|
||||
prerequisites:
|
||||
- 'x86 processzor szükséges'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 5678
|
||||
path: "/healthz"
|
||||
expect:
|
||||
status: 200
|
||||
|
||||
# --- English copy (localisation slice 5, R-560) --------------------------------------------
|
||||
# The Hungarian above is UNCHANGED. A box on English reads this block field by field; a missing
|
||||
# field shows the Hungarian one; a controller older than 0.257.0 ignores the block entirely.
|
||||
i18n:
|
||||
en:
|
||||
description: 'Workflow automation with a visual editor'
|
||||
app_info:
|
||||
tagline: 'Visual workflow automation - a Zapier/IFTTT alternative'
|
||||
use_cases:
|
||||
- 'Wire apps together in a visual workflow editor'
|
||||
- 'Automate e-mail, Telegram, webhooks and file handling'
|
||||
- '400+ integrations (Google, Slack, Notion, GitHub and more)'
|
||||
- 'Scheduled jobs (cron) and webhook triggers'
|
||||
- 'AI workflows with an LLM in them'
|
||||
first_steps:
|
||||
- 'Open auto.DOMAIN in your browser'
|
||||
- 'Create the admin account'
|
||||
- 'Try a ready-made workflow from the Template gallery'
|
||||
- 'Build your first workflow of your own'
|
||||
prerequisites:
|
||||
- 'An x86 processor is needed'
|
||||
deploy_fields:
|
||||
- env_var: DOMAIN
|
||||
label: 'Domain'
|
||||
description: 'The server domain name'
|
||||
- env_var: SUBDOMAIN
|
||||
label: 'Subdomain'
|
||||
description: 'The subdomain this app answers on'
|
||||
- env_var: N8N_ENCRYPTION_KEY
|
||||
label: 'Encryption key'
|
||||
@@ -0,0 +1,117 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Navidrome"
|
||||
description: "Könnyű zene szerver Subsonic API támogatással"
|
||||
category: "media"
|
||||
subdomain: "music"
|
||||
slug: "navidrome"
|
||||
# catalog_since: the date THIS repo last changed this app's pinned images. Any commit that
|
||||
# changes an image: line must set this to the same day (see CLAUDE.md).
|
||||
catalog_since: "2026-09-22"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "50M"
|
||||
mem_limit: "256M"
|
||||
pi_compatible: true
|
||||
needs_hdd: true
|
||||
|
||||
# --- Backup classification (referential coupling; see felhom.eu documentation/audits/SPIKE-backup-classification-2026-07-14.md) ---
|
||||
backup:
|
||||
userdata:
|
||||
- path: media/music
|
||||
class: excluded # re-rippable bulk, :ro, shared tree
|
||||
|
||||
# --- Deploy fields (first deployment only) ---
|
||||
deploy_fields:
|
||||
- env_var: DOMAIN
|
||||
label: "Domain"
|
||||
type: domain
|
||||
description: "A szerver domain neve"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: SUBDOMAIN
|
||||
label: "Aldomain"
|
||||
type: subdomain
|
||||
default: "music"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: HDD_PATH
|
||||
label: "Zenegyűjtemény útvonal"
|
||||
type: path
|
||||
required: true
|
||||
placeholder: "/mnt/felhom-drives/hdd_1"
|
||||
description: "A külső merevlemez elérési útja, ahol a zenefájlok tárolódnak"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Könnyű zene szerver - streameld a saját zenegyűjteményedet"
|
||||
docs_url: "https://www.navidrome.org/docs/"
|
||||
|
||||
use_cases:
|
||||
- 'Saját zenegyűjtemény streamelése bármilyen eszközről'
|
||||
- 'Subsonic API kompatibilis mobil alkalmazások használata'
|
||||
- 'Lejátszási listák, kedvencek és értékelések kezelése'
|
||||
- 'Automatikus metaadat és borítókép letöltés'
|
||||
- 'Több felhasználó külön könyvtárral és beállításokkal'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a music.DOMAIN címet a böngészőben'
|
||||
- 'Az első felhasználó automatikusan admin lesz'
|
||||
- 'Hozd létre a fiókodat és várd meg az első szkennelést'
|
||||
- 'Telepíts Subsonic-kompatibilis alkalmazást (pl. Subtracks, play:Sub)'
|
||||
- 'Add meg a szerver címet: https://music.DOMAIN'
|
||||
|
||||
prerequisites:
|
||||
- 'Külső HDD szükséges a zenefájlok tárolásához'
|
||||
- 'Zenefájlok mappákba rendezve (pl. Előadó/Album/szám.flac)'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 4533
|
||||
path: "/ping"
|
||||
expect:
|
||||
status: 200
|
||||
|
||||
# --- English copy (localisation slice 5, R-560) --------------------------------------------
|
||||
# The Hungarian above is UNCHANGED. A box on English reads this block field by field; a missing
|
||||
# field shows the Hungarian one; a controller older than 0.257.0 ignores the block entirely.
|
||||
i18n:
|
||||
en:
|
||||
description: 'A light music server with Subsonic API support'
|
||||
app_info:
|
||||
tagline: 'A light music server - stream your own music collection'
|
||||
use_cases:
|
||||
- 'Stream your own music collection to any device'
|
||||
- 'Use any Subsonic-compatible phone app'
|
||||
- 'Playlists, favourites and ratings'
|
||||
- 'Details and cover art arrive on their own'
|
||||
- 'Several people, each with their own library and settings'
|
||||
first_steps:
|
||||
- 'Open music.DOMAIN in your browser'
|
||||
- 'The first user becomes the admin automatically'
|
||||
- 'Create your account and wait for the first scan'
|
||||
- 'Install a Subsonic-compatible app (Subtracks or play:Sub, for example)'
|
||||
- 'Give it the server address: https://music.DOMAIN'
|
||||
prerequisites:
|
||||
- 'An external hard drive is needed to keep the music files on'
|
||||
- 'Music files sorted into folders (Artist/Album/track.flac, for example)'
|
||||
deploy_fields:
|
||||
- env_var: DOMAIN
|
||||
label: 'Domain'
|
||||
description: 'The server domain name'
|
||||
- env_var: SUBDOMAIN
|
||||
label: 'Subdomain'
|
||||
description: 'The subdomain this app answers on'
|
||||
- env_var: HDD_PATH
|
||||
label: 'Music collection path'
|
||||
description: 'The path to the external hard drive where the music files are kept'
|
||||
placeholder: '/mnt/felhom-drives/hdd_1'
|
||||
@@ -0,0 +1,171 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Nextcloud"
|
||||
description: "Saját felhő tárhely - Google Drive/Dropbox alternatíva"
|
||||
category: "files"
|
||||
subdomain: "cloud"
|
||||
slug: "nextcloud"
|
||||
# catalog_since: the date THIS repo last changed this app's pinned images. Any commit that
|
||||
# changes an image: line must set this to the same day (see CLAUDE.md).
|
||||
catalog_since: "2026-09-22"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "256M"
|
||||
mem_limit: "1024M"
|
||||
pi_compatible: false
|
||||
needs_hdd: true
|
||||
|
||||
# --- Backup classification (referential coupling; see felhom.eu documentation/audits/SPIKE-backup-classification-2026-07-14.md) ---
|
||||
backup:
|
||||
hdd:
|
||||
- path: appdata/nextcloud
|
||||
class: mandatory # THE user files — oc_filecache/shares reference them
|
||||
|
||||
# --- Deploy fields (first deployment only) ---
|
||||
deploy_fields:
|
||||
- env_var: DOMAIN
|
||||
label: "Domain"
|
||||
type: domain
|
||||
description: "A szerver domain neve"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: SUBDOMAIN
|
||||
label: "Aldomain"
|
||||
type: subdomain
|
||||
default: "cloud"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: DB_PASSWORD
|
||||
label: "Adatbázis jelszó"
|
||||
type: secret
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: MYSQL_ROOT_PASSWORD
|
||||
label: "MariaDB root jelszó"
|
||||
type: secret
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: NEXTCLOUD_ADMIN_USER
|
||||
label: "Admin felhasználónév"
|
||||
type: text
|
||||
default: "admin"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: NEXTCLOUD_ADMIN_PASSWORD
|
||||
label: "Admin jelszó"
|
||||
type: password
|
||||
generate: "password:16"
|
||||
description: "Első bejelentkezéshez. Utána a webes felületen módosítható."
|
||||
locked_after_deploy: false
|
||||
|
||||
- env_var: HDD_PATH
|
||||
label: "Adattárolási útvonal"
|
||||
type: path
|
||||
required: true
|
||||
placeholder: "/mnt/felhom-drives/hdd_1"
|
||||
description: "A külső merevlemez elérési útja"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "A saját Google Drive-od - fájlok, naptár, névjegyek egy helyen"
|
||||
default_creds: "Az admin fiók adatait a telepítéskor adod meg"
|
||||
docs_url: "https://docs.nextcloud.com/server/latest/user_manual/"
|
||||
|
||||
use_cases:
|
||||
- 'Fájlok szinkronizálása és megosztása eszközök között'
|
||||
- 'Naptár és névjegyek szinkronizálás (CalDAV/CardDAV)'
|
||||
- 'Dokumentumok közös szerkesztése (OnlyOffice integrációval)'
|
||||
- 'Fotó és videó automatikus feltöltés telefonról'
|
||||
- 'Alkalmazásbolt - kibővíthető funkciók (Notes, Tasks, Forms, stb.)'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a cloud.DOMAIN címet a böngészőben'
|
||||
- 'Jelentkezz be a telepítéskor megadott admin fiókkal'
|
||||
- 'Telepítsd a Nextcloud asztali alkalmazást a számítógépedre'
|
||||
- 'Telepítsd a Nextcloud mobil alkalmazást a telefonodra'
|
||||
- 'Hívd meg a családtagokat felhasználói fiókok létrehozásával'
|
||||
|
||||
prerequisites:
|
||||
- 'Külső HDD szükséges a fájlok tárolásához'
|
||||
- 'Legalább 1 GB szabad RAM (Nextcloud + MariaDB + Redis)'
|
||||
- 'x86 processzor ajánlott a legjobb teljesítményhez'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 80
|
||||
path: "/status.php"
|
||||
expect:
|
||||
status: 200
|
||||
body_contains: "installed"
|
||||
|
||||
# --- App-email mapping (apps → in-controller shim → hub → Resend) ---
|
||||
# Nextcloud (Symfony Mailer) has no env to skip TLS cert verification and opportunistically STARTTLS-upgrades,
|
||||
# so it can't use the self-signed :2525 listener → tls_mode=plaintext points it at :2526 (STARTTLS NOT
|
||||
# advertised → no upgrade attempted; plaintext on the single-tenant app bridge — accepted posture).
|
||||
# Nextcloud SPLITS the From into local-part + domain, so from_var=MAIL_FROM_ADDRESS (local) +
|
||||
# from_domain_var=MAIL_DOMAIN → nextcloud@felhom.eu. No security_var (SMTP_SECURE stays empty = no TLS);
|
||||
# SMTP_NAME/PASSWORD unset (no auth). The official image reads these via getenv() on every boot.
|
||||
smtp_mapping:
|
||||
tls_mode: plaintext
|
||||
host_var: SMTP_HOST
|
||||
port_var: SMTP_PORT
|
||||
from_var: MAIL_FROM_ADDRESS
|
||||
from_domain_var: MAIL_DOMAIN
|
||||
from_local: nextcloud
|
||||
|
||||
# --- English copy (localisation slice 5, R-560) --------------------------------------------
|
||||
# The Hungarian above is UNCHANGED. A box on English reads this block field by field; a missing
|
||||
# field shows the Hungarian one; a controller older than 0.257.0 ignores the block entirely.
|
||||
i18n:
|
||||
en:
|
||||
description: 'Your own cloud storage - a Google Drive/Dropbox alternative'
|
||||
app_info:
|
||||
tagline: 'Your own Google Drive - files, calendar and contacts in one place'
|
||||
default_creds: 'You set the admin account details at install time'
|
||||
use_cases:
|
||||
- 'Sync and share files between your devices'
|
||||
- 'Calendar and contact sync (CalDAV/CardDAV)'
|
||||
- 'Work on a document together (with the OnlyOffice integration)'
|
||||
- 'Photos and videos upload themselves from your phone'
|
||||
- 'An app store - more features when you want them (Notes, Tasks, Forms and more)'
|
||||
first_steps:
|
||||
- 'Open cloud.DOMAIN in your browser'
|
||||
- 'Sign in with the admin account you set at install time'
|
||||
- 'Install the Nextcloud desktop app on your computer'
|
||||
- 'Install the Nextcloud mobile app on your phone'
|
||||
- 'Invite the household by creating an account for each of them'
|
||||
prerequisites:
|
||||
- 'An external hard drive is needed to keep the files on'
|
||||
- 'At least 1 GB of free RAM (Nextcloud + MariaDB + Redis)'
|
||||
- 'An x86 processor is recommended for the best speed'
|
||||
deploy_fields:
|
||||
- env_var: DOMAIN
|
||||
label: 'Domain'
|
||||
description: 'The server domain name'
|
||||
- env_var: SUBDOMAIN
|
||||
label: 'Subdomain'
|
||||
description: 'The subdomain this app answers on'
|
||||
- env_var: DB_PASSWORD
|
||||
label: 'Database password'
|
||||
- env_var: HDD_PATH
|
||||
label: 'Data storage path'
|
||||
description: 'The path to the external hard drive'
|
||||
placeholder: '/mnt/felhom-drives/hdd_1'
|
||||
- env_var: MYSQL_ROOT_PASSWORD
|
||||
label: 'MariaDB root password'
|
||||
- env_var: NEXTCLOUD_ADMIN_USER
|
||||
label: 'Admin user name'
|
||||
- env_var: NEXTCLOUD_ADMIN_PASSWORD
|
||||
label: 'Admin password'
|
||||
description: 'For the first sign-in. You can change it in the app afterwards.'
|
||||
@@ -0,0 +1,236 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml — App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "RomM"
|
||||
description: "Retró játékgyűjtemény kezelő"
|
||||
category: "media"
|
||||
subdomain: "arcade"
|
||||
slug: "romm"
|
||||
# catalog_since: the date THIS repo last changed this app's pinned images. Any commit that
|
||||
# changes an image: line must set this to the same day (see CLAUDE.md).
|
||||
catalog_since: "2026-09-22"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "300M"
|
||||
mem_limit: "1280M"
|
||||
pi_compatible: false
|
||||
needs_hdd: true
|
||||
|
||||
# --- Backup classification (referential coupling; see felhom.eu documentation/audits/SPIKE-backup-classification-2026-07-14.md) ---
|
||||
backup:
|
||||
userdata:
|
||||
- path: roms
|
||||
class: optional # ruled: curated ROM sets often not re-acquirable
|
||||
hdd:
|
||||
- path: appdata/romm/resources
|
||||
class: excluded # scraper cache, re-derivable
|
||||
|
||||
# --- Customer-facing folder annotation (R-75) ---
|
||||
data_paths:
|
||||
- path: roms
|
||||
root: userdata
|
||||
role: library
|
||||
label: "ROM gyűjtemény"
|
||||
|
||||
# --- Deploy fields (first deployment only) ---
|
||||
deploy_fields:
|
||||
- env_var: DOMAIN
|
||||
label: "Domain"
|
||||
type: domain
|
||||
description: "A szerver domain neve"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: SUBDOMAIN
|
||||
label: "Aldomain"
|
||||
type: subdomain
|
||||
default: "arcade"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: DB_PASSWORD
|
||||
label: "Adatbázis jelszó"
|
||||
type: secret
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: MYSQL_ROOT_PASSWORD
|
||||
label: "MariaDB root jelszó"
|
||||
type: secret
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: ROMM_AUTH_SECRET_KEY
|
||||
label: "Hitelesítési titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: HDD_PATH
|
||||
label: "Adattárolási útvonal"
|
||||
type: path
|
||||
required: true
|
||||
placeholder: "/mnt/felhom-drives/hdd_1"
|
||||
description: "A külső merevlemez elérési útja, ahol a ROM-ok és borítóképek tárolódnak"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Retró játékgyűjtemény kezelő, böngésző és lejátszó"
|
||||
default_creds: "admin / admin"
|
||||
docs_url: "https://github.com/rommapp/romm/wiki"
|
||||
|
||||
use_cases:
|
||||
- "Retró játékgyűjtemény rendszerezése és böngészése webes felületen"
|
||||
- "Játékok metaadatainak automatikus letöltése — borítók, leírások, értékelések"
|
||||
- "Platformonkénti szűrés és keresés a teljes gyűjteményben"
|
||||
- "ROM fájlok webes feltöltése és letöltése"
|
||||
- "Többfelhasználós hozzáférés a háztartás tagjai számára"
|
||||
|
||||
first_steps:
|
||||
- "Nyisd meg az arcade.DOMAIN címet a böngészőben"
|
||||
- "Jelentkezz be az alapértelmezett admin / admin fiókkal"
|
||||
- "Változtasd meg azonnal a jelszót a Settings menüben"
|
||||
- "Töltsd fel a ROM fájlokat a Fájlkezelőben (FileBrowser) a roms/ mappába, platform mappákba rendezve (pl. roms/gba/, roms/snes/)"
|
||||
- "Indíts egy Scan-t a bal oldali menüben a ROM-ok beolvasásához"
|
||||
- "Opcionális: állíts be metaadat-szolgáltatókat a borítóképek és leírások automatikus letöltéséhez (lásd lent)"
|
||||
|
||||
prerequisites:
|
||||
- "Külső HDD szükséges a ROM fájlok és borítóképek tárolásához"
|
||||
- "Legalább 1 GB szabad RAM ajánlott (MariaDB + Redis + RomM)"
|
||||
- "ROM fájlok platform mappákba rendezve (pl. roms/gba/, roms/snes/)"
|
||||
|
||||
# --- Optional config (configurable before or after deployment) ---
|
||||
optional_config:
|
||||
- group: "Metaadat-szolgáltatók"
|
||||
description: "Játékok borítóinak, leírásainak és értékeléseinek automatikus letöltéséhez. Legalább az IGDB beállítása ajánlott. Mindegyik ingyenesen használható regisztráció után."
|
||||
fields:
|
||||
- env_var: IGDB_CLIENT_ID
|
||||
label: "IGDB Client ID"
|
||||
type: text
|
||||
help_url: "https://api-docs.igdb.com/#getting-started"
|
||||
help_text: "1) Regisztrálj / jelentkezz be a Twitch fejlesztői portálon (dev.twitch.tv). 2) Hozz létre egy új alkalmazást (bármilyen névvel). 3) Másold be a Client ID-t."
|
||||
|
||||
- env_var: IGDB_CLIENT_SECRET
|
||||
label: "IGDB Client Secret"
|
||||
type: secret_input
|
||||
help_text: "A Twitch alkalmazásod Client Secret-je (a „New Secret\" gombbal generálhatod)."
|
||||
|
||||
- env_var: STEAMGRIDDB_API_KEY
|
||||
label: "SteamGridDB API Key"
|
||||
type: text
|
||||
help_url: "https://www.steamgriddb.com/profile/preferences/api"
|
||||
help_text: "Regisztrálj a SteamGridDB oldalon, majd a Preferences → API fül alatt kattints a „Generate API key\" gombra."
|
||||
|
||||
- env_var: SCREENSCRAPER_USER
|
||||
label: "ScreenScraper felhasználónév"
|
||||
type: text
|
||||
help_url: "https://www.screenscraper.fr/"
|
||||
help_text: "Regisztrálj a screenscraper.fr oldalon. A felhasználóneved lesz az API felhasználónév."
|
||||
|
||||
- env_var: SCREENSCRAPER_PASSWORD
|
||||
label: "ScreenScraper jelszó"
|
||||
type: secret_input
|
||||
help_text: "A screenscraper.fr fiókod jelszava."
|
||||
|
||||
- env_var: MOBYGAMES_API_KEY
|
||||
label: "MobyGames API Key"
|
||||
type: text
|
||||
help_url: "https://www.mobygames.com/info/api/"
|
||||
help_text: "Regisztrálj a MobyGames oldalon, majd az API oldalon igényelj kulcsot. Részletes játékinformációkat és krediteket biztosít."
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 8080
|
||||
|
||||
# --- English copy (localisation slice 5, R-560) --------------------------------------------
|
||||
# The Hungarian above is UNCHANGED. A box on English reads this block field by field; a missing
|
||||
# field shows the Hungarian one; a controller older than 0.257.0 ignores the block entirely.
|
||||
i18n:
|
||||
en:
|
||||
description: "Retro game collection manager"
|
||||
|
||||
data_paths:
|
||||
- path: roms
|
||||
label: "ROM collection"
|
||||
|
||||
deploy_fields:
|
||||
- env_var: DOMAIN
|
||||
label: "Domain"
|
||||
description: "The server domain name"
|
||||
|
||||
- env_var: SUBDOMAIN
|
||||
label: "Subdomain"
|
||||
description: "The subdomain this app answers on"
|
||||
|
||||
- env_var: DB_PASSWORD
|
||||
label: "Database password"
|
||||
|
||||
- env_var: MYSQL_ROOT_PASSWORD
|
||||
label: "MariaDB root password"
|
||||
|
||||
- env_var: ROMM_AUTH_SECRET_KEY
|
||||
label: "Sign-in encryption key"
|
||||
|
||||
- env_var: HDD_PATH
|
||||
label: "Data storage path"
|
||||
placeholder: "/mnt/felhom-drives/hdd_1"
|
||||
description: "The path to the external hard drive where the ROMs and cover art are kept"
|
||||
|
||||
app_info:
|
||||
tagline: "Retro game collection manager, browser and player"
|
||||
default_creds: "admin / admin"
|
||||
|
||||
use_cases:
|
||||
- "Sort and browse a retro game collection in your browser"
|
||||
- "Game details download themselves - cover art, descriptions, ratings"
|
||||
- "Filter and search the whole collection by platform"
|
||||
- "Upload and download ROM files in your browser"
|
||||
- "Several people in the household can have their own account"
|
||||
|
||||
first_steps:
|
||||
- "Open arcade.DOMAIN in your browser"
|
||||
- "Sign in with the default admin / admin account"
|
||||
- "Change the password straight away, in the Settings menu"
|
||||
- "Upload the ROM files into the roms/ folder in the File manager (FileBrowser), sorted into platform folders (for example roms/gba/, roms/snes/)"
|
||||
- "Start a Scan from the menu on the left to read the ROMs in"
|
||||
- "Optional: set up metadata providers so cover art and descriptions download themselves (see below)"
|
||||
|
||||
prerequisites:
|
||||
- "An external hard drive is needed to keep the ROM files and cover art on"
|
||||
- "At least 1 GB of free RAM is recommended (MariaDB + Redis + RomM)"
|
||||
- "ROM files sorted into platform folders (for example roms/gba/, roms/snes/)"
|
||||
|
||||
optional_config:
|
||||
- match_group: "Metaadat-szolgáltatók"
|
||||
group: "Metadata providers"
|
||||
description: "So that cover art, descriptions and ratings download themselves. IGDB is the one worth setting up first. All of them are free after you sign up."
|
||||
fields:
|
||||
- env_var: IGDB_CLIENT_ID
|
||||
label: "IGDB Client ID"
|
||||
help_text: '1) Sign up or sign in on the Twitch developer portal (dev.twitch.tv). 2) Create a new application (any name will do). 3) Copy the Client ID across.'
|
||||
|
||||
- env_var: IGDB_CLIENT_SECRET
|
||||
label: "IGDB Client Secret"
|
||||
help_text: 'The Client Secret of your Twitch application (the "New Secret" button makes one).'
|
||||
|
||||
- env_var: STEAMGRIDDB_API_KEY
|
||||
label: "SteamGridDB API Key"
|
||||
help_text: 'Sign up on SteamGridDB, then select the "Generate API key" button under Preferences -> API.'
|
||||
|
||||
- env_var: SCREENSCRAPER_USER
|
||||
label: "ScreenScraper user name"
|
||||
help_text: 'Sign up on screenscraper.fr. Your account name is the API user name.'
|
||||
|
||||
- env_var: SCREENSCRAPER_PASSWORD
|
||||
label: "ScreenScraper password"
|
||||
help_text: 'The password of your screenscraper.fr account.'
|
||||
|
||||
- env_var: MOBYGAMES_API_KEY
|
||||
label: "MobyGames API Key"
|
||||
help_text: 'Sign up on MobyGames, then ask for a key on the API page. It gives detailed game information and credits.'
|
||||
@@ -0,0 +1,236 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml — App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "RomM"
|
||||
description: "Retró játékgyűjtemény kezelő"
|
||||
category: "media"
|
||||
subdomain: "arcade"
|
||||
slug: "romm"
|
||||
# catalog_since: the date THIS repo last changed this app's pinned images. Any commit that
|
||||
# changes an image: line must set this to the same day (see CLAUDE.md).
|
||||
catalog_since: "2026-09-23"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "300M"
|
||||
mem_limit: "1280M"
|
||||
pi_compatible: false
|
||||
needs_hdd: true
|
||||
|
||||
# --- Backup classification (referential coupling; see felhom.eu documentation/audits/SPIKE-backup-classification-2026-07-14.md) ---
|
||||
backup:
|
||||
userdata:
|
||||
- path: roms
|
||||
class: optional # ruled: curated ROM sets often not re-acquirable
|
||||
hdd:
|
||||
- path: appdata/romm/resources
|
||||
class: excluded # scraper cache, re-derivable
|
||||
|
||||
# --- Customer-facing folder annotation (R-75) ---
|
||||
data_paths:
|
||||
- path: roms
|
||||
root: userdata
|
||||
role: library
|
||||
label: "ROM gyűjtemény"
|
||||
|
||||
# --- Deploy fields (first deployment only) ---
|
||||
deploy_fields:
|
||||
- env_var: DOMAIN
|
||||
label: "Domain"
|
||||
type: domain
|
||||
description: "A szerver domain neve"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: SUBDOMAIN
|
||||
label: "Aldomain"
|
||||
type: subdomain
|
||||
default: "arcade"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: DB_PASSWORD
|
||||
label: "Adatbázis jelszó"
|
||||
type: secret
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: MYSQL_ROOT_PASSWORD
|
||||
label: "MariaDB root jelszó"
|
||||
type: secret
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: ROMM_AUTH_SECRET_KEY
|
||||
label: "Hitelesítési titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: HDD_PATH
|
||||
label: "Adattárolási útvonal"
|
||||
type: path
|
||||
required: true
|
||||
placeholder: "/mnt/felhom-drives/hdd_1"
|
||||
description: "A külső merevlemez elérési útja, ahol a ROM-ok és borítóképek tárolódnak"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Retró játékgyűjtemény kezelő, böngésző és lejátszó"
|
||||
default_creds: "admin / admin"
|
||||
docs_url: "https://github.com/rommapp/romm/wiki"
|
||||
|
||||
use_cases:
|
||||
- "Retró játékgyűjtemény rendszerezése és böngészése webes felületen"
|
||||
- "Játékok metaadatainak automatikus letöltése — borítók, leírások, értékelések"
|
||||
- "Platformonkénti szűrés és keresés a teljes gyűjteményben"
|
||||
- "ROM fájlok webes feltöltése és letöltése"
|
||||
- "Többfelhasználós hozzáférés a háztartás tagjai számára"
|
||||
|
||||
first_steps:
|
||||
- "Nyisd meg az arcade.DOMAIN címet a böngészőben"
|
||||
- "Jelentkezz be az alapértelmezett admin / admin fiókkal"
|
||||
- "Változtasd meg azonnal a jelszót a Settings menüben"
|
||||
- "Töltsd fel a ROM fájlokat a Fájlkezelőben (FileBrowser) a roms/ mappába, platform mappákba rendezve (pl. roms/gba/, roms/snes/)"
|
||||
- "Indíts egy Scan-t a bal oldali menüben a ROM-ok beolvasásához"
|
||||
- "Opcionális: állíts be metaadat-szolgáltatókat a borítóképek és leírások automatikus letöltéséhez (lásd lent)"
|
||||
|
||||
prerequisites:
|
||||
- "Külső HDD szükséges a ROM fájlok és borítóképek tárolásához"
|
||||
- "Legalább 1 GB szabad RAM ajánlott (MariaDB + Redis + RomM)"
|
||||
- "ROM fájlok platform mappákba rendezve (pl. roms/gba/, roms/snes/)"
|
||||
|
||||
# --- Optional config (configurable before or after deployment) ---
|
||||
optional_config:
|
||||
- group: "Metaadat-szolgáltatók"
|
||||
description: "Játékok borítóinak, leírásainak és értékeléseinek automatikus letöltéséhez. Legalább az IGDB beállítása ajánlott. Mindegyik ingyenesen használható regisztráció után."
|
||||
fields:
|
||||
- env_var: IGDB_CLIENT_ID
|
||||
label: "IGDB Client ID"
|
||||
type: text
|
||||
help_url: "https://api-docs.igdb.com/#getting-started"
|
||||
help_text: "1) Regisztrálj / jelentkezz be a Twitch fejlesztői portálon (dev.twitch.tv). 2) Hozz létre egy új alkalmazást (bármilyen névvel). 3) Másold be a Client ID-t."
|
||||
|
||||
- env_var: IGDB_CLIENT_SECRET
|
||||
label: "IGDB Client Secret"
|
||||
type: secret_input
|
||||
help_text: "A Twitch alkalmazásod Client Secret-je (a „New Secret\" gombbal generálhatod)."
|
||||
|
||||
- env_var: STEAMGRIDDB_API_KEY
|
||||
label: "SteamGridDB API Key"
|
||||
type: text
|
||||
help_url: "https://www.steamgriddb.com/profile/preferences/api"
|
||||
help_text: "Regisztrálj a SteamGridDB oldalon, majd a Preferences → API fül alatt kattints a „Generate API key\" gombra."
|
||||
|
||||
- env_var: SCREENSCRAPER_USER
|
||||
label: "ScreenScraper felhasználónév"
|
||||
type: text
|
||||
help_url: "https://www.screenscraper.fr/"
|
||||
help_text: "Regisztrálj a screenscraper.fr oldalon. A felhasználóneved lesz az API felhasználónév."
|
||||
|
||||
- env_var: SCREENSCRAPER_PASSWORD
|
||||
label: "ScreenScraper jelszó"
|
||||
type: secret_input
|
||||
help_text: "A screenscraper.fr fiókod jelszava."
|
||||
|
||||
- env_var: MOBYGAMES_API_KEY
|
||||
label: "MobyGames API Key"
|
||||
type: text
|
||||
help_url: "https://www.mobygames.com/info/api/"
|
||||
help_text: "Regisztrálj a MobyGames oldalon, majd az API oldalon igényelj kulcsot. Részletes játékinformációkat és krediteket biztosít."
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 8080
|
||||
|
||||
# --- English copy (localisation slice 5, R-560) --------------------------------------------
|
||||
# The Hungarian above is UNCHANGED. A box on English reads this block field by field; a missing
|
||||
# field shows the Hungarian one; a controller older than 0.257.0 ignores the block entirely.
|
||||
i18n:
|
||||
en:
|
||||
description: "Retro game collection manager"
|
||||
|
||||
data_paths:
|
||||
- path: roms
|
||||
label: "ROM collection"
|
||||
|
||||
deploy_fields:
|
||||
- env_var: DOMAIN
|
||||
label: "Domain"
|
||||
description: "The server domain name"
|
||||
|
||||
- env_var: SUBDOMAIN
|
||||
label: "Subdomain"
|
||||
description: "The subdomain this app answers on"
|
||||
|
||||
- env_var: DB_PASSWORD
|
||||
label: "Database password"
|
||||
|
||||
- env_var: MYSQL_ROOT_PASSWORD
|
||||
label: "MariaDB root password"
|
||||
|
||||
- env_var: ROMM_AUTH_SECRET_KEY
|
||||
label: "Sign-in encryption key"
|
||||
|
||||
- env_var: HDD_PATH
|
||||
label: "Data storage path"
|
||||
placeholder: "/mnt/felhom-drives/hdd_1"
|
||||
description: "The path to the external hard drive where the ROMs and cover art are kept"
|
||||
|
||||
app_info:
|
||||
tagline: "Retro game collection manager, browser and player"
|
||||
default_creds: "admin / admin"
|
||||
|
||||
use_cases:
|
||||
- "Sort and browse a retro game collection in your browser"
|
||||
- "Game details download themselves - cover art, descriptions, ratings"
|
||||
- "Filter and search the whole collection by platform"
|
||||
- "Upload and download ROM files in your browser"
|
||||
- "Several people in the household can have their own account"
|
||||
|
||||
first_steps:
|
||||
- "Open arcade.DOMAIN in your browser"
|
||||
- "Sign in with the default admin / admin account"
|
||||
- "Change the password straight away, in the Settings menu"
|
||||
- "Upload the ROM files into the roms/ folder in the File manager (FileBrowser), sorted into platform folders (for example roms/gba/, roms/snes/)"
|
||||
- "Start a Scan from the menu on the left to read the ROMs in"
|
||||
- "Optional: set up metadata providers so cover art and descriptions download themselves (see below)"
|
||||
|
||||
prerequisites:
|
||||
- "An external hard drive is needed to keep the ROM files and cover art on"
|
||||
- "At least 1 GB of free RAM is recommended (MariaDB + Redis + RomM)"
|
||||
- "ROM files sorted into platform folders (for example roms/gba/, roms/snes/)"
|
||||
|
||||
optional_config:
|
||||
- match_group: "Metaadat-szolgáltatók"
|
||||
group: "Metadata providers"
|
||||
description: "So that cover art, descriptions and ratings download themselves. IGDB is the one worth setting up first. All of them are free after you sign up."
|
||||
fields:
|
||||
- env_var: IGDB_CLIENT_ID
|
||||
label: "IGDB Client ID"
|
||||
help_text: '1) Sign up or sign in on the Twitch developer portal (dev.twitch.tv). 2) Create a new application (any name will do). 3) Copy the Client ID across.'
|
||||
|
||||
- env_var: IGDB_CLIENT_SECRET
|
||||
label: "IGDB Client Secret"
|
||||
help_text: 'The Client Secret of your Twitch application (the "New Secret" button makes one).'
|
||||
|
||||
- env_var: STEAMGRIDDB_API_KEY
|
||||
label: "SteamGridDB API Key"
|
||||
help_text: 'Sign up on SteamGridDB, then select the "Generate API key" button under Preferences -> API.'
|
||||
|
||||
- env_var: SCREENSCRAPER_USER
|
||||
label: "ScreenScraper user name"
|
||||
help_text: 'Sign up on screenscraper.fr. Your account name is the API user name.'
|
||||
|
||||
- env_var: SCREENSCRAPER_PASSWORD
|
||||
label: "ScreenScraper password"
|
||||
help_text: 'The password of your screenscraper.fr account.'
|
||||
|
||||
- env_var: MOBYGAMES_API_KEY
|
||||
label: "MobyGames API Key"
|
||||
help_text: 'Sign up on MobyGames, then ask for a key on the API page. It gives detailed game information and credits.'
|
||||
Reference in New Issue
Block a user