v0.257.0: the app catalog can speak English (R-560, slice 5 Part A)
gates / gates (push) Successful in 25s
gates / gates (push) Successful in 25s
The READ PATH for a second language in `.felhom.yml`. An `i18n: {en: …}` sibling
block inside the same file; `Metadata.For(lang)` merges it FIELD BY FIELD over the
Hungarian, so a missing or blank English field shows the Hungarian one and a
half-translated app is a legal, shippable state.
`For("hu")` is the parsed struct with `I18n` cleared and nothing else — measured
against all 53 real catalog files, copied into `internal/stacks/testdata/catalog/`.
Lists replace whole; every other list is matched by its own key, never by position.
`For` never writes through the receiver: the metadata is the stack manager's, shared
by concurrent requests, and an in-place merge would leak one household's language
into another household's page.
Pages reach catalog copy only through `LocalizeStacks`/`LocalizeStackPtr`/`MetaFor`,
and `TestNoDirectMetaCopyReadOnPages` keeps a named, reasoned allow-list of every
direct `.Meta.<copy>` read in `internal/web` so the NEXT page to read one fails the
suite instead of quietly rendering Hungarian to an English household.
Eight red-proofs. Two of them convicted a hollow TEST rather than the code: a struct
copy shares its slices' backing arrays, so the obvious DeepEqual mutation check
passed a deliberately broken merge; and a one-entry fixture cannot tell key matching
from position matching. Both rewritten, both then seen to fail.
MinAgent: 0.131.0 (unchanged). Older controllers are unaffected — `LoadMetadata`
uses non-strict `yaml.Unmarshal`, so a pre-0.257.0 box drops the whole block.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -66,6 +66,12 @@ type Metadata struct {
|
||||
// with the Fork-3 asymmetry — a malformed PATH rejects the whole block, an unknown ROLE drops
|
||||
// just that entry (see ValidateDataPaths).
|
||||
DataPaths []DataPath `yaml:"data_paths,omitempty" json:"data_paths,omitempty"`
|
||||
// I18n is the catalog's copy in every language OTHER than the Hungarian above (R-560). Keyed by
|
||||
// language code; only "en" exists today. It is read through `For(lang)` and NEVER rendered
|
||||
// directly — see metadata_i18n.go for the whole contract. `json:"-"`: this struct is serialised
|
||||
// into the API answers and the page data, and the untranslated half of a bundle has no reader
|
||||
// there; the merged view is what travels.
|
||||
I18n map[string]MetadataOverlay `yaml:"i18n,omitempty" json:"-"`
|
||||
}
|
||||
|
||||
// SMTPMapping renames the generic relay settings (host / port / security / from / from-name)
|
||||
|
||||
@@ -0,0 +1,320 @@
|
||||
package stacks
|
||||
|
||||
import "strings"
|
||||
|
||||
// CATALOG COPY IN A SECOND LANGUAGE (localisation slice 5, R-560).
|
||||
//
|
||||
// A catalog template's customer-facing text is Hungarian in the fields the controller has always
|
||||
// read (`description`, `app_info`, `deploy_fields[].label` …). English is a SIBLING BLOCK in the
|
||||
// SAME file:
|
||||
//
|
||||
// description: "Titkosított jegyzet és szöveg megosztás"
|
||||
// app_info:
|
||||
// first_steps: [...]
|
||||
// i18n:
|
||||
// en:
|
||||
// description: "Encrypted notes and text sharing"
|
||||
// app_info:
|
||||
// first_steps: [...]
|
||||
//
|
||||
// THREE PROPERTIES, EACH LOAD-BEARING.
|
||||
//
|
||||
// 1. **The Hungarian bytes never move.** A translation adds a block; it never edits a Hungarian
|
||||
// string. `For("hu")` is the parsed struct with `I18n` cleared — pinned by
|
||||
// TestMetaForHuIsIdentity over all 53 real catalog files.
|
||||
//
|
||||
// 2. **An older controller ignores the block.** `LoadMetadata` uses `yaml.Unmarshal`, which is
|
||||
// NON-STRICT (no `KnownFields`; verified — this repo constructs no yaml.Decoder at all), so a
|
||||
// controller built before this file silently drops `i18n:` and renders exactly as it did. That
|
||||
// is what lets the catalog be pushed to the whole fleet ahead of the floor raise.
|
||||
//
|
||||
// 3. **Fallback is FIELD BY FIELD, never all-or-nothing.** A missing — or empty — English field
|
||||
// shows the Hungarian one (10-localisation.md §4, operator ruling 3). A half-translated app is
|
||||
// therefore a legal, shippable state, which is what makes the batch pushes safe.
|
||||
//
|
||||
// LISTS ARE REPLACED WHOLE, NEVER MERGED BY INDEX. `use_cases`, `first_steps` and `prerequisites`
|
||||
// are prose in a running order; merging item 3 of one language with item 4 of another would produce
|
||||
// a list nobody wrote. An English list that is present replaces the Hungarian list entirely; an
|
||||
// absent or empty one leaves the Hungarian list alone.
|
||||
//
|
||||
// EVERY OTHER LIST IS MATCHED BY ITS OWN KEY, NEVER BY POSITION: `deploy_fields` by `env_var`,
|
||||
// `options` by `value`, `optional_config` groups by `match_group` (the Hungarian `group` value they
|
||||
// translate — a group has no other stable identity), `optional_config[].fields` by `env_var`,
|
||||
// `integrations` by `target`, `data_paths` by `path`. Position matching would silently mistranslate
|
||||
// the moment a Hungarian field is inserted above another, and nothing on the page would look wrong.
|
||||
//
|
||||
// WHAT AN OVERLAY MAY CARRY IS EXACTLY THE COPY FIELDS — no `env_var`, `type`, `default`,
|
||||
// `generate`, `required`, `locked_after_deploy`, `data_key`, `path`, `role`, `docs_url`, no image,
|
||||
// port or healthcheck. The struct shape below IS that rule: a translation cannot change what an app
|
||||
// does, only what it says. The catalog's `check-copy-i18n.py` gate states the same rule on the file
|
||||
// before it is ever parsed here.
|
||||
|
||||
// MetadataOverlay is one language's copy for one app. Every scalar is a POINTER so that "the
|
||||
// translator did not write this field" is distinguishable from "the translator wrote an empty
|
||||
// string" — both fall back to Hungarian, but only the first is silent.
|
||||
type MetadataOverlay struct {
|
||||
Description *string `yaml:"description,omitempty"`
|
||||
AppInfo *AppInfoOverlay `yaml:"app_info,omitempty"`
|
||||
DeployFields []DeployFieldOverlay `yaml:"deploy_fields,omitempty"`
|
||||
OptionalConfig []OptionalConfigGroupOverlay `yaml:"optional_config,omitempty"`
|
||||
Integrations []IntegrationOverlay `yaml:"integrations,omitempty"`
|
||||
DataPaths []DataPathOverlay `yaml:"data_paths,omitempty"`
|
||||
InitialCreds *InitialCredentialsOverlay `yaml:"initial_credentials,omitempty"`
|
||||
}
|
||||
|
||||
// AppInfoOverlay carries the info page's prose. The three lists replace whole.
|
||||
type AppInfoOverlay struct {
|
||||
Tagline *string `yaml:"tagline,omitempty"`
|
||||
UseCases []string `yaml:"use_cases,omitempty"`
|
||||
FirstSteps []string `yaml:"first_steps,omitempty"`
|
||||
Prerequisites []string `yaml:"prerequisites,omitempty"`
|
||||
DefaultCreds *string `yaml:"default_creds,omitempty"`
|
||||
}
|
||||
|
||||
// DeployFieldOverlay translates one deploy field, found by EnvVar.
|
||||
type DeployFieldOverlay struct {
|
||||
EnvVar string `yaml:"env_var"`
|
||||
Label *string `yaml:"label,omitempty"`
|
||||
Description *string `yaml:"description,omitempty"`
|
||||
Placeholder *string `yaml:"placeholder,omitempty"`
|
||||
Options []SelectOptionOverlay `yaml:"options,omitempty"`
|
||||
}
|
||||
|
||||
// SelectOptionOverlay translates one select option's label, found by Value.
|
||||
type SelectOptionOverlay struct {
|
||||
Value string `yaml:"value"`
|
||||
Label *string `yaml:"label,omitempty"`
|
||||
}
|
||||
|
||||
// OptionalConfigGroupOverlay translates one optional-config group. MatchGroup is the HUNGARIAN
|
||||
// `group:` value it belongs to — a group carries no id, and its own label is the thing being
|
||||
// translated, so the match key has to be stated rather than derived.
|
||||
type OptionalConfigGroupOverlay struct {
|
||||
MatchGroup string `yaml:"match_group"`
|
||||
Group *string `yaml:"group,omitempty"`
|
||||
Description *string `yaml:"description,omitempty"`
|
||||
Fields []OptionalConfigFieldOverlay `yaml:"fields,omitempty"`
|
||||
}
|
||||
|
||||
// OptionalConfigFieldOverlay translates one optional-config field, found by EnvVar.
|
||||
type OptionalConfigFieldOverlay struct {
|
||||
EnvVar string `yaml:"env_var"`
|
||||
Label *string `yaml:"label,omitempty"`
|
||||
HelpText *string `yaml:"help_text,omitempty"`
|
||||
}
|
||||
|
||||
// IntegrationOverlay translates one integration offer, found by Target.
|
||||
type IntegrationOverlay struct {
|
||||
Target string `yaml:"target"`
|
||||
Label *string `yaml:"label,omitempty"`
|
||||
Description *string `yaml:"description,omitempty"`
|
||||
}
|
||||
|
||||
// DataPathOverlay translates one data-folder label, found by Path.
|
||||
type DataPathOverlay struct {
|
||||
Path string `yaml:"path"`
|
||||
Label *string `yaml:"label,omitempty"`
|
||||
}
|
||||
|
||||
// InitialCredentialsOverlay translates the note shown beside a first-login credential. Only the
|
||||
// note: the file path, the format and the keys are configuration, and the credential VALUE never
|
||||
// passes through here at all.
|
||||
type InitialCredentialsOverlay struct {
|
||||
Note *string `yaml:"note,omitempty"`
|
||||
}
|
||||
|
||||
// BaseLanguage is the language the unmarshalled fields themselves are written in. It is not a
|
||||
// choice a template can make — the catalog's Hungarian is the base by construction (the freeze
|
||||
// gate in the catalog repo pins it byte for byte).
|
||||
const BaseLanguage = "hu"
|
||||
|
||||
// overlayStr returns the translated string, or the base one when the translation is absent or
|
||||
// blank. A blank translation is treated as ABSENT and never renders an empty box — operator
|
||||
// ruling 3, 10-localisation.md §4.
|
||||
func overlayStr(p *string, base string) string {
|
||||
if p == nil || strings.TrimSpace(*p) == "" {
|
||||
return base
|
||||
}
|
||||
return *p
|
||||
}
|
||||
|
||||
// overlayList returns the translated list, or the base one when the translation is absent or
|
||||
// empty. Whole-list replacement, never a per-index merge — see the header.
|
||||
func overlayList(in []string, base []string) []string {
|
||||
if len(in) == 0 {
|
||||
return base
|
||||
}
|
||||
out := make([]string, len(in))
|
||||
copy(out, in)
|
||||
return out
|
||||
}
|
||||
|
||||
// For returns this app's metadata as the given language renders it.
|
||||
//
|
||||
// For the base language — and for any language this template has no block for — it is the parsed
|
||||
// struct with `I18n` cleared, so a Hungarian page cannot be changed by the presence of a
|
||||
// translation. For a language with a block, copy fields are replaced one by one and EVERYTHING
|
||||
// ELSE is carried through untouched.
|
||||
//
|
||||
// It NEVER mutates the receiver. Every slice it changes is copied first: `Metadata` values live
|
||||
// inside the stack manager's cache and are handed to many requests at once, so an in-place edit
|
||||
// would leak one household's language into another's page.
|
||||
//
|
||||
// VALUE receiver, like CanInstall and CatalogSinceAge above it — see the comment there: a pointer
|
||||
// receiver on a type that reaches html/template inside an interface{} is a render-time 500.
|
||||
func (m Metadata) For(lang string) Metadata {
|
||||
out := m
|
||||
out.I18n = nil
|
||||
if lang == "" || lang == BaseLanguage {
|
||||
return out
|
||||
}
|
||||
ov, ok := m.I18n[lang]
|
||||
if !ok {
|
||||
return out
|
||||
}
|
||||
|
||||
out.Description = overlayStr(ov.Description, out.Description)
|
||||
|
||||
if ov.AppInfo != nil {
|
||||
out.AppInfo.Tagline = overlayStr(ov.AppInfo.Tagline, out.AppInfo.Tagline)
|
||||
out.AppInfo.DefaultCreds = overlayStr(ov.AppInfo.DefaultCreds, out.AppInfo.DefaultCreds)
|
||||
out.AppInfo.UseCases = overlayList(ov.AppInfo.UseCases, out.AppInfo.UseCases)
|
||||
out.AppInfo.FirstSteps = overlayList(ov.AppInfo.FirstSteps, out.AppInfo.FirstSteps)
|
||||
out.AppInfo.Prerequisites = overlayList(ov.AppInfo.Prerequisites, out.AppInfo.Prerequisites)
|
||||
}
|
||||
|
||||
if len(ov.DeployFields) > 0 && len(out.DeployFields) > 0 {
|
||||
fields := make([]DeployField, len(out.DeployFields))
|
||||
copy(fields, out.DeployFields)
|
||||
for _, fo := range ov.DeployFields {
|
||||
for i := range fields {
|
||||
if fields[i].EnvVar != fo.EnvVar || fo.EnvVar == "" {
|
||||
continue
|
||||
}
|
||||
fields[i].Label = overlayStr(fo.Label, fields[i].Label)
|
||||
fields[i].Description = overlayStr(fo.Description, fields[i].Description)
|
||||
fields[i].Placeholder = overlayStr(fo.Placeholder, fields[i].Placeholder)
|
||||
if len(fo.Options) > 0 && len(fields[i].Options) > 0 {
|
||||
opts := make([]SelectOption, len(fields[i].Options))
|
||||
copy(opts, fields[i].Options)
|
||||
for _, oo := range fo.Options {
|
||||
for j := range opts {
|
||||
if opts[j].Value == oo.Value && oo.Value != "" {
|
||||
opts[j].Label = overlayStr(oo.Label, opts[j].Label)
|
||||
}
|
||||
}
|
||||
}
|
||||
fields[i].Options = opts
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
out.DeployFields = fields
|
||||
}
|
||||
|
||||
if len(ov.OptionalConfig) > 0 && len(out.OptionalConfig) > 0 {
|
||||
groups := make([]OptionalConfigGroup, len(out.OptionalConfig))
|
||||
copy(groups, out.OptionalConfig)
|
||||
for _, gov := range ov.OptionalConfig {
|
||||
for i := range groups {
|
||||
if groups[i].Group != gov.MatchGroup || gov.MatchGroup == "" {
|
||||
continue
|
||||
}
|
||||
groups[i].Description = overlayStr(gov.Description, groups[i].Description)
|
||||
if len(gov.Fields) > 0 && len(groups[i].Fields) > 0 {
|
||||
flds := make([]OptionalConfigField, len(groups[i].Fields))
|
||||
copy(flds, groups[i].Fields)
|
||||
for _, fo := range gov.Fields {
|
||||
for j := range flds {
|
||||
if flds[j].EnvVar == fo.EnvVar && fo.EnvVar != "" {
|
||||
flds[j].Label = overlayStr(fo.Label, flds[j].Label)
|
||||
flds[j].HelpText = overlayStr(fo.HelpText, flds[j].HelpText)
|
||||
}
|
||||
}
|
||||
}
|
||||
groups[i].Fields = flds
|
||||
}
|
||||
// Group LAST: it is the match key, so translating it earlier would make the
|
||||
// remaining overlay entries for this group unmatchable.
|
||||
groups[i].Group = overlayStr(gov.Group, groups[i].Group)
|
||||
break
|
||||
}
|
||||
}
|
||||
out.OptionalConfig = groups
|
||||
}
|
||||
|
||||
if len(ov.Integrations) > 0 && len(out.Integrations) > 0 {
|
||||
ints := make([]IntegrationDef, len(out.Integrations))
|
||||
copy(ints, out.Integrations)
|
||||
for _, io := range ov.Integrations {
|
||||
for i := range ints {
|
||||
if ints[i].Target == io.Target && io.Target != "" {
|
||||
ints[i].Label = overlayStr(io.Label, ints[i].Label)
|
||||
ints[i].Description = overlayStr(io.Description, ints[i].Description)
|
||||
}
|
||||
}
|
||||
}
|
||||
out.Integrations = ints
|
||||
}
|
||||
|
||||
if len(ov.DataPaths) > 0 && len(out.DataPaths) > 0 {
|
||||
dps := make([]DataPath, len(out.DataPaths))
|
||||
copy(dps, out.DataPaths)
|
||||
for _, do := range ov.DataPaths {
|
||||
for i := range dps {
|
||||
if dps[i].Path == do.Path && do.Path != "" {
|
||||
dps[i].Label = overlayStr(do.Label, dps[i].Label)
|
||||
}
|
||||
}
|
||||
}
|
||||
out.DataPaths = dps
|
||||
}
|
||||
|
||||
if ov.InitialCreds != nil && out.InitialCreds != nil {
|
||||
ic := *out.InitialCreds
|
||||
ic.Note = overlayStr(ov.InitialCreds.Note, ic.Note)
|
||||
out.InitialCreds = &ic
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// MetaFor is For on a stack, and it is the ONLY way a page should reach catalog copy: reading
|
||||
// `stack.Meta.Description` straight out of the manager renders Hungarian to an English household.
|
||||
// TestNoDirectMetaCopyReadOnPages pins that rule on the handler sources.
|
||||
func (s Stack) MetaFor(lang string) Metadata { return s.Meta.For(lang) }
|
||||
|
||||
// LocalizeStacks returns the list as the given language renders it.
|
||||
//
|
||||
// For the base language it returns the INPUT SLICE ITSELF — not a copy. That is deliberate and it
|
||||
// is the parity guarantee in code: the Hungarian page cannot differ from the pre-change one,
|
||||
// because nothing on its path was touched. For another language every element is copied (Stack is
|
||||
// a value type) and only its Meta replaced.
|
||||
func LocalizeStacks(in []Stack, lang string) []Stack {
|
||||
if lang == "" || lang == BaseLanguage {
|
||||
return in
|
||||
}
|
||||
out := make([]Stack, len(in))
|
||||
copy(out, in)
|
||||
for i := range out {
|
||||
out[i].Meta = out[i].Meta.For(lang)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// LocalizeStack is LocalizeStacks for a single stack.
|
||||
func LocalizeStack(in Stack, lang string) Stack {
|
||||
in.Meta = in.Meta.For(lang)
|
||||
return in
|
||||
}
|
||||
|
||||
// LocalizeStackPtr is LocalizeStack for a stack POINTER, returning a NEW pointer so the value the
|
||||
// caller holds — which may be the manager's own — is never written through. A nil stack stays nil.
|
||||
func LocalizeStackPtr(in *Stack, lang string) *Stack {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := *in
|
||||
out.Meta = out.Meta.For(lang)
|
||||
return &out
|
||||
}
|
||||
@@ -0,0 +1,478 @@
|
||||
package stacks
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// testdata/catalog is a SNAPSHOT of all 53 `templates/<app>/.felhom.yml` from
|
||||
// app-catalog-felhom.eu at 94bc5febaca2 (2026-09-20), copied verbatim. It is here so the identity
|
||||
// property below is measured on the REAL catalog rather than on a fixture written to pass.
|
||||
//
|
||||
// Refresh it with, from this repo's `controller/` directory:
|
||||
//
|
||||
// for d in ../../app-catalog-felhom.eu/templates/*/; do
|
||||
// a=$(basename "$d"); mkdir -p internal/stacks/testdata/catalog/$a
|
||||
// cp "$d/.felhom.yml" internal/stacks/testdata/catalog/$a/.felhom.yml
|
||||
// done
|
||||
//
|
||||
// A refresh is only ever a copy — if one of these tests then fails, the catalog has grown a shape
|
||||
// the overlay does not handle, which is the finding, not a reason to edit the fixture.
|
||||
const catalogFixtureDir = "testdata/catalog"
|
||||
|
||||
func loadCatalogFixtures(t *testing.T) map[string]Metadata {
|
||||
t.Helper()
|
||||
entries, err := os.ReadDir(catalogFixtureDir)
|
||||
if err != nil {
|
||||
t.Fatalf("catalog fixtures unreadable: %v", err)
|
||||
}
|
||||
out := make(map[string]Metadata, len(entries))
|
||||
for _, e := range entries {
|
||||
if !e.IsDir() {
|
||||
continue
|
||||
}
|
||||
b, err := os.ReadFile(filepath.Join(catalogFixtureDir, e.Name(), ".felhom.yml"))
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v", e.Name(), err)
|
||||
}
|
||||
var m Metadata
|
||||
if err := yaml.Unmarshal(b, &m); err != nil {
|
||||
t.Fatalf("%s: %v", e.Name(), err)
|
||||
}
|
||||
out[e.Name()] = m
|
||||
}
|
||||
if len(out) < 50 {
|
||||
t.Fatalf("only %d catalog fixtures found — the snapshot is not the catalog", len(out))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// TestMetaForHuIsIdentity — S1. The Hungarian product must render byte-for-byte the same before and
|
||||
// after this slice (10-localisation.md §1). `For("hu")` is therefore required to be the parsed
|
||||
// struct with nothing but `I18n` cleared, over every real catalog file.
|
||||
//
|
||||
// RED-PROOF: mutating any copy field inside For's hu branch — e.g. adding
|
||||
// `out.Description = out.Description + " "` before the `lang == BaseLanguage` return — fails this
|
||||
// naming the app and the field. Run 2026-09-20: FAIL on 53 apps, then green after revert.
|
||||
func TestMetaForHuIsIdentity(t *testing.T) {
|
||||
for app, m := range loadCatalogFixtures(t) {
|
||||
want := m
|
||||
want.I18n = nil
|
||||
for _, lang := range []string{"hu", ""} {
|
||||
got := m.For(lang)
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("%s: For(%q) changed the Hungarian metadata\n got: %+v\nwant: %+v", app, lang, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestMetaForUnknownLanguageIsHungarian — a language no template carries a block for must fall all
|
||||
// the way back, not render blanks. This is the state EVERY app is in until its batch is pushed.
|
||||
func TestMetaForUnknownLanguageIsHungarian(t *testing.T) {
|
||||
for app, m := range loadCatalogFixtures(t) {
|
||||
want := m
|
||||
want.I18n = nil
|
||||
if got := m.For("en"); !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("%s: For(\"en\") on an untranslated app is not the Hungarian view", app)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestCatalogFixturesCarryNoOverlayYet pins the fact the two tests above depend on: the snapshot is
|
||||
// of an UNTRANSLATED catalog, so "For(en) equals Hungarian" above is a real assertion and not a
|
||||
// tautology that would keep passing once a block exists. When the pilot lands in the catalog and the
|
||||
// snapshot is refreshed, this test fails — and the refresher must then split the fixture set into
|
||||
// translated and untranslated, rather than delete the assertion.
|
||||
func TestCatalogFixturesCarryNoOverlayYet(t *testing.T) {
|
||||
for app, m := range loadCatalogFixtures(t) {
|
||||
if len(m.I18n) != 0 {
|
||||
t.Errorf("%s: the snapshot now carries an i18n block — see this test's comment", app)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// overlayFixture is one hand-written app carrying a PARTIAL English block: `description`, the
|
||||
// tagline, first_steps and ONE of two deploy fields, with the English deploy_fields list in the
|
||||
// OPPOSITE order to the Hungarian one.
|
||||
const overlayFixture = `
|
||||
display_name: "Fixture"
|
||||
description: "Magyar leírás"
|
||||
slug: fixture
|
||||
app_info:
|
||||
tagline: "Magyar tagline"
|
||||
use_cases:
|
||||
- "Magyar eset egy"
|
||||
- "Magyar eset kettő"
|
||||
first_steps:
|
||||
- "Magyar lépés egy"
|
||||
- "Magyar lépés kettő"
|
||||
prerequisites:
|
||||
- "Magyar előfeltétel"
|
||||
default_creds: "admin / admin"
|
||||
deploy_fields:
|
||||
- env_var: FIRST
|
||||
label: "Első mező"
|
||||
description: "Az első mező leírása"
|
||||
placeholder: "elso"
|
||||
type: text
|
||||
default: "alap"
|
||||
required: true
|
||||
- env_var: SECOND
|
||||
label: "Második mező"
|
||||
description: "A második mező leírása"
|
||||
type: select
|
||||
options:
|
||||
- value: "yes"
|
||||
label: "Igen"
|
||||
- value: "no"
|
||||
label: "Nem"
|
||||
i18n:
|
||||
en:
|
||||
description: "English description"
|
||||
app_info:
|
||||
tagline: "English tagline"
|
||||
first_steps:
|
||||
- "English step one"
|
||||
- "English step two"
|
||||
deploy_fields:
|
||||
- env_var: SECOND
|
||||
label: "Second field"
|
||||
options:
|
||||
- value: "no"
|
||||
label: "No"
|
||||
- env_var: FIRST
|
||||
description: "The first field explained"
|
||||
`
|
||||
|
||||
func parseFixture(t *testing.T, src string) Metadata {
|
||||
t.Helper()
|
||||
var m Metadata
|
||||
if err := yaml.Unmarshal([]byte(src), &m); err != nil {
|
||||
t.Fatalf("fixture: %v", err)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// TestMetaForEnFieldByField — S2. Every English field present wins; every absent one shows the
|
||||
// Hungarian; nothing renders blank.
|
||||
func TestMetaForEnFieldByField(t *testing.T) {
|
||||
en := parseFixture(t, overlayFixture).For("en")
|
||||
|
||||
checks := []struct{ name, got, want string }{
|
||||
{"description", en.Description, "English description"},
|
||||
{"tagline", en.AppInfo.Tagline, "English tagline"},
|
||||
// Absent from the English block — the Hungarian must show through, field by field.
|
||||
{"default_creds", en.AppInfo.DefaultCreds, "admin / admin"},
|
||||
{"display_name", en.DisplayName, "Fixture"},
|
||||
}
|
||||
for _, c := range checks {
|
||||
if c.got != c.want {
|
||||
t.Errorf("%s = %q, want %q", c.name, c.got, c.want)
|
||||
}
|
||||
}
|
||||
if got := strings.Join(en.AppInfo.FirstSteps, "|"); got != "English step one|English step two" {
|
||||
t.Errorf("first_steps = %q", got)
|
||||
}
|
||||
// use_cases and prerequisites carry no English — whole Hungarian lists, not empty ones.
|
||||
if got := strings.Join(en.AppInfo.UseCases, "|"); got != "Magyar eset egy|Magyar eset kettő" {
|
||||
t.Errorf("use_cases fell back wrong: %q", got)
|
||||
}
|
||||
if got := strings.Join(en.AppInfo.Prerequisites, "|"); got != "Magyar előfeltétel" {
|
||||
t.Errorf("prerequisites fell back wrong: %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestDeployFieldsMatchedByKey — S2's second half, and the one that would fail silently on a live
|
||||
// box: the English deploy_fields list is in the OPPOSITE order, so a position match would put
|
||||
// "Second field" on FIRST. Everything that is not copy must also survive untouched.
|
||||
func TestDeployFieldsMatchedByKey(t *testing.T) {
|
||||
en := parseFixture(t, overlayFixture).For("en")
|
||||
byVar := map[string]DeployField{}
|
||||
for _, f := range en.DeployFields {
|
||||
byVar[f.EnvVar] = f
|
||||
}
|
||||
|
||||
first, second := byVar["FIRST"], byVar["SECOND"]
|
||||
if first.Label != "Első mező" {
|
||||
t.Errorf("FIRST.label = %q — the English block does not translate it", first.Label)
|
||||
}
|
||||
if first.Description != "The first field explained" {
|
||||
t.Errorf("FIRST.description = %q", first.Description)
|
||||
}
|
||||
if first.Placeholder != "elso" {
|
||||
t.Errorf("FIRST.placeholder = %q — no English given, Hungarian expected", first.Placeholder)
|
||||
}
|
||||
if second.Label != "Second field" {
|
||||
t.Errorf("SECOND.label = %q", second.Label)
|
||||
}
|
||||
if second.Description != "A második mező leírása" {
|
||||
t.Errorf("SECOND.description = %q", second.Description)
|
||||
}
|
||||
|
||||
// Non-copy fields are not in MetadataOverlay at all, and this is the assertion that says so.
|
||||
if first.Default != "alap" || !first.Required || first.Type != "text" {
|
||||
t.Errorf("FIRST lost configuration: %+v", first)
|
||||
}
|
||||
|
||||
// Options are matched by VALUE, and only the one the block names changes.
|
||||
opts := map[string]string{}
|
||||
for _, o := range second.Options {
|
||||
opts[o.Value] = o.Label
|
||||
}
|
||||
if opts["no"] != "No" {
|
||||
t.Errorf("option no = %q, want %q", opts["no"], "No")
|
||||
}
|
||||
if opts["yes"] != "Igen" {
|
||||
t.Errorf("option yes = %q — untranslated options must stay Hungarian", opts["yes"])
|
||||
}
|
||||
}
|
||||
|
||||
// TestEmptyEnglishFallsBack — a translator who leaves a field as `""` must not blank the page.
|
||||
// Operator ruling 3 (10-localisation.md §4): never a key, never an empty box.
|
||||
func TestEmptyEnglishFallsBack(t *testing.T) {
|
||||
m := parseFixture(t, `
|
||||
description: "Magyar leírás"
|
||||
app_info:
|
||||
tagline: "Magyar tagline"
|
||||
use_cases: ["Magyar eset"]
|
||||
i18n:
|
||||
en:
|
||||
description: ""
|
||||
app_info:
|
||||
tagline: " "
|
||||
use_cases: []
|
||||
`)
|
||||
en := m.For("en")
|
||||
if en.Description != "Magyar leírás" {
|
||||
t.Errorf("empty English description did not fall back: %q", en.Description)
|
||||
}
|
||||
if en.AppInfo.Tagline != "Magyar tagline" {
|
||||
t.Errorf("whitespace-only English tagline did not fall back: %q", en.AppInfo.Tagline)
|
||||
}
|
||||
if len(en.AppInfo.UseCases) != 1 || en.AppInfo.UseCases[0] != "Magyar eset" {
|
||||
t.Errorf("empty English list did not fall back: %v", en.AppInfo.UseCases)
|
||||
}
|
||||
}
|
||||
|
||||
// TestForDoesNotMutateTheReceiver — the metadata For reads lives in the stack manager's cache and
|
||||
// is shared by every concurrent request. An in-place write would leak one household's language into
|
||||
// another household's page, and the page would look perfectly normal.
|
||||
// NOTE ON HOW THIS IS ASSERTED. The obvious form — copy the struct, call For, DeepEqual the copy
|
||||
// against the original — IS HOLLOW, and was written that way first: a struct copy shares the slices'
|
||||
// backing arrays, so a write through `out.DeployFields[i].Label` changes BOTH sides and the compare
|
||||
// passes. It did pass, on a deliberately broken For, in this file's red-proof run. What follows
|
||||
// therefore snapshots the concrete STRINGS before the call and compares those.
|
||||
func TestForDoesNotMutateTheReceiver(t *testing.T) {
|
||||
m := parseFixture(t, overlayFixture)
|
||||
snap := func() []string {
|
||||
out := []string{m.Description, m.AppInfo.Tagline, strings.Join(m.AppInfo.FirstSteps, "|")}
|
||||
for _, f := range m.DeployFields {
|
||||
out = append(out, f.EnvVar, f.Label, f.Description, f.Placeholder)
|
||||
for _, o := range f.Options {
|
||||
out = append(out, o.Value, o.Label)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
before := snap()
|
||||
_ = m.For("en")
|
||||
if after := snap(); !reflect.DeepEqual(before, after) {
|
||||
t.Fatalf("For(\"en\") wrote through to the receiver\nbefore: %q\n after: %q", before, after)
|
||||
}
|
||||
// And the hu view taken AFTER an English render is still Hungarian.
|
||||
if hu := m.For("hu"); hu.Description != "Magyar leírás" || hu.DeployFields[1].Options[1].Label != "Nem" {
|
||||
t.Fatalf("Hungarian view damaged by an English render: %q / %q", hu.Description, hu.DeployFields[1].Options[1].Label)
|
||||
}
|
||||
}
|
||||
|
||||
// TestOverlayMatchesOptionalConfigIntegrationsAndDataPaths covers the three key-matched blocks the
|
||||
// main fixture leaves out. optional_config groups have no id of their own, so the overlay names the
|
||||
// Hungarian group it translates in `match_group`.
|
||||
func TestOverlayMatchesOptionalConfigIntegrationsAndDataPaths(t *testing.T) {
|
||||
// EACH LIST CARRIES TWO ENTRIES AND THE OVERLAY NAMES ONLY THE SECOND. With a single entry per
|
||||
// list — how this fixture was first written — position and key agree, and a position-matching
|
||||
// implementation passes the test. It did, in this file's red-proof run. Two entries, translated
|
||||
// out of order, is what makes the assertion mean anything.
|
||||
m := parseFixture(t, `
|
||||
optional_config:
|
||||
- group: "Egyéb"
|
||||
description: "Nem fordított csoport"
|
||||
fields:
|
||||
- env_var: OTHER_KEY
|
||||
label: "Más kulcs"
|
||||
help_text: "Más magyar súgó"
|
||||
- group: "Metaadat-szolgáltatók"
|
||||
description: "Magyar csoportleírás"
|
||||
fields:
|
||||
- env_var: KEY_ONE
|
||||
label: "Kulcs egy"
|
||||
help_text: "Magyar súgó"
|
||||
- env_var: KEY_TWO
|
||||
label: "Kulcs kettő"
|
||||
help_text: "Másik magyar súgó"
|
||||
integrations:
|
||||
- target: nextcloud
|
||||
label: "Nem fordított integráció"
|
||||
description: "Nem fordított leírás"
|
||||
- target: filebrowser
|
||||
label: "Magyar integráció"
|
||||
description: "Magyar integrációs leírás"
|
||||
data_paths:
|
||||
- path: "export"
|
||||
role: export
|
||||
label: "Nem fordított mappa"
|
||||
- path: "import"
|
||||
role: import
|
||||
label: "Magyar mappa"
|
||||
initial_credentials:
|
||||
file: /x
|
||||
note: "Magyar megjegyzés"
|
||||
i18n:
|
||||
en:
|
||||
optional_config:
|
||||
- match_group: "Metaadat-szolgáltatók"
|
||||
group: "Metadata providers"
|
||||
fields:
|
||||
- env_var: KEY_TWO
|
||||
help_text: "English help"
|
||||
integrations:
|
||||
- target: filebrowser
|
||||
label: "English integration"
|
||||
data_paths:
|
||||
- path: "import"
|
||||
label: "English folder"
|
||||
initial_credentials:
|
||||
note: "English note"
|
||||
`)
|
||||
en := m.For("en")
|
||||
|
||||
// The FIRST entry of each list is the one nobody translated — it must be untouched.
|
||||
if en.OptionalConfig[0].Group != "Egyéb" || en.OptionalConfig[0].Fields[0].HelpText != "Más magyar súgó" {
|
||||
t.Errorf("an untranslated group was changed: %+v", en.OptionalConfig[0])
|
||||
}
|
||||
if en.Integrations[0].Label != "Nem fordított integráció" {
|
||||
t.Errorf("an untranslated integration was changed: %+v", en.Integrations[0])
|
||||
}
|
||||
if en.DataPaths[0].Label != "Nem fordított mappa" {
|
||||
t.Errorf("an untranslated data_path was changed: %+v", en.DataPaths[0])
|
||||
}
|
||||
|
||||
g := en.OptionalConfig[1]
|
||||
if g.Group != "Metadata providers" {
|
||||
t.Errorf("group = %q", g.Group)
|
||||
}
|
||||
if g.Description != "Magyar csoportleírás" {
|
||||
t.Errorf("group description should fall back: %q", g.Description)
|
||||
}
|
||||
if g.Fields[1].HelpText != "English help" {
|
||||
t.Errorf("KEY_TWO help_text = %q", g.Fields[1].HelpText)
|
||||
}
|
||||
if g.Fields[0].HelpText != "Magyar súgó" || g.Fields[1].Label != "Kulcs kettő" {
|
||||
t.Errorf("unnamed optional-config fields must stay Hungarian: %+v", g.Fields)
|
||||
}
|
||||
if en.Integrations[1].Label != "English integration" || en.Integrations[1].Description != "Magyar integrációs leírás" {
|
||||
t.Errorf("integration overlay wrong: %+v", en.Integrations[1])
|
||||
}
|
||||
if en.DataPaths[1].Label != "English folder" || en.DataPaths[1].Path != "import" {
|
||||
t.Errorf("data_path overlay wrong: %+v", en.DataPaths[1])
|
||||
}
|
||||
if en.InitialCreds.Note != "English note" || en.InitialCreds.File != "/x" {
|
||||
t.Errorf("initial_credentials overlay wrong: %+v", en.InitialCreds)
|
||||
}
|
||||
|
||||
// The Hungarian view is still Hungarian afterwards — the nested slices were copied, not edited.
|
||||
hu := m.For("hu")
|
||||
if hu.OptionalConfig[1].Group != "Metaadat-szolgáltatók" || hu.OptionalConfig[1].Fields[1].HelpText != "Másik magyar súgó" {
|
||||
t.Errorf("Hungarian optional_config damaged: %+v", hu.OptionalConfig[1])
|
||||
}
|
||||
if hu.InitialCreds.Note != "Magyar megjegyzés" {
|
||||
t.Errorf("Hungarian initial_credentials note damaged: %q", hu.InitialCreds.Note)
|
||||
}
|
||||
}
|
||||
|
||||
// TestUnmatchedOverlayEntriesAreInert — an English entry whose key has no Hungarian twin must
|
||||
// change nothing. (The catalog gate REFUSES such a file; this is the controller's behaviour if one
|
||||
// reaches a box anyway, e.g. from a hand-edited template.)
|
||||
func TestUnmatchedOverlayEntriesAreInert(t *testing.T) {
|
||||
m := parseFixture(t, `
|
||||
deploy_fields:
|
||||
- env_var: FIRST
|
||||
label: "Első mező"
|
||||
i18n:
|
||||
en:
|
||||
deploy_fields:
|
||||
- env_var: NOSUCHFIELD
|
||||
label: "Ghost"
|
||||
`)
|
||||
en := m.For("en")
|
||||
if len(en.DeployFields) != 1 || en.DeployFields[0].Label != "Első mező" {
|
||||
t.Fatalf("an unmatched overlay entry changed the fields: %+v", en.DeployFields)
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadMetadataReadsTheI18nBlock — the loader is the seam that actually has to see `i18n:`.
|
||||
// Without this the whole overlay could be correct and inert (the "seam built but never wired"
|
||||
// class, on file four times in this project).
|
||||
func TestLoadMetadataReadsTheI18nBlock(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
if err := os.WriteFile(filepath.Join(dir, ".felhom.yml"), []byte(overlayFixture), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
m := LoadMetadata(dir)
|
||||
if len(m.I18n) != 1 {
|
||||
t.Fatalf("LoadMetadata did not parse the i18n block: %+v", m.I18n)
|
||||
}
|
||||
if got := m.For("en").Description; got != "English description" {
|
||||
t.Fatalf("loaded metadata does not localise: %q", got)
|
||||
}
|
||||
if got := m.For("hu").Description; got != "Magyar leírás" {
|
||||
t.Fatalf("loaded metadata changed Hungarian: %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestLocalizeStacksLeavesHungarianSliceAlone — LocalizeStacks returns the INPUT SLICE for hu. That
|
||||
// is the parity guarantee in code, so it is asserted rather than assumed.
|
||||
func TestLocalizeStacksLeavesHungarianSliceAlone(t *testing.T) {
|
||||
in := []Stack{{Name: "a", Meta: parseFixture(t, overlayFixture)}}
|
||||
if got := LocalizeStacks(in, "hu"); &got[0] != &in[0] {
|
||||
t.Fatalf("LocalizeStacks copied the slice for hu")
|
||||
}
|
||||
out := LocalizeStacks(in, "en")
|
||||
if out[0].Meta.Description != "English description" {
|
||||
t.Fatalf("LocalizeStacks did not localise: %q", out[0].Meta.Description)
|
||||
}
|
||||
if in[0].Meta.Description != "Magyar leírás" {
|
||||
t.Fatalf("LocalizeStacks wrote through to the input: %q", in[0].Meta.Description)
|
||||
}
|
||||
if out[0].Meta.I18n != nil {
|
||||
t.Fatalf("the untranslated half must not reach a page")
|
||||
}
|
||||
}
|
||||
|
||||
// TestLocalizeStackPtrReturnsANewPointer — the manager hands out pointers to its own values; a
|
||||
// localised page must never be able to write into one.
|
||||
func TestLocalizeStackPtrReturnsANewPointer(t *testing.T) {
|
||||
st := &Stack{Name: "a", Meta: parseFixture(t, overlayFixture)}
|
||||
out := LocalizeStackPtr(st, "en")
|
||||
if out == st {
|
||||
t.Fatalf("LocalizeStackPtr returned the caller's pointer")
|
||||
}
|
||||
if st.Meta.Description != "Magyar leírás" {
|
||||
t.Fatalf("the manager's value was localised in place: %q", st.Meta.Description)
|
||||
}
|
||||
if LocalizeStackPtr(nil, "en") != nil {
|
||||
t.Fatalf("nil must stay nil")
|
||||
}
|
||||
if got := LocalizeStackPtr(st, "hu"); got.Meta.Description != "Magyar leírás" {
|
||||
t.Fatalf("hu view wrong: %q", got.Meta.Description)
|
||||
}
|
||||
if got := st.MetaFor("en"); got.Description != "English description" {
|
||||
t.Fatalf("MetaFor wrong: %q", got.Description)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml — App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
# Place alongside docker-compose.yml in each stack directory:
|
||||
# /opt/docker/stacks/actualbudget/.felhom.yml
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "ActualBudget"
|
||||
description: "Személyes pénzügyek és költségvetés kezelése"
|
||||
category: "finance"
|
||||
subdomain: "budget"
|
||||
|
||||
# --- Asset slug ---
|
||||
slug: "actualbudget"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "50M"
|
||||
mem_limit: "256M"
|
||||
pi_compatible: true
|
||||
needs_hdd: false
|
||||
|
||||
# --- 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: "budget"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: 'Költségvetés tervező - pénzügyeid kézben tartása egyszerűen'
|
||||
docs_url: 'https://actualbudget.org/docs/'
|
||||
|
||||
use_cases:
|
||||
- 'Havi költségvetés tervezése és követése envelope módszerrel'
|
||||
- 'Bankszámla tranzakciók importálása és kategorizálása'
|
||||
- 'Riportok és grafikonok a kiadásokról és bevételekről'
|
||||
- 'Több felhasználó - közös háztartási pénzügyek kezelése'
|
||||
- 'Offline is működik, szinkronizálás a szerver és eszközök között'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a budget.DOMAIN címet a böngészőben'
|
||||
- 'Hozz létre egy jelszót az első megnyitáskor'
|
||||
- 'Hozd létre a költségvetési kategóriákat (pl. élelmiszer, közlekedés)'
|
||||
- 'Adj hozzá számlákat és kezdd el rögzíteni a tranzakciókat'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 5006
|
||||
@@ -0,0 +1,81 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "AdventureLog"
|
||||
description: "Utazási napló és kalandtervező"
|
||||
category: "travel"
|
||||
subdomain: "travel"
|
||||
slug: "adventurelog"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "100M"
|
||||
mem_limit: "384M"
|
||||
pi_compatible: true
|
||||
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: "travel"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: SECRET_KEY
|
||||
label: "Titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
# Data-encrypting key: the app secures stored data with it, so it must NOT be regenerated on
|
||||
# restore (that would render restored data unreadable). The recovery unit stays secret-free; at
|
||||
# restore the controller recovers this key from the guest's own app.yaml (live, or via the PBS
|
||||
# whole-guest snapshot) and FAILS CLOSED (refuse + warn) if it cannot — never silently restores.
|
||||
data_key: true
|
||||
|
||||
- env_var: DB_PASSWORD
|
||||
label: "Adatbázis jelszó"
|
||||
type: secret
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Utazási napló - utazások dokumentálása térképpel és fotókkal"
|
||||
docs_url: "https://adventurelog.app/docs/"
|
||||
|
||||
use_cases:
|
||||
- 'Utazások dokumentálása képekkel és jegyzetekkel'
|
||||
- 'Térképes megjelenítés a meglátogatott helyekről'
|
||||
- 'Úti tervek készítése és szervezése'
|
||||
- 'Statisztikák - meglátogatott országok, városok'
|
||||
- 'Kalandok megosztása családdal és barátokkal'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a travel.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre a fiókodat'
|
||||
- 'Add hozzá az első utazásodat'
|
||||
- 'Jelöld meg a meglátogatott helyeket a térképen'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 8000
|
||||
path: "/api/"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,86 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Audiobookshelf"
|
||||
description: "Hangoskönyv és podcast kezelő szerver"
|
||||
category: "media"
|
||||
subdomain: "audiobooks"
|
||||
slug: "audiobookshelf"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "100M"
|
||||
mem_limit: "512M"
|
||||
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/audiobooks
|
||||
class: optional # PENDING-VETO: spike chose excluded; ruled optional for consistency
|
||||
# with komga/romm (curated, often personally ripped — precious).
|
||||
# If Viktor rules excluded, flip THIS LINE ONLY before committing.
|
||||
- path: media/podcasts
|
||||
class: excluded # re-downloadable by definition
|
||||
|
||||
# --- 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: "audiobooks"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: HDD_PATH
|
||||
label: "Hangoskönyv tá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: "Hangoskönyv és podcast kezelő, lejátszó és szinkronizáló"
|
||||
docs_url: "https://www.audiobookshelf.org/docs"
|
||||
|
||||
use_cases:
|
||||
- 'Hangoskönyvek és podcastok rendszerezése és lejátszása'
|
||||
- 'Automatikus metaadat letöltés - borítók, leírások, fejezetek'
|
||||
- 'Folytatás ott, ahol abbahagytad (szinkron eszközök között)'
|
||||
- 'Podcast feliratkozás és automatikus letöltés'
|
||||
- 'Dedikált mobil alkalmazások (Android, iOS)'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg az audiobooks.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre az admin fiókot az első megnyitáskor'
|
||||
- 'Add hozzá a könyvtárakat (/audiobooks és/vagy /podcasts)'
|
||||
- 'Várd meg az automatikus szkennelést'
|
||||
- 'Telepítsd az Audiobookshelf alkalmazást a telefonodra'
|
||||
|
||||
prerequisites:
|
||||
- 'Külső HDD szükséges a hangoskönyvek tárolásához'
|
||||
- 'Hangoskönyvek mappákba rendezve (pl. Szerző/Könyv/)'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 80
|
||||
path: "/healthcheck"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,60 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "BentoPDF"
|
||||
description: "Adatvédelmi fókuszú PDF eszköztár"
|
||||
category: "tools"
|
||||
subdomain: "pdf"
|
||||
slug: "bentopdf"
|
||||
# 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-07-12"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "100M"
|
||||
mem_limit: "384M"
|
||||
pi_compatible: true
|
||||
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: "pdf"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Adatvédelmi fókuszú PDF eszköztár - a fájlok soha nem hagyják el a szervered"
|
||||
docs_url: "https://www.bentopdf.com/docs/"
|
||||
|
||||
use_cases:
|
||||
- 'PDF összefűzés, szétválasztás és forgatás'
|
||||
- 'PDF konvertálás képekké és képekből'
|
||||
- 'Jelszóvédelem és titkosítás'
|
||||
- 'Vízjel hozzáadása dokumentumokhoz'
|
||||
- 'Minden feldolgozás a szerveren - a fájlok nem kerülnek külső szolgáltatóhoz'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a pdf.DOMAIN címet a böngészőben'
|
||||
- 'Válaszd ki a kívánt műveletet'
|
||||
- 'Töltsd fel a PDF fájlt és kattints a feldolgozásra'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 8080
|
||||
@@ -0,0 +1,75 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "BookStack"
|
||||
description: "Egyszerű, könyv-szerű wiki és dokumentáció platform"
|
||||
category: "productivity"
|
||||
subdomain: "wiki"
|
||||
slug: "bookstack"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "150M"
|
||||
mem_limit: "512M"
|
||||
pi_compatible: true
|
||||
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: "wiki"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: APP_KEY
|
||||
label: "Alkalmazás kulcs"
|
||||
type: secret
|
||||
generate: "base64key:32"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: DB_PASSWORD
|
||||
label: "Adatbázis jelszó"
|
||||
type: secret
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Egyszerű wiki platform - polcok, könyvek, fejezetek és oldalak"
|
||||
default_creds: "admin@admin.com / password"
|
||||
docs_url: "https://www.bookstackapp.com/docs/"
|
||||
|
||||
use_cases:
|
||||
- 'Családi tudásbázis - receptek, kézikönyvek, szabályok'
|
||||
- 'Projekt dokumentáció strukturált formában'
|
||||
- 'Könyv > Fejezet > Oldal hierarchia az áttekinthetőségért'
|
||||
- 'Teljes szöveges keresés és címkék'
|
||||
- 'WYSIWYG és Markdown szerkesztő'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a wiki.DOMAIN címet a böngészőben'
|
||||
- 'Jelentkezz be: admin@admin.com / password'
|
||||
- 'Változtasd meg azonnal az admin jelszót és email címet'
|
||||
- 'Hozd létre az első polcot és könyvet'
|
||||
- 'Kezdj el írni!'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 80
|
||||
@@ -0,0 +1,101 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Cal.com"
|
||||
description: "Nyílt forráskódú időpontfoglaló (Calendly alternatíva)"
|
||||
category: "travel"
|
||||
subdomain: "cal"
|
||||
slug: "calcom"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "200M"
|
||||
mem_limit: "768M"
|
||||
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: "cal"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: NEXTAUTH_SECRET
|
||||
label: "NextAuth titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: CALENDSO_ENCRYPTION_KEY
|
||||
label: "Titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:16"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: DB_PASSWORD
|
||||
label: "Adatbázis jelszó"
|
||||
type: secret
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Időpontfoglaló - Calendly alternatíva saját szerveren"
|
||||
docs_url: "https://cal.com/docs/"
|
||||
|
||||
use_cases:
|
||||
- 'Időpontfoglalási oldal létrehozása ügyfeleknek'
|
||||
- 'Naptár szinkronizáció (Google Calendar, Outlook)'
|
||||
- 'Személyre szabható foglalási típusok és időtartamok'
|
||||
- 'Automatikus emlékeztető emailek'
|
||||
- 'Csapat naptár kezelés'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a cal.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre az admin fiókot'
|
||||
- 'Állíts be egy foglalási típust (pl. 30 perces megbeszélés)'
|
||||
- 'Szinkronizáld a naptáradat'
|
||||
- 'Oszd meg a foglalási linket'
|
||||
|
||||
prerequisites:
|
||||
- 'x86 processzor szükséges'
|
||||
- 'Legalább 1 GB szabad RAM (Cal.com + PostgreSQL)'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 3000
|
||||
# /api/health does not exist in cal.com v4.x (404); /api/auth/providers is a stable 200 once serving.
|
||||
path: "/api/auth/providers"
|
||||
expect:
|
||||
status: 200
|
||||
|
||||
# --- App-email mapping (apps → in-controller shim → hub → Resend) ---
|
||||
# Cal.com (Nodemailer) hard-codes TLS rejectUnauthorized=true with no skip flag and opportunistically
|
||||
# STARTTLS-upgrades whenever the server offers it — so it cannot use the self-signed :2525 listener.
|
||||
# tls_mode=plaintext points it at the :2526 listener, which does NOT advertise STARTTLS, so Cal.com never
|
||||
# attempts TLS (plaintext on the single-tenant app bridge — accepted posture). secure is inferred from the
|
||||
# port (≠465 → plaintext). EMAIL_SERVER_USER/PASSWORD stay unset (the shim accepts no-auth).
|
||||
smtp_mapping:
|
||||
tls_mode: plaintext
|
||||
host_var: EMAIL_SERVER_HOST
|
||||
port_var: EMAIL_SERVER_PORT
|
||||
from_var: EMAIL_FROM
|
||||
from_name_var: EMAIL_FROM_NAME
|
||||
from_local: calcom
|
||||
@@ -0,0 +1,94 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Calibre-Web Automated"
|
||||
description: "Automatizált e-könyv könyvtár - konvertálás, metaadat kezelés és webes olvasó"
|
||||
category: "media"
|
||||
subdomain: "books"
|
||||
slug: "calibre-web"
|
||||
# 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-07-12"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "200M"
|
||||
mem_limit: "768M"
|
||||
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/books
|
||||
class: mandatory # metadata.db lives INSIDE the tree — DB and books are one unit
|
||||
import:
|
||||
- path: calibre
|
||||
class: excluded # ingest inbox, transient
|
||||
|
||||
# --- Customer-facing folder annotation (R-75) ---
|
||||
data_paths:
|
||||
- path: calibre
|
||||
root: import
|
||||
role: import
|
||||
label: "Beolvasandó e-könyvek"
|
||||
- path: media/books
|
||||
root: userdata
|
||||
role: library
|
||||
label: "E-könyvtár"
|
||||
|
||||
# --- 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: "books"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: HDD_PATH
|
||||
label: "E-könyvtár útvonal"
|
||||
type: path
|
||||
required: true
|
||||
placeholder: "/mnt/felhom-drives/hdd_1"
|
||||
description: "A külső merevlemez elérési útja, ahol a Calibre könyvtár található"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: 'Automatizált e-könyv könyvtár - könyvfeldolgozás, formátumkonverzió és OPDS feed'
|
||||
default_creds: "admin / admin123"
|
||||
docs_url: "https://github.com/crocodilestick/Calibre-Web-Automated/wiki"
|
||||
|
||||
use_cases:
|
||||
- 'Automatizált e-könyv feldolgozás - csak dobd be az ingest mappába'
|
||||
- 'Automatikus formátumkonverzió (EPUB, MOBI, PDF, AZW3)'
|
||||
- 'OPDS feed e-olvasókhoz (Kindle, KOReader, Moon+ Reader)'
|
||||
- 'Webes olvasó böngészőben'
|
||||
- 'KOReader szinkronizáció (olvasási pozíció, könyvjelzők)'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a books.DOMAIN címet a böngészőben'
|
||||
- 'Jelentkezz be: admin / admin123'
|
||||
- 'Változtasd meg azonnal a jelszót'
|
||||
- 'Dobj egy könyvet a Fájlkezelőben (FileBrowser) az import/calibre mappába — automatikusan feldolgozza és a media/books könyvtárba helyezi'
|
||||
|
||||
prerequisites:
|
||||
- 'Külső HDD szükséges az e-könyvek tárolásához'
|
||||
- 'x86 processzor szükséges (a CWA tartalmazza a Calibre binárist)'
|
||||
- 'Legalább 768 MB szabad RAM ajánlott'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 8083
|
||||
@@ -0,0 +1,73 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Claper"
|
||||
description: "Interaktív prezentáció és közönség bevonás"
|
||||
category: "productivity"
|
||||
subdomain: "present"
|
||||
slug: "claper"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "100M"
|
||||
mem_limit: "384M"
|
||||
pi_compatible: true
|
||||
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: "present"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: SECRET_KEY_BASE
|
||||
label: "Titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: DB_PASSWORD
|
||||
label: "Adatbázis jelszó"
|
||||
type: secret
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Interaktív prezentáció - szavazás, kérdések és reakciók élőben"
|
||||
docs_url: "https://docs.claper.co/"
|
||||
|
||||
use_cases:
|
||||
- 'Interaktív prezentációk élő szavazásokkal'
|
||||
- 'Közönség kérdéseinek gyűjtése és megjelenítése'
|
||||
- 'Reakciók és visszajelzések valós időben'
|
||||
- 'PDF prezentációk feltöltése és megosztása'
|
||||
- 'QR kód a közönség gyors csatlakozásához'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a present.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre a fiókodat'
|
||||
- 'Tölts fel egy PDF prezentációt'
|
||||
- 'Oszd meg a kódot a közönséggel'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 4000
|
||||
@@ -0,0 +1,75 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Code-Server"
|
||||
description: "VS Code a böngészőben - kódolás bárhonnan"
|
||||
category: "dev"
|
||||
subdomain: "code"
|
||||
slug: "code-server"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "200M"
|
||||
mem_limit: "1024M"
|
||||
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: "code"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: PASSWORD
|
||||
label: "Hozzáférési jelszó"
|
||||
type: password
|
||||
generate: "password:16"
|
||||
description: "Bejelentkezési jelszó a szerkesztőhöz."
|
||||
locked_after_deploy: false
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "VS Code a böngészőben - teljes fejlesztői környezet bárhonnan"
|
||||
default_creds: "(telepítéskor generált jelszó)"
|
||||
docs_url: "https://coder.com/docs/code-server/"
|
||||
|
||||
use_cases:
|
||||
- 'Kódolás bárhonnan, bármilyen eszközről böngészőben'
|
||||
- 'VS Code teljes funkcionalitás - bővítmények, terminál, debug'
|
||||
- 'Távoli fejlesztés alacsony sávszélességű kapcsolaton is'
|
||||
- 'Egységes fejlesztői környezet több eszközről'
|
||||
- 'Tableten és iPaden is használható'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a code.DOMAIN címet a böngészőben'
|
||||
- 'Add meg a hozzáférési jelszót'
|
||||
- 'Nyisd meg a terminált (Ctrl+`) és telepíts eszközöket'
|
||||
- 'Telepíts bővítményeket az Extensions panelben'
|
||||
|
||||
prerequisites:
|
||||
- 'x86 processzor szükséges a legjobb teljesítményhez'
|
||||
- 'Legalább 1 GB szabad RAM ajánlott'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 8443
|
||||
path: "/healthz"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,86 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Crafty Controller"
|
||||
description: "Minecraft szerver kezelő webes felülettel"
|
||||
category: "games"
|
||||
subdomain: "minecraft"
|
||||
slug: "crafty-controller"
|
||||
# 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-06-26"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "256M"
|
||||
mem_limit: "2048M"
|
||||
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: "minecraft"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: CRAFTY_PASSWORD
|
||||
label: "Admin jelszó"
|
||||
type: password
|
||||
generate: password:24
|
||||
locked_after_deploy: true
|
||||
description: "A Crafty admin felhasználó (admin) kezdeti jelszava — ezzel tudsz belépni a kezelőfelületre"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Minecraft szerver kezelő - hozd létre a saját világodat"
|
||||
docs_url: "https://docs.craftycontrol.com/"
|
||||
|
||||
use_cases:
|
||||
- 'Minecraft szerver létrehozása és kezelése webes felületen'
|
||||
- 'Több szerver párhuzamos futtatása (Java és Bedrock)'
|
||||
- 'Automatikus mentések és ütemezett újraindítás'
|
||||
- 'Játékos menedzsment és konzol hozzáférés'
|
||||
- 'Szerver fájlok kezelése böngészőből'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a minecraft.DOMAIN címet a böngészőben'
|
||||
- 'A kezdeti belépési adatokat ezen az oldalon (Kezdeti belépési adatok) találod'
|
||||
- 'Hozz létre egy új Minecraft szervert a varázslóval'
|
||||
- 'Állítsd be a szerver beállításokat (játékmód, nehézség, stb.)'
|
||||
- 'Állítsd be a szerver portját a 25565–25575 tartományon belül (server.properties → server-port); az első szerver a 25565-öt használja, a továbbiak 25566–25575-öt'
|
||||
- 'Helyi hálózaton csatlakozz a szerver helyi IP-címére és portjára (pl. 192.168.x.x:25565) — a Minecraft kliens „helyi hálózat keresése” nem listázza automatikusan, add meg kézzel a címet'
|
||||
- 'Interneten keresztüli eléréshez port-továbbítás szükséges a választott port(ok)ra — egyeztess az üzemeltetővel'
|
||||
|
||||
prerequisites:
|
||||
- 'Legalább 2 GB szabad RAM ajánlott (Minecraft szerver + Crafty)'
|
||||
- 'x86 processzor szükséges (nem fut Raspberry Pi-n)'
|
||||
- 'A Minecraft szerverek a 25565–25575 porttartományt használhatják (egyszerre legfeljebb 11 szerver)'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: tcp
|
||||
port: 8443
|
||||
|
||||
# --- Initial login (felhom-seeded) ---
|
||||
# The admin password is seeded into default.json by the compose entrypoint (CRAFTY_PASSWORD deploy
|
||||
# field). The controller reads it back from default.json and shows it on the app page under "Kezdeti
|
||||
# belépési adatok" — same value the customer set at deploy time.
|
||||
initial_credentials:
|
||||
file: /crafty/app/config/default.json
|
||||
format: json
|
||||
username_key: username
|
||||
password_key: password
|
||||
note: "Kezdeti admin jelszó (a telepítéskor beállított). Az első belépés után változtasd meg a Crafty felületén — ez a kártya továbbra is a kezdeti jelszót mutatja."
|
||||
@@ -0,0 +1,81 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml — App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
# Place alongside docker-compose.yml in each stack directory:
|
||||
# /opt/docker/stacks/docmost/.felhom.yml
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Docmost"
|
||||
description: "Modern wiki és dokumentáció platform (Notion-szerű)"
|
||||
category: "productivity"
|
||||
subdomain: "docs"
|
||||
|
||||
# --- Asset slug ---
|
||||
slug: "docmost"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "200M"
|
||||
mem_limit: "768M"
|
||||
pi_compatible: false
|
||||
needs_hdd: false
|
||||
|
||||
# --- 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: "docs"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: APP_SECRET
|
||||
label: "Alkalmazás titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: DB_PASSWORD
|
||||
label: "Adatbázis jelszó"
|
||||
type: secret
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: 'Modern wiki és dokumentáció platform Notion-szerű szerkesztővel'
|
||||
docs_url: 'https://docmost.com/docs/'
|
||||
|
||||
use_cases:
|
||||
- 'Csapat tudásbázis és belső dokumentáció'
|
||||
- 'Notion-szerű blokk szerkesztő valós idejű együttműködéssel'
|
||||
- 'Terek és oldalak hierarchikus szervezése'
|
||||
- 'Képek, táblázatok és kód blokkok beágyazása'
|
||||
- 'Keresés a teljes dokumentációban'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a docs.DOMAIN címet a böngészőben'
|
||||
- 'Az első regisztrált felhasználó automatikusan admin lesz'
|
||||
- 'Hozd létre az első teret (Space) a dokumentumoknak'
|
||||
- 'Kezdj el írni a Notion-szerű szerkesztőben'
|
||||
|
||||
prerequisites:
|
||||
- 'x86 processzor szükséges'
|
||||
- 'Legalább 768 MB szabad RAM (Docmost + PostgreSQL + Redis)'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 3000
|
||||
@@ -0,0 +1,83 @@
|
||||
# =============================================================================
|
||||
# .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-07-18"
|
||||
|
||||
# --- 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
|
||||
@@ -0,0 +1,65 @@
|
||||
# =============================================================================
|
||||
# .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-07-18"
|
||||
# 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
|
||||
@@ -0,0 +1,81 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Gitea"
|
||||
description: "Könnyű, saját Git szerver webes felülettel"
|
||||
category: "dev"
|
||||
subdomain: "git"
|
||||
slug: "gitea"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "100M"
|
||||
mem_limit: "512M"
|
||||
pi_compatible: true
|
||||
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: "git"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Saját Git szerver - GitHub-szerű felület, privát repók"
|
||||
docs_url: "https://docs.gitea.com/"
|
||||
|
||||
use_cases:
|
||||
- 'Privát Git repozitóriók a saját szerveren'
|
||||
- 'GitHub-szerű felület: pull request, issue, wiki'
|
||||
- 'CI/CD pipeline-ok (Gitea Actions - GitHub Actions kompatibilis)'
|
||||
- 'Szervezetek és csapatok kezelése'
|
||||
- 'Container registry és csomagkezelő'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a git.DOMAIN címet a böngészőben'
|
||||
- 'Kövesd az első beállítás varázslót'
|
||||
- 'Hozd létre az admin fiókot'
|
||||
- 'Hozd létre az első repozitóriót'
|
||||
- 'Klónozd a repót: git clone https://git.DOMAIN/user/repo.git'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 3000
|
||||
# /api/healthz is always available (200) once serving; /api/v1/version 404s pre-install-lock.
|
||||
path: "/api/healthz"
|
||||
expect:
|
||||
status: 200
|
||||
|
||||
# --- App-email mapping (apps → in-controller shim → hub → Resend) ---
|
||||
# Gitea uses STARTTLS to the shim and trusts its self-signed cert via FORCE_TRUST_SERVER_CERT.
|
||||
# Gitea applies GITEA__* env on every boot, so toggling app-email + redeploy takes effect. The From
|
||||
# is Gitea's single GITEA__mailer__FROM; USER/PASSWD stay unset (the shim accepts no-auth).
|
||||
smtp_mapping:
|
||||
host_var: GITEA__mailer__SMTP_ADDR
|
||||
port_var: GITEA__mailer__SMTP_PORT
|
||||
security_var: GITEA__mailer__PROTOCOL
|
||||
security_value: "smtp+starttls"
|
||||
from_var: GITEA__mailer__FROM
|
||||
from_local: gitea
|
||||
extra:
|
||||
GITEA__mailer__ENABLED: "true"
|
||||
GITEA__mailer__FORCE_TRUST_SERVER_CERT: "true"
|
||||
@@ -0,0 +1,61 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Glance"
|
||||
description: "Minimalista információs dashboard"
|
||||
category: "dashboard"
|
||||
subdomain: "dashboard"
|
||||
slug: "glance"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "20M"
|
||||
mem_limit: "128M"
|
||||
pi_compatible: true
|
||||
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: "dashboard"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Minimalista dashboard - RSS, időjárás, könyvjelzők egy oldalon"
|
||||
docs_url: "https://github.com/glanceapp/glance/blob/main/docs/configuration.md"
|
||||
|
||||
use_cases:
|
||||
- 'RSS hírek, YouTube, Reddit és egyéb tartalmak egy oldalon'
|
||||
- 'Időjárás és rendszer monitorozás widgetekkel'
|
||||
- 'Könyvjelzők és kedvenc oldalak rendszerezése'
|
||||
- 'Ultragyors, minimális erőforrás igény'
|
||||
- 'Személyre szabható elrendezés YAML konfigurációval'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a dashboard.DOMAIN címet a böngészőben'
|
||||
- 'Szerkeszd a glance.yml konfigurációs fájlt a kötetben'
|
||||
- 'Add hozzá az RSS feedeket, widgeteket'
|
||||
- 'Személyre szabd az elrendezést'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 8080
|
||||
@@ -0,0 +1,72 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Gokapi"
|
||||
description: "Ideiglenes fájlmegosztás lejáró linkekkel"
|
||||
category: "files"
|
||||
subdomain: "share"
|
||||
slug: "gokapi"
|
||||
# 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-07-18"
|
||||
# Gokapi's bare "/" redirects away (file-share index); the admin/login UI is at /admin.
|
||||
open_path: "/admin"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "30M"
|
||||
mem_limit: "128M"
|
||||
pi_compatible: true
|
||||
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: "share"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: GOKAPI_PASSWORD
|
||||
label: "Admin jelszó"
|
||||
type: password
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
description: "A Gokapi admin felhasználó (admin) jelszava — ezzel tudsz belépni a kezelőfelületre"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Ideiglenes fájlmegosztás lejáró linkekkel"
|
||||
docs_url: "https://gokapi.readthedocs.io/"
|
||||
default_creds: "Felhasználó: admin · A jelszó a Beállítások oldalon látható (telepítéskor generált kezdeti jelszó)"
|
||||
|
||||
use_cases:
|
||||
- 'Fájlok biztonságos megosztása lejáró linkekkel'
|
||||
- 'Beállítható lejárati idő és letöltési limit'
|
||||
- 'Jelszóvédett letöltési linkek'
|
||||
- 'API támogatás automatizált feltöltéshez'
|
||||
- 'Titkosított tárolás és E2E titkosítás opció'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a share.DOMAIN címet a böngészőben'
|
||||
- 'Lépj be: felhasználó "admin", a jelszó a Beállítások oldalon található'
|
||||
- 'Tölts fel egy fájlt és generálj megosztási linket'
|
||||
- 'Állíts be lejárati időt és letöltési limitet a linkhez'
|
||||
- 'Oszd meg a linket - automatikusan lejár a beállított idő után'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 53842
|
||||
@@ -0,0 +1,74 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Grafana"
|
||||
description: "Professzionális monitoring és vizualizációs platform"
|
||||
category: "dashboard"
|
||||
subdomain: "grafana"
|
||||
slug: "grafana"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "100M"
|
||||
mem_limit: "512M"
|
||||
pi_compatible: true
|
||||
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: "grafana"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: GF_SECURITY_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
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Vizualizációs platform - dashboardok, grafikonok, alertek"
|
||||
default_creds: "admin / (telepítéskor megadott jelszó)"
|
||||
docs_url: "https://grafana.com/docs/grafana/latest/"
|
||||
|
||||
use_cases:
|
||||
- 'Rendszer metrikák vizualizálása (CPU, RAM, hálózat, lemez)'
|
||||
- 'Egyedi dashboardok létrehozása különböző adatforrásokból'
|
||||
- 'Alertek és értesítések küszöbértékek alapján'
|
||||
- 'Prometheus, InfluxDB és sok más adatforrás támogatás'
|
||||
- 'Szép, megosztható dashboardok'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a grafana.DOMAIN címet a böngészőben'
|
||||
- 'Jelentkezz be az admin fiókkal'
|
||||
- 'Add hozzá az adatforrásokat (Connections > Data Sources)'
|
||||
- 'Importálj egy dashboard sablont vagy hozz létre sajátot'
|
||||
|
||||
prerequisites:
|
||||
- 'Adatforrás szükséges (pl. Prometheus - külön telepítendő)'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 3000
|
||||
path: "/api/health"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,67 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Gramps Web"
|
||||
description: "Családfa készítő és genealógiai szoftver"
|
||||
category: "home"
|
||||
subdomain: "family"
|
||||
slug: "gramps-web"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "384M"
|
||||
mem_limit: "1024M"
|
||||
pi_compatible: true
|
||||
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: "family"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: GRAMPSWEB_SECRET_KEY
|
||||
label: "Titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Családfa készítő - genealógiai adatbázis webes felületen"
|
||||
docs_url: "https://gramps-project.github.io/web/"
|
||||
|
||||
use_cases:
|
||||
- 'Családfa építése és vizualizálása'
|
||||
- 'Személyek, események, helyszínek és kapcsolatok rögzítése'
|
||||
- 'Fényképek és dokumentumok csatolása a családtagokhoz'
|
||||
- 'GEDCOM import és export kompatibilitás'
|
||||
- 'Családtagok közös hozzáférése a családfához'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a family.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre az admin fiókot'
|
||||
- 'Importálj egy meglévő GEDCOM fájlt, vagy kezdd az üres családfát'
|
||||
- 'Add hozzá az első családtagokat'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 5000
|
||||
@@ -0,0 +1,66 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Home Assistant"
|
||||
description: "Nyílt forráskódú okos otthon központ"
|
||||
category: "home"
|
||||
subdomain: "ha"
|
||||
slug: "home-assistant"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "256M"
|
||||
mem_limit: "1024M"
|
||||
pi_compatible: true
|
||||
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: "ha"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Okos otthon központ - automatizálás és vezérlés egy helyről"
|
||||
docs_url: "https://www.home-assistant.io/docs/"
|
||||
|
||||
use_cases:
|
||||
- 'Okos otthon eszközök központi kezelése (lámpa, termosztát, kamera)'
|
||||
- 'Automatizálások létrehozása (pl. mozgásérzékelőre lámpa be)'
|
||||
- '2000+ integráció (Zigbee, Z-Wave, Tuya, Shelly, stb.)'
|
||||
- 'Dashboard a család számára mobilon és tableten'
|
||||
- 'Energiafogyasztás monitorozás'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a ha.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre a tulajdonos fiókot az onboarding során'
|
||||
- 'Fedezd fel az automatikusan felfedezett eszközöket'
|
||||
- 'Telepíts integrációkat az okos otthon eszközeidhez'
|
||||
- 'Hozd létre az első automatizálást'
|
||||
|
||||
prerequisites:
|
||||
- 'Okos otthon eszközök (nem kötelező, de ajánlott a telepítés előtt)'
|
||||
- 'Zigbee/Z-Wave koordinátor USB eszközök átpasszolása nem támogatott Docker módban'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 8123
|
||||
path: "/api/"
|
||||
@@ -0,0 +1,78 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml — App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
# Place alongside docker-compose.yml in each stack directory:
|
||||
# /opt/docker/stacks/homebox/.felhom.yml
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Homebox"
|
||||
description: "Otthoni leltár és eszköznyilvántartás"
|
||||
category: "tools"
|
||||
subdomain: "inventory"
|
||||
|
||||
# --- Asset slug ---
|
||||
slug: "homebox"
|
||||
# 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-07-19"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "50M"
|
||||
mem_limit: "256M"
|
||||
pi_compatible: true
|
||||
needs_hdd: false
|
||||
|
||||
# --- Deploy fields ---
|
||||
deploy_fields:
|
||||
- env_var: DOMAIN
|
||||
label: "Domain"
|
||||
type: domain
|
||||
description: "A szerver domain neve"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: HBOX_AUTH_API_KEY_PEPPER
|
||||
label: "API-kulcs pepper"
|
||||
type: secret
|
||||
generate: "base64key:48"
|
||||
locked_after_deploy: true
|
||||
# A Homebox 0.26+ pánikol induláskor, ha ez nincs beállítva (min. 32 bájt).
|
||||
# Ez sózza az API-kulcsokat: ha újragenerálódik, MINDEN kiadott API-kulcs
|
||||
# érvénytelenné válik, ezért visszaállításkor a régi értéket kell megtartani.
|
||||
data_key: true
|
||||
|
||||
- env_var: SUBDOMAIN
|
||||
label: "Aldomain"
|
||||
type: subdomain
|
||||
default: "inventory"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: 'Otthoni leltár kezelő - tartsd számon a tárgyaidat'
|
||||
docs_url: 'https://homebox.software/en/'
|
||||
|
||||
use_cases:
|
||||
- 'Otthoni tárgyak leltározása és nyilvántartása'
|
||||
- 'Helyszínek, címkék és kategóriák szerinti rendszerezés'
|
||||
- 'Garancia lejáratok és beszerzési árak nyilvántartása'
|
||||
- 'Vonalkód szkennelés a gyors hozzáadáshoz'
|
||||
- 'Biztosítási célú leltár készítés'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg az inventory.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre a fiókodat az első megnyitáskor'
|
||||
- 'Add hozzá a helyszíneket (pl. nappali, konyha, garázs)'
|
||||
- 'Kezdd el felvenni a tárgyakat fotókkal'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 7745
|
||||
path: "/api/v1/status"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,61 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Homepage"
|
||||
description: "Személyre szabható kezdőlap szolgáltatás widgetekkel"
|
||||
category: "dashboard"
|
||||
subdomain: "home"
|
||||
slug: "homepage"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "50M"
|
||||
mem_limit: "256M"
|
||||
pi_compatible: true
|
||||
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: "home"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Személyes kezdőlap - szolgáltatás státuszok és widgetek egy helyen"
|
||||
docs_url: "https://gethomepage.dev/"
|
||||
|
||||
use_cases:
|
||||
- 'Összes szolgáltatás egy áttekinthető oldalon'
|
||||
- 'Szolgáltatás állapot monitoring widgetek'
|
||||
- 'Docker integráció - automatikus szolgáltatás felfedezés'
|
||||
- 'Könyvjelzők és kedvenc oldalak'
|
||||
- 'Időjárás, rendszer erőforrás és egyéb widgetek'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a home.DOMAIN címet a böngészőben'
|
||||
- 'Szerkeszd a konfigurációs fájlokat a homepage_config kötetben'
|
||||
- 'Add hozzá a szolgáltatásokat a services.yaml-ban'
|
||||
- 'Állítsd be a widgeteket a widgets.yaml-ban'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 3000
|
||||
@@ -0,0 +1,102 @@
|
||||
# =============================================================================
|
||||
# .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-07-18"
|
||||
|
||||
# --- 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:
|
||||
checks:
|
||||
- type: api
|
||||
port: 2283
|
||||
path: "/api/server/ping"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,83 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Jellyfin"
|
||||
description: "Ingyenes és nyílt forráskódú média szerver"
|
||||
category: "media"
|
||||
subdomain: "media"
|
||||
slug: "jellyfin"
|
||||
# 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-07-18"
|
||||
|
||||
# --- 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: "media"
|
||||
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, ahol a filmek, sorozatok és zenék tárolódnak"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Ingyenes média szerver - filmek, sorozatok és zene streamelése"
|
||||
docs_url: "https://jellyfin.org/docs/"
|
||||
|
||||
use_cases:
|
||||
- 'Filmek, sorozatok és zenék streamelése bármilyen eszközre'
|
||||
- 'Automatikus metaadat letöltés - borítók, leírások, értékelések'
|
||||
- 'Élő TV és DVR funkció TV tunerrel'
|
||||
- 'Több felhasználó külön profillal és szülői felügyelettel'
|
||||
- 'Mobil és TV alkalmazások (Android, iOS, Roku, Fire TV, stb.)'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a media.DOMAIN címet a böngészőben'
|
||||
- 'Kövesd a beállítás varázslót - válaszd a magyar nyelvet'
|
||||
- 'Hozd létre az admin fiókot'
|
||||
- 'Add hozzá a médiatárat (filmek: /media/movies, sorozatok: /media/shows)'
|
||||
- 'Telepítsd a Jellyfin alkalmazást a telefonodra vagy TV-dre'
|
||||
|
||||
prerequisites:
|
||||
- 'Külső HDD szükséges a médiafájlok tárolásához'
|
||||
- 'Legalább 2 GB szabad RAM ajánlott'
|
||||
- 'Filmek és sorozatok mappákba rendezve (pl. /media/movies/, /media/shows/)'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 8096
|
||||
path: "/health"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,80 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Kimai"
|
||||
description: "Időkövetés és projektmenedzsment"
|
||||
category: "productivity"
|
||||
subdomain: "time"
|
||||
slug: "kimai"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "100M"
|
||||
mem_limit: "384M"
|
||||
pi_compatible: true
|
||||
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: "time"
|
||||
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: ADMIN_EMAIL
|
||||
label: "Admin email"
|
||||
type: text
|
||||
default: "admin@example.com"
|
||||
|
||||
- env_var: 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
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Időkövetés - projektek, ügyfelek és munkaidő nyilvántartás"
|
||||
default_creds: "(telepítéskor megadott admin email és jelszó)"
|
||||
docs_url: "https://www.kimai.org/documentation/"
|
||||
|
||||
use_cases:
|
||||
- 'Munkaidő nyilvántartás projektekre és ügyfelekre bontva'
|
||||
- 'Stopper-szerű időmérés egy kattintással'
|
||||
- 'Riportok és exportálás (PDF, CSV, Excel)'
|
||||
- 'Költségek és számlázás nyilvántartás'
|
||||
- 'Több felhasználó csapat szintű jogosultságokkal'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a time.DOMAIN címet a böngészőben'
|
||||
- 'Jelentkezz be a telepítéskor megadott admin adatokkal'
|
||||
- 'Hozd létre az első ügyfelet és projektet'
|
||||
- 'Indítsd el az időmérést'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 8001
|
||||
@@ -0,0 +1,83 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Komga"
|
||||
description: "Képregény és manga szerver OPDS támogatással"
|
||||
category: "media"
|
||||
subdomain: "comics"
|
||||
slug: "komga"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "200M"
|
||||
mem_limit: "512M"
|
||||
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/comics
|
||||
class: optional # ruled: precious-decoupled (re-scanned, hand-curated)
|
||||
|
||||
# --- 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: "comics"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: HDD_PATH
|
||||
label: "Képregénytá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: "Képregény, manga és könyv szerver webes olvasóval"
|
||||
docs_url: "https://komga.org/docs/"
|
||||
|
||||
use_cases:
|
||||
- 'Képregények és mangák rendszerezése és olvasása böngészőben'
|
||||
- 'Automatikus metaadat szkennelés és borítókép generálás'
|
||||
- 'OPDS feed kompatibilis olvasó alkalmazásokhoz'
|
||||
- 'Olvasási haladás szinkronizálás eszközök között'
|
||||
- 'Több felhasználó külön könyvtárral'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a comics.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre az admin fiókot az első megnyitáskor'
|
||||
- 'Add hozzá a könyvtárat (/data)'
|
||||
- 'Várd meg az automatikus szkennelést'
|
||||
- 'Használj OPDS-kompatibilis alkalmazást mobilon (pl. Tachiyomi)'
|
||||
|
||||
prerequisites:
|
||||
- 'Külső HDD szükséges a képregények tárolásához'
|
||||
- 'Támogatott formátumok: CBZ, CBR, PDF, EPUB'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 25600
|
||||
# /actuator/health is unauthenticated (200); the /api/v1 prefix is auth-gated (401).
|
||||
path: "/actuator/health"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,82 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml — App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
# Place alongside docker-compose.yml in each stack directory:
|
||||
# /opt/docker/stacks/mealie/.felhom.yml
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Mealie"
|
||||
description: "Receptkezelő és étkezéstervező"
|
||||
category: "productivity"
|
||||
subdomain: "recipes"
|
||||
|
||||
# --- Asset slug ---
|
||||
slug: "mealie"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "200M"
|
||||
mem_limit: "1000M"
|
||||
pi_compatible: true
|
||||
needs_hdd: false
|
||||
|
||||
# --- 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: "recipes"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: 'Receptkezelő és étkezés tervező a családnak'
|
||||
default_creds: 'changeme@example.com / MyPassword'
|
||||
docs_url: 'https://docs.mealie.io/'
|
||||
|
||||
use_cases:
|
||||
- 'Receptek gyűjtése és rendszerezése kategóriák és címkék szerint'
|
||||
- 'Receptek importálása weboldalakról automatikusan'
|
||||
- 'Heti étkezés tervezés és bevásárlólista generálás'
|
||||
- 'Receptek megosztása családtagokkal és barátokkal'
|
||||
- 'Többnyelvű felület - magyar is elérhető'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a mealie.DOMAIN címet a böngészőben'
|
||||
- 'Jelentkezz be: changeme@example.com / MyPassword'
|
||||
- 'Változtasd meg azonnal az email címet és jelszót'
|
||||
- 'Importáld az első receptet egy weboldal URL beillesztésével'
|
||||
- 'Próbáld ki az étkezés tervezőt'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: tcp
|
||||
port: 9000
|
||||
|
||||
# --- App-email mapping (apps → in-controller shim → hub → Resend) ---
|
||||
# When app-email is on (global toggle + this app's per-app toggle), the controller injects
|
||||
# host = the on-box shim, port = 2525, From = mealie@felhom.eu. Mealie has NO accept-invalid-
|
||||
# cert option, so it talks PLAINTEXT (SMTP_AUTH_STRATEGY=NONE) to the shim on 2525 — the
|
||||
# spike-validated mode (SPIKE-smtp-app-relay-2026-06-28 §7). SMTP_USER/SMTP_PASSWORD stay
|
||||
# unset (no auth needed; the shim holds no Resend key).
|
||||
smtp_mapping:
|
||||
host_var: SMTP_HOST
|
||||
port_var: SMTP_PORT
|
||||
security_var: SMTP_AUTH_STRATEGY
|
||||
security_value: "NONE"
|
||||
from_var: SMTP_FROM_EMAIL
|
||||
from_name_var: SMTP_FROM_NAME
|
||||
from_local: mealie
|
||||
@@ -0,0 +1,72 @@
|
||||
# =============================================================================
|
||||
# .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-07-18"
|
||||
|
||||
# --- 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
|
||||
@@ -0,0 +1,82 @@
|
||||
# =============================================================================
|
||||
# .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-07-18"
|
||||
|
||||
# --- 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
|
||||
@@ -0,0 +1,125 @@
|
||||
# =============================================================================
|
||||
# .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-07-18"
|
||||
|
||||
# --- 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
|
||||
@@ -0,0 +1,84 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "OnlyOffice"
|
||||
description: "Teljes értékű irodai csomag a böngészőben"
|
||||
category: "productivity"
|
||||
subdomain: "office"
|
||||
slug: "onlyoffice"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "512M"
|
||||
mem_limit: "2048M"
|
||||
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: "office"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: JWT_SECRET
|
||||
label: "JWT titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Teljes értékű irodai csomag - Word, Excel, PowerPoint a böngészőben"
|
||||
docs_url: "https://helpcenter.onlyoffice.com/"
|
||||
|
||||
use_cases:
|
||||
- 'Dokumentumok, táblázatok és prezentációk szerkesztése böngészőben'
|
||||
- 'Valós idejű közös szerkesztés több felhasználóval'
|
||||
- 'Microsoft Office formátumok teljes kompatibilitása (docx, xlsx, pptx)'
|
||||
- 'Nextcloud és egyéb felhő tárhely integrációk'
|
||||
- 'PDF konvertálás és kitöltés'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg az office.DOMAIN címet a böngészőben'
|
||||
- 'Várj amíg az inicializálás befejeződik (1-2 perc)'
|
||||
- 'A Document Server önmagában API-ként működik'
|
||||
- 'Integráld Nextcloud-dal vagy más alkalmazással a JWT tokennel'
|
||||
- 'Nextcloudban: telepítsd az OnlyOffice alkalmazást és add meg az URL-t'
|
||||
|
||||
prerequisites:
|
||||
- 'Legalább 2 GB szabad RAM szükséges'
|
||||
- 'x86 processzor szükséges (nem fut Raspberry Pi-n)'
|
||||
- 'Nextcloud vagy más kompatibilis alkalmazás ajánlott az integrációhoz'
|
||||
|
||||
# --- App-to-app integrations ---
|
||||
integrations:
|
||||
- target: filebrowser
|
||||
label: "FileBrowser integráció"
|
||||
description: "Dokumentumok szerkesztése a fájlkezelőben"
|
||||
- target: nextcloud
|
||||
label: "Nextcloud integráció"
|
||||
description: "Dokumentumok szerkesztése a Nextcloudban"
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 80
|
||||
path: "/healthcheck"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,64 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "OpenGist"
|
||||
description: "Kód snippetek megosztása (GitHub Gist alternatíva)"
|
||||
category: "dev"
|
||||
subdomain: "gist"
|
||||
slug: "opengist"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "30M"
|
||||
mem_limit: "128M"
|
||||
pi_compatible: true
|
||||
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: "gist"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Kód snippetek megosztása - privát GitHub Gist alternatíva"
|
||||
docs_url: "https://github.com/thomiceli/opengist"
|
||||
|
||||
use_cases:
|
||||
- 'Kód snippetek és szövegek megosztása'
|
||||
- 'Szintaxis kiemelés sok programozási nyelvhez'
|
||||
- 'Privát és nyilvános gistek'
|
||||
- 'Git-alapú tárolás - verziókezelés automatikusan'
|
||||
- 'Markdown támogatás és beágyazás'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a gist.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre a fiókodat (az első felhasználó admin lesz)'
|
||||
- 'Hozd létre az első gistet - írd be a kódot és mentsd'
|
||||
- 'Oszd meg a linket'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 6157
|
||||
path: "/healthcheck"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,86 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Outline"
|
||||
description: "Modern csapat tudásbázis Markdown támogatással"
|
||||
category: "productivity"
|
||||
subdomain: "kb"
|
||||
slug: "outline"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "200M"
|
||||
mem_limit: "768M"
|
||||
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: "kb"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: SECRET_KEY
|
||||
label: "Titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: UTILS_SECRET
|
||||
label: "Segédprogram kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: DB_PASSWORD
|
||||
label: "Adatbázis jelszó"
|
||||
type: secret
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Modern tudásbázis - Markdown, valós idejű együttműködés, keresés"
|
||||
docs_url: "https://docs.getoutline.com/"
|
||||
|
||||
use_cases:
|
||||
- 'Csapat tudásbázis és dokumentáció'
|
||||
- 'Markdown szerkesztő valós idejű együttműködéssel'
|
||||
- 'Strukturált dokumentumok fa-szerkezetben'
|
||||
- 'Teljes szöveges keresés és hivatkozások'
|
||||
- 'API és integrációk (Slack, webhookok)'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a kb.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre az első felhasználót'
|
||||
- 'Hozz létre egy gyűjteményt (Collection) a dokumentumoknak'
|
||||
- 'Kezdj el írni Markdown-ban'
|
||||
- 'Hívd meg a csapattagokat'
|
||||
|
||||
prerequisites:
|
||||
- 'x86 processzor szükséges'
|
||||
- 'Legalább 1 GB szabad RAM (Outline + PostgreSQL + Redis)'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 3000
|
||||
path: "/_health"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,167 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml — App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
# Place alongside docker-compose.yml in each stack directory:
|
||||
# /opt/docker/stacks/paperless-ngx/.felhom.yml
|
||||
#
|
||||
# This file defines:
|
||||
# 1. Display info (name, description, icon)
|
||||
# 2. Deploy fields (what the user fills in during first deployment)
|
||||
# 3. Asset references (logos, screenshots loaded from felhom.eu)
|
||||
# 4. Resource hints (RAM, Pi compatibility)
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Paperless-ngx"
|
||||
description: "Dokumentumok digitalizálása és rendszerezése"
|
||||
category: "productivity" # productivity, media, finance, security, tools
|
||||
subdomain: "paperless" # -> paperless.<domain>
|
||||
|
||||
# --- Asset slug ---
|
||||
# Used to construct URLs for logo and screenshots from felhom.eu:
|
||||
# Logo: {assets.base_url}/assets/{slug}-logo.webp
|
||||
# Screenshot: {assets.base_url}/assets/{slug}-screenshot-{n}.webp
|
||||
# App page: {assets.base_url}/alkalmazasok#{slug}
|
||||
# Falls back to directory name if not set.
|
||||
slug: "paperless-ngx"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "500M" # Expected memory usage (display hint)
|
||||
mem_limit: "1664M" # Total enforced limit across all containers (1280+256+128) — R-514
|
||||
pi_compatible: true # Runs on Raspberry Pi 3B+
|
||||
needs_hdd: true # Needs external storage for user data
|
||||
|
||||
# --- Backup classification (referential coupling; see felhom.eu documentation/audits/SPIKE-backup-classification-2026-07-14.md) ---
|
||||
backup:
|
||||
hdd:
|
||||
- path: appdata/paperless/media
|
||||
class: mandatory # document originals+archive — DB hashes/paths reference them
|
||||
- path: appdata/paperless/export
|
||||
class: excluded # transient export target
|
||||
import:
|
||||
- path: paperless
|
||||
class: excluded # consume inbox — deleted after ingest by contract
|
||||
|
||||
# --- Customer-facing folder annotation (R-75) ---
|
||||
# ANNOTATES paths that already exist as compose binds above; never declares a new one.
|
||||
# role: import | library | export (unknown role → that entry is simply not shown)
|
||||
data_paths:
|
||||
- path: paperless
|
||||
root: import
|
||||
role: import
|
||||
label: "Beolvasandó dokumentumok"
|
||||
|
||||
# --- Deploy fields ---
|
||||
# Shown to the user during first deployment.
|
||||
# After deployment, values are saved to app.yaml in the stack directory.
|
||||
#
|
||||
# Field types:
|
||||
# domain - Auto-filled from controller config, read-only
|
||||
# secret - Auto-generated, hidden (user sees "Generated ✓")
|
||||
# password - Auto-generated but shown, user can override
|
||||
# path - Filesystem path (validated for existence)
|
||||
# text - Free text input
|
||||
# select - Dropdown with predefined options
|
||||
# boolean - Toggle switch
|
||||
#
|
||||
# Generator types (for secret/password):
|
||||
# password:N - N chars alphanumeric
|
||||
# hex:N - N bytes hex-encoded
|
||||
# static:VAL - Fixed value
|
||||
|
||||
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: "paperless"
|
||||
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: PAPERLESS_SECRET_KEY
|
||||
label: "Titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: PAPERLESS_ADMIN_USER
|
||||
label: "Admin felhasználónév"
|
||||
type: text
|
||||
default: "admin"
|
||||
locked_after_deploy: false
|
||||
|
||||
- env_var: PAPERLESS_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, ahol a dokumentumok tárolódnak"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: PAPERLESS_OCR_LANGUAGE
|
||||
label: "OCR nyelv"
|
||||
type: select
|
||||
default: "hun+eng"
|
||||
options:
|
||||
- value: "hun"
|
||||
label: "Magyar"
|
||||
- value: "eng"
|
||||
label: "Angol"
|
||||
- value: "hun+eng"
|
||||
label: "Magyar + Angol"
|
||||
- value: "deu+eng"
|
||||
label: "Német + Angol"
|
||||
description: "Dokumentum felismerés nyelve"
|
||||
locked_after_deploy: false
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: 'Digitális irattár - szkennelés, OCR és automatikus rendszerezés'
|
||||
docs_url: 'https://docs.paperless-ngx.com/'
|
||||
|
||||
use_cases:
|
||||
- 'Papír dokumentumok digitalizálása és rendszerezése'
|
||||
- 'Automatikus OCR szövegfelismerés szkennelt dokumentumokon'
|
||||
- 'Intelligens automatikus kategorizálás és címkézés'
|
||||
- 'Teljes szöveges keresés az összes dokumentumban'
|
||||
- 'Email-ből érkező dokumentumok automatikus feldolgozása'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a paperless.DOMAIN címet a böngészőben'
|
||||
- 'Lépj be: felhasználó "admin", a jelszó a Beállítások oldalon található (Automatikusan generált értékek)'
|
||||
- 'Tölts fel egy dokumentumot a webfelületen, VAGY dobd a Fájlkezelőben (FileBrowser) az import/paperless mappába — onnan automatikusan beolvassa és OCR-rel feldolgozza. A Fájlkezelő belépése a Fájlkezelő alkalmazás oldalán található'
|
||||
- 'Sok dokumentumot egyszerre is feltölthetsz: egyenként dolgozza fel őket, egy nagyobb köteg néhány percig tart'
|
||||
- 'Hozz létre címkéket és levelezőket az automatikus rendszerezéshez'
|
||||
|
||||
prerequisites:
|
||||
- 'Külső HDD ajánlott a dokumentumok tárolásához'
|
||||
- 'Legalább 1 GB szabad RAM (OCR feldolgozáshoz)'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 8000
|
||||
@@ -0,0 +1,70 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Papra"
|
||||
description: "Minimalista dokumentumtár és rendszerező"
|
||||
category: "productivity"
|
||||
subdomain: "papra"
|
||||
slug: "papra"
|
||||
# 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-07-12"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "50M"
|
||||
mem_limit: "256M"
|
||||
pi_compatible: true
|
||||
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: "papra"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: AUTH_SECRET
|
||||
label: "Munkamenet-aláíró kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
# A Papra éles módban ELUTASÍTJA az indulást, ha ez az alapértelmezett érték
|
||||
# marad ("the auth secret must not be the default one"), ezért kötelező.
|
||||
# Ez írja alá a munkameneteket: ha újragenerálódik, minden bejelentkezés
|
||||
# érvénytelenné válik, ezért visszaállításkor a régi kulcsot kell megtartani.
|
||||
data_key: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Minimalista dokumentumtár - egyszerű rendszerezés és keresés"
|
||||
docs_url: "https://docs.papra.app/"
|
||||
|
||||
use_cases:
|
||||
- 'Dokumentumok egyszerű feltöltése és rendszerezése'
|
||||
- 'Gyors keresés a dokumentumok között'
|
||||
- 'Minimalista felület felesleges funkciók nélkül'
|
||||
- 'Könnyű alternatíva a Paperless-ngx-hez'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a papra.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre a fiókodat'
|
||||
- 'Töltsd fel az első dokumentumot'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 1221
|
||||
@@ -0,0 +1,83 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Plant-it"
|
||||
description: "Növénynapló és gondozás emlékeztető"
|
||||
category: "home"
|
||||
subdomain: "plants"
|
||||
slug: "plant-it"
|
||||
# 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-07-21"
|
||||
|
||||
# --- Lifecycle ---
|
||||
# abandoned: upstream stopped developing the self-hosted edition. NOT offered for new installs;
|
||||
# anyone already running it keeps running it, with a permanent notice that no updates or security
|
||||
# fixes will arrive. Evidence (2026-07-21): the `backend/` and `deployment/` directories are DELETED
|
||||
# from upstream `main` (the project is now an Android app on F-Droid/Obtainium); the last server
|
||||
# image `msdeluise/plant-it-server:0.10.0` was pushed 2024-12-10 and is a security-frozen Spring
|
||||
# Boot 3.4.0; and it requires MySQL 8.0 + Redis, which this template never had.
|
||||
#
|
||||
# The compose below is deliberately LEFT AS-IS (it pins `msdeluise/plant-it:0.10.0`, a repository
|
||||
# that does not exist — the real one is `-server`). It is not worth fixing: the app is not
|
||||
# installable, and rewriting it would imply it is.
|
||||
lifecycle: abandoned
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "50M"
|
||||
mem_limit: "256M"
|
||||
pi_compatible: true
|
||||
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: "plants"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: JWT_SECRET
|
||||
label: "JWT titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Növénynapló - emlékeztetők öntözésre, trágyázásra és fotónapló"
|
||||
docs_url: "https://docs.plant-it.org/"
|
||||
|
||||
use_cases:
|
||||
- 'Szobanövények és kerti növények nyilvántartása'
|
||||
- 'Emlékeztetők öntözésre, trágyázásra, átültetésre'
|
||||
- 'Fotónapló a növények fejlődéséről'
|
||||
- 'Statisztikák és gondozási előzmények'
|
||||
- 'Több felhasználó - a család együtt gondozhat'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a plants.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre a fiókodat'
|
||||
- 'Add hozzá az első növényt fotóval'
|
||||
- 'Állíts be gondozási emlékeztetőket'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 8080
|
||||
path: "/api/info"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,91 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Plex"
|
||||
description: "Népszerű média szerver csiszolt felülettel"
|
||||
category: "media"
|
||||
subdomain: "plex"
|
||||
slug: "plex"
|
||||
# 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-02-15"
|
||||
|
||||
# --- 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: "plex"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: PLEX_CLAIM
|
||||
label: "Plex Claim Token"
|
||||
type: text
|
||||
required: true
|
||||
placeholder: "claim-xxxxxxxxxxxx"
|
||||
description: "Generáld a https://plex.tv/claim oldalon (4 percig érvényes)"
|
||||
locked_after_deploy: true
|
||||
|
||||
- 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: "Prémium média szerver kiváló alkalmazás támogatással"
|
||||
docs_url: "https://support.plex.tv/"
|
||||
|
||||
use_cases:
|
||||
- 'Filmek, sorozatok és zene streamelése professzionális felületen'
|
||||
- 'Automatikus transzkódolás bármilyen eszközhöz'
|
||||
- 'Watch Together - közös filmnézés távolról'
|
||||
- 'Intro/outro skip funkció (Plex Pass)'
|
||||
- 'Gazdag mobilalkalmazás és Smart TV támogatás'
|
||||
|
||||
first_steps:
|
||||
- 'Generálj egy claim tokent a https://plex.tv/claim oldalon'
|
||||
- 'Telepítés után nyisd meg a plex.DOMAIN címet'
|
||||
- 'Kapcsold össze a Plex fiókoddat a szerverrel'
|
||||
- 'Add hozzá a médiatárat (filmek: /media/movies, sorozatok: /media/shows)'
|
||||
- 'Telepítsd a Plex alkalmazást eszközeidre'
|
||||
|
||||
prerequisites:
|
||||
- 'Plex fiók szükséges (ingyenes regisztráció a plex.tv-n)'
|
||||
- 'Külső HDD a médiafájlok tárolásához'
|
||||
- 'Legalább 2 GB szabad RAM (transzkódoláshoz több ajánlott)'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 32400
|
||||
path: "/identity"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,60 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "PrivateBin"
|
||||
description: "Titkosított jegyzet és szöveg megosztás"
|
||||
category: "security"
|
||||
subdomain: "paste"
|
||||
slug: "privatebin"
|
||||
# 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-14"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "30M"
|
||||
mem_limit: "128M"
|
||||
pi_compatible: true
|
||||
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: "paste"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Titkosított szöveg megosztás - a szerver nem látja a tartalmat"
|
||||
docs_url: "https://github.com/PrivateBin/PrivateBin/wiki"
|
||||
|
||||
use_cases:
|
||||
- 'Érzékeny szövegek biztonságos megosztása'
|
||||
- 'E2E titkosítás - a szerver nem fér hozzá a tartalomhoz'
|
||||
- 'Beállítható lejárati idő (5 perc - 1 év, vagy soha)'
|
||||
- 'Olvasás után automatikus törlés opció'
|
||||
- 'Jelszóvédelem a még nagyobb biztonságért'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a paste.DOMAIN címet a böngészőben'
|
||||
- 'Írd be a szöveget és kattints a Küldés gombra'
|
||||
- 'Oszd meg a generált linket - a titkosítási kulcs az URL-ben van'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 8080
|
||||
@@ -0,0 +1,85 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Radarr"
|
||||
description: "Automatikus film letöltő és rendszerező"
|
||||
category: "media-automation"
|
||||
subdomain: "radarr"
|
||||
slug: "radarr"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "150M"
|
||||
mem_limit: "512M"
|
||||
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/movies
|
||||
class: excluded # re-downloadable by design
|
||||
- path: downloads
|
||||
class: excluded # ruled: transient queue (cross-app shared with sonarr)
|
||||
|
||||
# --- 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: "radarr"
|
||||
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: "Automatikus film letöltő és rendszerező"
|
||||
docs_url: "https://wiki.servarr.com/radarr"
|
||||
|
||||
use_cases:
|
||||
- 'Filmek automatikus letöltése és rendszerezése'
|
||||
- 'Kívánságlista - filmek automatikusan a könyvtáradba kerülnek'
|
||||
- 'Minőség kezelés és automatikus frissítés jobb minőségre'
|
||||
- 'Integráció Jellyfin/Plex és letöltő kliensekkel'
|
||||
- 'Metaadat és borítókép automatikus letöltés'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a radarr.DOMAIN címet a böngészőben'
|
||||
- 'Állíts be egy letöltő klienst (pl. qBittorrent)'
|
||||
- 'Add hozzá az indexereket (vagy használj Prowlarr-t)'
|
||||
- 'Állítsd be a gyökérmappát (/media/movies)'
|
||||
- 'Keress rá egy filmre és add hozzá a listádhoz'
|
||||
|
||||
prerequisites:
|
||||
- 'Külső HDD szükséges a médiafájlok tárolásához'
|
||||
- 'Letöltő kliens szükséges (pl. qBittorrent - külön telepítendő)'
|
||||
- 'Indexer hozzáférés szükséges a kereséshez'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 7878
|
||||
path: "/ping"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,88 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Rallly"
|
||||
description: "Időpont szavazás (Doodle alternatíva)"
|
||||
category: "productivity"
|
||||
subdomain: "poll"
|
||||
slug: "rallly"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "384M"
|
||||
mem_limit: "1024M"
|
||||
pi_compatible: true
|
||||
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: "poll"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: SECRET_PASSWORD
|
||||
label: "Titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: DB_PASSWORD
|
||||
label: "Adatbázis jelszó"
|
||||
type: secret
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Időpont szavazás - Doodle alternatíva a saját szerveren"
|
||||
docs_url: "https://support.rallly.co/"
|
||||
|
||||
use_cases:
|
||||
- 'Közös időpont egyeztetés szavazással'
|
||||
- 'Találkozók, események szervezése'
|
||||
- 'Résztvevők regisztráció nélkül szavazhatnak'
|
||||
- 'Email értesítések és emlékeztetők'
|
||||
- 'Egyszerű, tiszta felület'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a poll.DOMAIN címet a böngészőben'
|
||||
- 'Hozz létre egy új szavazást'
|
||||
- 'Add meg a lehetséges időpontokat'
|
||||
- 'Oszd meg a linket a résztvevőkkel'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 3000
|
||||
|
||||
# --- App-email mapping (apps → in-controller shim → hub → Resend) ---
|
||||
# Rallly (Nodemailer) uses STARTTLS to the shim (SMTP_SECURE=false) and accepts the shim's self-signed
|
||||
# cert (SMTP_REJECT_UNAUTHORIZED=false on v4; v3.x accepts by default). From = Rallly's single
|
||||
# NOREPLY_EMAIL; SMTP_USER/SMTP_PWD stay unset (the shim accepts no-auth).
|
||||
smtp_mapping:
|
||||
host_var: SMTP_HOST
|
||||
port_var: SMTP_PORT
|
||||
security_var: SMTP_SECURE
|
||||
security_value: "false"
|
||||
from_var: NOREPLY_EMAIL
|
||||
from_name_var: NOREPLY_EMAIL_NAME
|
||||
from_local: rallly
|
||||
extra:
|
||||
SMTP_REJECT_UNAUTHORIZED: "false"
|
||||
@@ -0,0 +1,79 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml — App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
# Place alongside docker-compose.yml in each stack directory:
|
||||
# /opt/docker/stacks/recipe-importer/.felhom.yml
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Recipe Importer"
|
||||
description: "Magyar receptoldalak importálása Mealie-be és Tandoor-ba"
|
||||
category: "tools"
|
||||
subdomain: "rimport"
|
||||
|
||||
# --- Asset slug ---
|
||||
slug: "recipe-importer"
|
||||
# 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-07-12"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "30M"
|
||||
mem_limit: "128M"
|
||||
pi_compatible: true
|
||||
needs_hdd: false
|
||||
|
||||
# --- 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: "rimport"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: SECRET_KEY
|
||||
label: "Titkos kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
description: "Flask munkamenet titkos kulcs (automatikusan generált)"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: 'Magyar receptoldalak importálása egyszerűen — egyedi és tömeges import Mealie-be és Tandoor-ba'
|
||||
docs_url: 'https://gitea.dooplex.hu/admin/recipe-importer'
|
||||
|
||||
use_cases:
|
||||
- 'Receptek importálása 6 magyar oldalról: mindmegette.hu, streetkitchen.hu, nosalty.hu, sobors.hu, kiskegyed.hu és gastrohobbi.hu — hozzávalók, lépések, képek és címkék automatikus felismerése'
|
||||
- 'Tömeges importálás: több URL beillesztése egyszerre, recept-áttekintéssel vagy teljesen automatikus módban'
|
||||
- 'Importálás előtti szerkesztés — strukturált hozzávalók (mennyiség, mértékegység, étel, megjegyzés), lépések módosítása, címkék kezelése'
|
||||
- 'Mealie és Tandoor Recipes egyidejű támogatás — választhatsz célrendszert, vagy mindkettőbe importálhatsz egyszerre'
|
||||
- 'Ismeretlen oldalak esetén schema.org JSON-LD alapú automatikus feldolgozás (recipeIngredient, recipeInstructions, keywords)'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a rimport.DOMAIN címet a böngészőben'
|
||||
- 'Menj a Beállítások oldalra és add meg a Mealie és/vagy Tandoor URL-t és API kulcsot (Mealie: Profil → API Tokens; Tandoor: Beállítások → API Browser → Auth Token)'
|
||||
- 'Állíts be felhasználónevet és jelszót a hozzáférés védelméhez'
|
||||
- 'Illeszd be egy recept URL-jét az importálás oldalon, kattints a Feldolgozás gombra, majd ellenőrzés után az Importálás gombra'
|
||||
|
||||
prerequisites:
|
||||
- 'Mealie és/vagy Tandoor Recipes telepítve és elérhető a hálózaton'
|
||||
- 'API kulcs a célalkalmazásban (Mealie és/vagy Tandoor) létrehozva'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 8000
|
||||
path: "/health"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,149 @@
|
||||
# =============================================================================
|
||||
# .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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "300M"
|
||||
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:
|
||||
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
|
||||
@@ -0,0 +1,68 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Jellyseerr"
|
||||
description: "Média igénylés kezelő Jellyfin/Plex integrációval"
|
||||
category: "media-automation"
|
||||
subdomain: "requests"
|
||||
slug: "seerr"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "100M"
|
||||
mem_limit: "384M"
|
||||
pi_compatible: true
|
||||
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: "requests"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Film és sorozat igénylő a háztartás tagjai számára"
|
||||
docs_url: "https://docs.overseerr.dev/"
|
||||
|
||||
use_cases:
|
||||
- 'Családtagok filmeket és sorozatokat igényelhetnek egyszerűen'
|
||||
- 'Automatikus letöltés Sonarr/Radarr integrációval'
|
||||
- 'Elérhető tartalmak böngészése szép felületen'
|
||||
- 'Igénylések állapotának követése'
|
||||
- 'Felhasználói kvóták és jogosultságok kezelése'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a requests.DOMAIN címet a böngészőben'
|
||||
- 'Kövesd a beállítás varázslót'
|
||||
- 'Csatlakoztasd a Jellyfin vagy Plex szerveredet'
|
||||
- 'Csatlakoztasd a Sonarr és Radarr példányokat'
|
||||
- 'Hívd meg a családtagokat'
|
||||
|
||||
prerequisites:
|
||||
- 'Jellyfin vagy Plex szerver szükséges'
|
||||
- 'Sonarr és/vagy Radarr szükséges az automatikus letöltéshez'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 5055
|
||||
path: "/api/v1/status"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,85 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Sonarr"
|
||||
description: "Automatikus sorozat letöltő és rendszerező"
|
||||
category: "media-automation"
|
||||
subdomain: "sonarr"
|
||||
slug: "sonarr"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "150M"
|
||||
mem_limit: "512M"
|
||||
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/tv
|
||||
class: excluded
|
||||
- path: downloads
|
||||
class: excluded
|
||||
|
||||
# --- 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: "sonarr"
|
||||
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: "Automatikus sorozat letöltő és rendszerező"
|
||||
docs_url: "https://wiki.servarr.com/sonarr"
|
||||
|
||||
use_cases:
|
||||
- 'Sorozatok automatikus letöltése és rendszerezése'
|
||||
- 'Kívánságlista kezelés - új epizódok automatikus letöltése'
|
||||
- 'Minőség kezelés (480p-tól 4K-ig, automatikus frissítés)'
|
||||
- 'Integráció Jellyfin/Plex és letöltő kliensekkel'
|
||||
- 'Felirat automatikus letöltés'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a sonarr.DOMAIN címet a böngészőben'
|
||||
- 'Állíts be egy letöltő klienst (pl. qBittorrent)'
|
||||
- 'Add hozzá az indexereket (vagy használj Prowlarr-t)'
|
||||
- 'Állítsd be a gyökérmappát (/media/shows)'
|
||||
- 'Keress rá egy sorozatra és add hozzá a listádhoz'
|
||||
|
||||
prerequisites:
|
||||
- 'Külső HDD szükséges a médiafájlok tárolásához'
|
||||
- 'Letöltő kliens szükséges (pl. qBittorrent - külön telepítendő)'
|
||||
- 'Indexer hozzáférés szükséges a kereséshez'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 8989
|
||||
path: "/ping"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,91 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
display_name: "SparkyFitness"
|
||||
description: "Táplálkozás- és edzéskövető"
|
||||
category: "home"
|
||||
subdomain: "sparky"
|
||||
slug: "sparkyfitness"
|
||||
# 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-07-18"
|
||||
|
||||
resources:
|
||||
mem_request: "400M"
|
||||
# Sum of compose limits: db 512M + server 1024M + frontend 256M = 1792M
|
||||
mem_limit: "1792M"
|
||||
pi_compatible: false
|
||||
needs_hdd: false
|
||||
|
||||
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: "sparky"
|
||||
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: APP_DB_PASSWORD
|
||||
label: "Alkalmazás adatbázis jelszó"
|
||||
type: secret
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: API_ENCRYPTION_KEY
|
||||
label: "Adattitkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
# Encrypts stored data (e.g. external-integration credentials). Must NEVER be
|
||||
# regenerated after first boot — that would make existing encrypted data
|
||||
# unrecoverable. At restore the controller RECOVERS (never regenerates) it.
|
||||
data_key: true
|
||||
|
||||
- env_var: BETTER_AUTH_SECRET
|
||||
label: "Munkamenet aláíró kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
# Signs sessions and encrypts 2FA/TOTP secrets. Must NEVER change after first
|
||||
# boot — changing it locks out any user who enabled two-factor auth.
|
||||
data_key: true
|
||||
|
||||
app_info:
|
||||
tagline: "Táplálkozási napló, kalóriaszámláló és edzéskövető – önállóan üzemeltetve"
|
||||
docs_url: "https://github.com/CodeWithCJ/SparkyFitness"
|
||||
|
||||
use_cases:
|
||||
- 'Napi étkezések és kalóriabevitel naplózása'
|
||||
- 'Testsúly és testméretek követése grafikonokkal'
|
||||
- 'Edzések és mozgás rögzítése'
|
||||
- 'Tápanyag-célok (fehérje, szénhidrát, zsír) beállítása és követése'
|
||||
- 'Haladás áttekintése idővonalon és statisztikákon'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a sparky.DOMAIN címet a böngészőben'
|
||||
- 'Regisztrálj egy fiókot e-mail címmel és jelszóval'
|
||||
- 'Állítsd be a profilodat és a napi céljaidat'
|
||||
- 'Kezdd el naplózni az étkezéseidet és edzéseidet'
|
||||
|
||||
prerequisites:
|
||||
- 'Az első indításkor a szerver lefuttatja az adatbázis-migrációkat – ez akár 1-2 percig is eltarthat, mire az alkalmazás elérhetővé válik'
|
||||
|
||||
# --- Controller-side health probe (same form as wger) ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 80
|
||||
@@ -0,0 +1,75 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Tandoor Recipes"
|
||||
description: "Receptkezelő és étkezés tervező"
|
||||
category: "home"
|
||||
subdomain: "recipes"
|
||||
slug: "tandoor"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "512M"
|
||||
mem_limit: "1280M"
|
||||
pi_compatible: true
|
||||
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: "recipes"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: SECRET_KEY
|
||||
label: "Titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: DB_PASSWORD
|
||||
label: "Adatbázis jelszó"
|
||||
type: secret
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Receptkezelő és étkezés tervező a családnak"
|
||||
docs_url: "https://docs.tandoor.dev/"
|
||||
|
||||
use_cases:
|
||||
- 'Receptek gyűjtése és rendszerezése egy helyen'
|
||||
- 'Receptek importálása weboldalakról egy kattintással'
|
||||
- 'Heti étkezés tervezés és bevásárlólista generálás'
|
||||
- 'Több felhasználó - a család együtt tervezhet'
|
||||
- 'Receptek megosztása linkkel családtagokkal, barátokkal'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a recipes.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre az admin fiókot'
|
||||
- 'Importáld az első receptet egy weboldalról (Bookmarklet)'
|
||||
- 'Próbáld ki az étkezés tervezőt'
|
||||
- 'Hívd meg a családtagokat'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 8080
|
||||
path: "/accounts/login/"
|
||||
@@ -0,0 +1,57 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Termix"
|
||||
description: "Webes SSH és szerver menedzser"
|
||||
category: "dev"
|
||||
subdomain: "terminal"
|
||||
slug: "termix"
|
||||
# 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-07-12"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "30M"
|
||||
mem_limit: "128M"
|
||||
pi_compatible: true
|
||||
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: "terminal"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Webes SSH terminál - szerver hozzáférés a böngészőből"
|
||||
docs_url: "https://github.com/Termix-SSH/Termix"
|
||||
|
||||
use_cases:
|
||||
- 'SSH hozzáférés a szerveredhez böngészőből'
|
||||
- 'Nincs szükség SSH kliensre a számítógépen'
|
||||
- 'Alapvető szerver menedzsment feladatok bárhonnan'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a terminal.DOMAIN címet a böngészőben'
|
||||
- 'Csatlakozz a szerveredhez SSH-n keresztül'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 8080
|
||||
@@ -0,0 +1,62 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Uptime Kuma"
|
||||
description: "Szolgáltatás és weboldal monitoring"
|
||||
category: "dashboard"
|
||||
subdomain: "status"
|
||||
slug: "uptime-kuma"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "50M"
|
||||
mem_limit: "256M"
|
||||
pi_compatible: true
|
||||
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: "status"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Szolgáltatás monitoring - értesítés ha valami nem működik"
|
||||
docs_url: "https://github.com/louislam/uptime-kuma/wiki"
|
||||
|
||||
use_cases:
|
||||
- 'Weboldalak és szolgáltatások elérhetőségének figyelése'
|
||||
- 'HTTP, TCP, DNS, ping és egyéb protokollok támogatása'
|
||||
- 'Értesítések emailben, Telegramon, Discord-on, stb.'
|
||||
- 'Nyilvános státusz oldal a felhasználóknak'
|
||||
- 'Szép grafikonok a rendelkezésre állásról'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a status.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre az admin fiókot az első megnyitáskor'
|
||||
- 'Add hozzá az első monitort (pl. a saját weboldalad)'
|
||||
- 'Állíts be értesítéseket (email, Telegram, stb.)'
|
||||
- 'Opcionálisan: hozz létre egy nyilvános státusz oldalt'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 3001
|
||||
@@ -0,0 +1,112 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml — App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
# Place alongside docker-compose.yml in each stack directory:
|
||||
# /opt/docker/stacks/vaultwarden/.felhom.yml
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Vaultwarden"
|
||||
description: "Jelszókezelő (Bitwarden-kompatibilis)"
|
||||
category: "security"
|
||||
subdomain: "vault"
|
||||
|
||||
# --- Asset slug ---
|
||||
slug: "vaultwarden"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "50M"
|
||||
mem_limit: "256M"
|
||||
pi_compatible: true
|
||||
needs_hdd: false
|
||||
|
||||
# --- 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: "vault"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: ADMIN_TOKEN
|
||||
label: "Admin panel token"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
description: "Token az admin panel eléréséhez (https://vault.<domain>/admin)"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: SIGNUPS_ALLOWED
|
||||
label: "Regisztráció engedélyezése"
|
||||
type: select
|
||||
default: "false"
|
||||
options:
|
||||
- value: "false"
|
||||
label: "Nem – csak meghívással (ajánlott)"
|
||||
- value: "true"
|
||||
label: "Igen – bárki regisztrálhat, aki ismeri a címet"
|
||||
description: "Alapból lezárva: a család tagjait az admin panelen hívod meg (lásd Első lépések). Nyitott regisztrációval bárki fiókot nyithat, aki kitalálja a címet."
|
||||
locked_after_deploy: false
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: 'Jelszókezelő - Bitwarden kompatibilis, a saját szerveren'
|
||||
docs_url: 'https://github.com/dani-garcia/vaultwarden/wiki'
|
||||
|
||||
use_cases:
|
||||
- 'Jelszavak biztonságos tárolása és automatikus kitöltése'
|
||||
- 'Bitwarden kliensek teljes kompatibilitása (böngésző, mobil, asztali)'
|
||||
- 'Jelszavak megosztása családtagokkal szervezeten belül'
|
||||
- 'Kétfaktoros hitelesítés (TOTP) kódok tárolása'
|
||||
- 'Biztonságos jegyzetek és bankkártya adatok tárolása'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a vault.DOMAIN/admin címet, és lépj be az admin panel tokenjével (Beállítások → Automatikusan generált értékek)'
|
||||
- 'A „Users" fülön az „Invite User" mezőben hívd meg a saját és a családtagok e-mail címét — a regisztráció alapból le van zárva, csak meghívott cím nyithat fiókot'
|
||||
- 'Nyisd meg a vault.DOMAIN címet, válaszd a „Create account" lehetőséget a meghívott címmel, és adj meg erős mesterjelszót'
|
||||
- 'Telepítsd a Bitwarden bővítményt a böngésződbe'
|
||||
- 'Telepítsd a Bitwarden alkalmazást a telefonodra'
|
||||
- 'Importáld a meglévő jelszavaidat (Chrome, Firefox, LastPass, stb.)'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 80
|
||||
path: "/alive"
|
||||
expect:
|
||||
status: 200
|
||||
|
||||
# --- App-email mapping (apps → in-controller shim → hub → Resend) ---
|
||||
# When app-email is on (global toggle + this app's per-app toggle), the controller injects
|
||||
# the relay SMTP settings: host = the on-box shim, port = 2525, From = vaultwarden@felhom.eu.
|
||||
# Vaultwarden uses STARTTLS to the shim and accepts its self-signed cert
|
||||
# (SMTP_ACCEPT_INVALID_CERTS/HOSTNAMES). SMTP_USERNAME/SMTP_PASSWORD are intentionally left
|
||||
# unset — the shim accepts no-auth on the Docker network and holds no Resend key.
|
||||
smtp_mapping:
|
||||
host_var: SMTP_HOST
|
||||
port_var: SMTP_PORT
|
||||
security_var: SMTP_SECURITY
|
||||
security_value: starttls
|
||||
from_var: SMTP_FROM
|
||||
from_name_var: SMTP_FROM_NAME
|
||||
from_local: vaultwarden
|
||||
extra:
|
||||
SMTP_ACCEPT_INVALID_CERTS: "true"
|
||||
SMTP_ACCEPT_INVALID_HOSTNAMES: "true"
|
||||
# Boot-gate for Vaultwarden's strict SMTP validation (campaign finding F1, 2026-07-06):
|
||||
# the image errors out when SMTP_HOST/SMTP_FROM are defined-but-empty, so the compose
|
||||
# default is _ENABLE_SMTP=false and this injection flips it on with the rest of the group.
|
||||
_ENABLE_SMTP: "true"
|
||||
@@ -0,0 +1,71 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Vikunja"
|
||||
description: "Feladatkezelő listák és táblák (Todoist/Trello alternatíva)"
|
||||
category: "productivity"
|
||||
subdomain: "tasks"
|
||||
slug: "vikunja"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "50M"
|
||||
mem_limit: "256M"
|
||||
pi_compatible: true
|
||||
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: "tasks"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: VIKUNJA_SERVICE_JWTSECRET
|
||||
label: "JWT titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Feladatkezelő - listák, Kanban táblák és Gantt diagramok"
|
||||
docs_url: "https://vikunja.io/docs/"
|
||||
|
||||
use_cases:
|
||||
- 'Feladatlisták és teendők kezelése'
|
||||
- 'Kanban tábla nézet (Trello-szerű)'
|
||||
- 'Gantt diagram projekt ütemezéshez'
|
||||
- 'Megosztott listák és csapat együttműködés'
|
||||
- 'Emlékeztetők, lejárati dátumok, címkék és prioritások'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a tasks.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre a fiókodat'
|
||||
- 'Hozd létre az első projektet és feladatlistát'
|
||||
- 'Próbáld ki a Kanban és Lista nézeteket'
|
||||
- 'Hívd meg a családtagokat vagy kollégákat'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 3456
|
||||
path: "/api/v1/info"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -0,0 +1,81 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Wanderer"
|
||||
description: "Túra tervező és nyomkövetéssel"
|
||||
category: "travel"
|
||||
subdomain: "hike"
|
||||
slug: "wanderer"
|
||||
# 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-07-21"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "350M"
|
||||
mem_limit: "1024M"
|
||||
pi_compatible: true
|
||||
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: "hike"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: SUBDOMAIN_DB
|
||||
label: "Adatbázis aldomain"
|
||||
type: subdomain
|
||||
default: "hike-db"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "A PocketBase adatbázis aldomainje - a böngésző KÖZVETLENÜL ezt hívja, ezért saját nevet kap"
|
||||
|
||||
- env_var: MEILI_MASTER_KEY
|
||||
label: "Keresőmotor kulcs"
|
||||
type: secret
|
||||
generate: "hex:16"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: POCKETBASE_ENCRYPTION_KEY
|
||||
label: "Adatbázis titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:16"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Túra tervező - útvonalak, GPX nyomok és domborzati térképek"
|
||||
docs_url: "https://wanderer.to/"
|
||||
|
||||
use_cases:
|
||||
- 'Túra útvonalak tervezése és mentése'
|
||||
- 'GPX fájlok importálása és exportálása'
|
||||
- 'Domborzati profilok és statisztikák'
|
||||
- 'Fotók és jegyzetek hozzáadása az útvonalakhoz'
|
||||
- 'Útvonalak megosztása másokkal'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a hike.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre a fiókodat'
|
||||
- 'Importálj egy GPX fájlt vagy tervezz új útvonalat'
|
||||
- 'Fedezd fel a térképes megjelenítést'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 3000
|
||||
@@ -0,0 +1,69 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "wger"
|
||||
description: "Edzésnapló és fitnesz tervező"
|
||||
category: "home"
|
||||
subdomain: "fitness"
|
||||
slug: "wger"
|
||||
# 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-07-19"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "100M"
|
||||
mem_limit: "384M"
|
||||
pi_compatible: true
|
||||
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: "fitness"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: SECRET_KEY
|
||||
label: "Titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Edzésnapló - edzéstervek, haladás követés és testsúly napló"
|
||||
default_creds: "admin / adminadmin"
|
||||
docs_url: "https://wger.readthedocs.io/"
|
||||
|
||||
use_cases:
|
||||
- 'Edzéstervek létrehozása és követése'
|
||||
- 'Testsúly és testméretek nyilvántartása grafikonokkal'
|
||||
- 'Gyakorlatok adatbázisa képekkel és leírásokkal'
|
||||
- 'Kalória és tápanyag követés'
|
||||
- 'API támogatás fitnesz alkalmazás integrációkhoz'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a fitness.DOMAIN címet a böngészőben'
|
||||
- 'Jelentkezz be: admin / adminadmin'
|
||||
- 'Változtasd meg azonnal a jelszót'
|
||||
- 'Hozd létre az edzéstervedet'
|
||||
- 'Kezdd el naplózni az edzéseidet'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 80
|
||||
@@ -0,0 +1,61 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Wishlist"
|
||||
description: "Családi kívánságlista megosztás"
|
||||
category: "home"
|
||||
subdomain: "wishes"
|
||||
slug: "wishlist"
|
||||
# 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-07-19"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "30M"
|
||||
mem_limit: "128M"
|
||||
pi_compatible: true
|
||||
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: "wishes"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Családi kívánságlista - karácsonyra, születésnapokra"
|
||||
docs_url: "https://github.com/cmintey/wishlist"
|
||||
|
||||
use_cases:
|
||||
- 'Kívánságlisták létrehozása karácsonyra, születésnapokra'
|
||||
- 'Családtagok meghívása saját listáik kezeléséhez'
|
||||
- 'Ajándékok lefoglalása meglepetés nélkül'
|
||||
- 'Árak és linkek hozzáadása az ajándékokhoz'
|
||||
- 'Csoportos ajándékok szervezése'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg a wishes.DOMAIN címet a böngészőben'
|
||||
- 'Hozd létre a fiókodat'
|
||||
- 'Hozd létre az első kívánságlistádat'
|
||||
- 'Hívd meg a családtagokat'
|
||||
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: http
|
||||
port: 3000
|
||||
@@ -0,0 +1,80 @@
|
||||
# =============================================================================
|
||||
# .felhom.yml - App metadata for felhom-controller
|
||||
# =============================================================================
|
||||
|
||||
# --- Display info (shown on dashboard) ---
|
||||
display_name: "Zipline"
|
||||
description: "ShareX/Flameshot szerver - screenshot és fájlmegosztás"
|
||||
category: "files"
|
||||
subdomain: "img"
|
||||
slug: "zipline"
|
||||
# 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-07-18"
|
||||
|
||||
# --- Resource hints (displayed on deploy screen) ---
|
||||
resources:
|
||||
mem_request: "100M"
|
||||
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: "img"
|
||||
required: true
|
||||
locked_after_deploy: true
|
||||
description: "Az alkalmazás aldomainje"
|
||||
|
||||
- env_var: CORE_SECRET
|
||||
label: "Titkosítási kulcs"
|
||||
type: secret
|
||||
generate: "hex:32"
|
||||
locked_after_deploy: true
|
||||
|
||||
- env_var: DB_PASSWORD
|
||||
label: "Adatbázis jelszó"
|
||||
type: secret
|
||||
generate: "password:24"
|
||||
locked_after_deploy: true
|
||||
|
||||
# --- App info (info page content) ---
|
||||
app_info:
|
||||
tagline: "Screenshot és fájlmegosztó szerver ShareX/Flameshot integrációval"
|
||||
default_creds: "admin / zipline"
|
||||
docs_url: "https://zipline.diced.sh/docs/"
|
||||
|
||||
use_cases:
|
||||
- 'Screenshotok automatikus feltöltése ShareX/Flameshot-ból'
|
||||
- 'URL rövidítés és szöveg megosztás (paste)'
|
||||
- 'Galéria nézet és album kezelés'
|
||||
- 'API támogatás egyedi integrációkhoz'
|
||||
- 'Felhasználói fiókok és meghívó rendszer'
|
||||
|
||||
first_steps:
|
||||
- 'Nyisd meg az img.DOMAIN címet a böngészőben'
|
||||
- 'Jelentkezz be: admin / zipline'
|
||||
- 'Változtasd meg azonnal a jelszót'
|
||||
- 'Konfiguráld a ShareX-et vagy Flameshot-ot az API URL-lel'
|
||||
- 'Tölts fel egy screenshot-ot a teszteléshez'
|
||||
|
||||
prerequisites:
|
||||
- 'ShareX (Windows) vagy Flameshot (Linux) ajánlott a screenshot feltöltéshez'
|
||||
|
||||
# --- Controller-side health probe ---
|
||||
healthcheck:
|
||||
checks:
|
||||
- type: api
|
||||
port: 3000
|
||||
path: "/api/health"
|
||||
expect:
|
||||
status: 200
|
||||
@@ -182,7 +182,11 @@ func (s *Server) dashboardHandler(w http.ResponseWriter, r *http.Request) {
|
||||
data["TitleKey"] = "page.title.dashboard" // i18n: the Hungarian title above is what hu renders
|
||||
s.addRecoveryBanner(data, r) // R-241: the reminder bar, per visit
|
||||
data["SettingsWarning"] = s.settings.LoadWarning // non-empty if settings.json was recovered from corruption
|
||||
data["Stacks"] = deployedStacks
|
||||
// R-560: the app rows carry catalog copy (each row's `.Meta.Description`), so the list the
|
||||
// TEMPLATE sees is the localised view. The lists the warning helpers below see are the
|
||||
// originals — they key on stack NAMES, and handing them a translated copy would only widen
|
||||
// what a catalog push can reach. For hu this returns the same slice, untouched.
|
||||
data["Stacks"] = stacks.LocalizeStacks(deployedStacks, s.langFor(r))
|
||||
data["MissingStorage"] = s.missingStorageMap(deployedStacks)
|
||||
data["OOMKilled"] = s.stackMgr.OOMKilledStacks() // R-514
|
||||
nw, ns := s.networkStorageWarnings(deployedStacks) // NAS unreachable (recoverable) / guest-side stub (defect)
|
||||
@@ -362,7 +366,7 @@ func (s *Server) stacksHandler(w http.ResponseWriter, r *http.Request) {
|
||||
data := s.baseData("stacks", "Alkalmazások")
|
||||
data["TitleKey"] = "page.title.stacks" // i18n: the Hungarian title above is what hu renders
|
||||
allStacks := visibleCatalogStacks(s.stackMgr.GetStacks())
|
||||
data["Stacks"] = allStacks
|
||||
data["Stacks"] = stacks.LocalizeStacks(allStacks, s.langFor(r)) // R-560 — see dashboardHandler
|
||||
data["MissingStorage"] = s.missingStorageMap(allStacks)
|
||||
nw, ns := s.networkStorageWarnings(allStacks) // NAS unreachable (recoverable) / guest-side stub (defect)
|
||||
data["NetworkWarnings"] = nw
|
||||
@@ -415,7 +419,7 @@ func (s *Server) logsHandler(w http.ResponseWriter, r *http.Request, name string
|
||||
|
||||
data := s.baseData("logs", stack.Meta.DisplayName+" — Naplók")
|
||||
data["TitleKey"], data["TitleArgs"] = "page.title.logs", []interface{}{stack.Meta.DisplayName} // i18n: the Hungarian title above is what hu renders
|
||||
data["Stack"] = stack
|
||||
data["Stack"] = stacks.LocalizeStackPtr(stack, s.langFor(r)) // R-560
|
||||
data["Logs"] = logs
|
||||
s.executeTemplate(w, r, "logs", data)
|
||||
}
|
||||
@@ -436,13 +440,23 @@ func (s *Server) deployHandler(w http.ResponseWriter, r *http.Request, name stri
|
||||
stack, _ := s.stackMgr.GetStack(name)
|
||||
alreadyDeployed := appCfg != nil && appCfg.Deployed
|
||||
|
||||
// R-560 — the ONE place this page's catalog copy is chosen, and it is placed here on purpose:
|
||||
// every `meta` read below it (the field labels, the descriptions, the optional-config groups)
|
||||
// is a display read, and this handler only ever renders — the deploy POST is a different
|
||||
// route. The overlay changes copy fields ONLY; `env_var`, `type`, `generate`, `default`,
|
||||
// `required` and `locked_after_deploy` are not in MetadataOverlay at all, so the auto-field
|
||||
// map, the HDD_PATH question and the prefill keys below read exactly what they read before.
|
||||
lang := s.langFor(r)
|
||||
localized := meta.For(lang)
|
||||
meta = &localized
|
||||
|
||||
pageTitle, pageTitleKey := meta.DisplayName+" — Telepítés", "page.title.deploy"
|
||||
if alreadyDeployed {
|
||||
pageTitle, pageTitleKey = meta.DisplayName+" — Beállítások", "page.title.app_settings"
|
||||
}
|
||||
data := s.baseData("deploy", pageTitle)
|
||||
data["TitleKey"], data["TitleArgs"] = pageTitleKey, []interface{}{meta.DisplayName} // i18n: the Hungarian title above is what hu renders
|
||||
data["Stack"] = stack
|
||||
data["Stack"] = stacks.LocalizeStackPtr(stack, lang) // R-560
|
||||
data["Meta"] = meta
|
||||
data["AppConfig"] = appCfg
|
||||
data["AlreadyDeployed"] = alreadyDeployed
|
||||
@@ -583,7 +597,21 @@ func (s *Server) deployHandler(w http.ResponseWriter, r *http.Request, name stri
|
||||
// App-to-app integrations
|
||||
if im := s.integrationMgr.Load(); meta.HasIntegrations() && im != nil {
|
||||
data["HasIntegrations"] = true
|
||||
data["Integrations"] = im.ListForProvider(meta.Slug)
|
||||
// R-560: the integration manager reads the stack's own (Hungarian) Meta to build these
|
||||
// rows — it has no request and therefore no language. The label and the sentence are
|
||||
// catalog copy, so they are re-taken from the LOCALISED meta here, matched by target
|
||||
// the same way the overlay itself matches. Everything else in the row (state, target
|
||||
// health, last error) is the manager's and is left alone.
|
||||
rows := im.ListForProvider(meta.Slug)
|
||||
for i := range rows {
|
||||
for _, def := range meta.Integrations {
|
||||
if def.Target == rows[i].Target {
|
||||
rows[i].Label, rows[i].Description = def.Label, def.Description
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
data["Integrations"] = rows
|
||||
}
|
||||
|
||||
// Geo-restriction per-app data
|
||||
@@ -707,6 +735,13 @@ func (s *Server) appDetailHandler(w http.ResponseWriter, r *http.Request, slug s
|
||||
}
|
||||
}
|
||||
|
||||
// R-560 — this page is the one that shows ALL of an app's catalog copy (tagline, use cases,
|
||||
// first steps, prerequisites, the default-credentials line, the data-folder labels), so the
|
||||
// localised view is taken ONCE here and `found` is replaced by it. Everything downstream —
|
||||
// the data-path cards, the initial-credentials note — then reads the household's language
|
||||
// without a second decision to get wrong.
|
||||
found = stacks.LocalizeStackPtr(found, s.langFor(r))
|
||||
|
||||
data := s.baseData("stacks", found.Meta.DisplayName)
|
||||
data["Stack"] = found
|
||||
data["Meta"] = found.Meta
|
||||
@@ -743,7 +778,10 @@ func (s *Server) appDetailHandler(w http.ResponseWriter, r *http.Request, slug s
|
||||
data["InitialCreds"] = &stacks.ExtractedCreds{
|
||||
Available: creds.Available,
|
||||
Username: creds.Username,
|
||||
Note: creds.Note,
|
||||
// R-560: the reader took the note from the manager's Hungarian metadata (it runs
|
||||
// without a request and has no language). The note is catalog copy, so it is
|
||||
// re-taken from the localised spec — the same value for hu, byte for byte.
|
||||
Note: found.Meta.InitialCreds.Note,
|
||||
// Password deliberately NOT carried — the reveal endpoint is the only path to it.
|
||||
}
|
||||
data["InitialCredsHasPassword"] = strings.TrimSpace(creds.Password) != ""
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestNoDirectMetaCopyReadOnPages — the guard for R-560's whole point.
|
||||
//
|
||||
// Catalog copy (`Description`, `AppInfo`, the deploy-field labels, `OptionalConfig`, `Integrations`,
|
||||
// the `DataPaths` labels, the initial-credentials note) is HUNGARIAN in the value the stack manager
|
||||
// caches. A page reaches the household's language only by going through `Metadata.For(lang)` —
|
||||
// `stacks.LocalizeStacks`, `LocalizeStack`, `LocalizeStackPtr` or `MetaFor`. Read `x.Meta.<copy>`
|
||||
// straight off a manager value and an English household silently gets Hungarian: no error, no log,
|
||||
// nothing that looks wrong on the page. That is precisely the failure mode this project has shipped
|
||||
// nine times under a comment that read as settled.
|
||||
//
|
||||
// So every direct read of a copy field off a `.Meta` in this package is LISTED BELOW WITH A REASON.
|
||||
// A new one fails this test, and the author then has two honest choices: route it through For(lang),
|
||||
// or add it here saying why it may stay Hungarian.
|
||||
//
|
||||
// WHAT THIS TEST CANNOT DO: it reads the source, so it cannot tell a localised receiver from an
|
||||
// unlocalised one — `found.Meta.AppInfo` looks the same either way. It catches the ARRIVAL of a new
|
||||
// copy read, which is when a human has to think, and that is the whole claim made for it.
|
||||
//
|
||||
// RED-PROOF (2026-09-20): adding `_ = stack.Meta.Description` to handlers.go failed this test
|
||||
// naming handlers.go and Description; removing it went green.
|
||||
var metaCopyReadAllowlist = map[string]string{
|
||||
// The app page localises `found` in one place at the top of appDetailHandler and every read
|
||||
// below it — these included — is of that localised value.
|
||||
"handlers.go:AppInfo": "appDetailHandler reads it off the LocalizeStackPtr'd `found`",
|
||||
"handlers.go:InitialCreds": "appDetailHandler: the nil check and the note, both off localised `found`",
|
||||
// buildDataPathCards is called with the same localised `found`; the labels it renders are the
|
||||
// English ones when the household is on English.
|
||||
"datapath_card.go:DataPaths": "buildDataPathCards is handed the localised stack by appDetailHandler",
|
||||
}
|
||||
|
||||
// metaCopyFields are the Metadata fields that carry customer-facing TEXT. Everything else on
|
||||
// Metadata — Slug, Subdomain, OpenPath, BrandColor, Category, Resources, Lifecycle, CatalogSince,
|
||||
// HealthCheck, SMTPMapping, Backup — is configuration and reads the same in every language.
|
||||
// DisplayName is deliberately NOT here: an app's name is not translated (10-localisation.md §11,
|
||||
// operator ruling 7).
|
||||
var metaCopyFields = map[string]bool{
|
||||
"Description": true,
|
||||
"AppInfo": true,
|
||||
"DeployFields": true,
|
||||
"OptionalConfig": true,
|
||||
"Integrations": true,
|
||||
"DataPaths": true,
|
||||
"InitialCreds": true,
|
||||
}
|
||||
|
||||
func TestNoDirectMetaCopyReadOnPages(t *testing.T) {
|
||||
entries, err := os.ReadDir(".")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
var unlisted []string
|
||||
|
||||
for _, e := range entries {
|
||||
name := e.Name()
|
||||
if e.IsDir() || !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
|
||||
continue
|
||||
}
|
||||
fset := token.NewFileSet()
|
||||
f, err := parser.ParseFile(fset, name, nil, 0) // comments are not walked — only real reads count
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v", name, err)
|
||||
}
|
||||
ast.Inspect(f, func(n ast.Node) bool {
|
||||
outer, ok := n.(*ast.SelectorExpr)
|
||||
if !ok || !metaCopyFields[outer.Sel.Name] {
|
||||
return true
|
||||
}
|
||||
inner, ok := outer.X.(*ast.SelectorExpr)
|
||||
if !ok || inner.Sel.Name != "Meta" {
|
||||
return true
|
||||
}
|
||||
key := name + ":" + outer.Sel.Name
|
||||
seen[key] = true
|
||||
if _, allowed := metaCopyReadAllowlist[key]; !allowed {
|
||||
unlisted = append(unlisted, fmt.Sprintf("%s (%s)", key, fset.Position(outer.Pos())))
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
sort.Strings(unlisted)
|
||||
for _, u := range unlisted {
|
||||
t.Errorf("catalog COPY read straight off .Meta: %s\n"+
|
||||
" Route it through stacks.LocalizeStack(s)/LocalizeStackPtr/MetaFor(lang), or add it to\n"+
|
||||
" metaCopyReadAllowlist in this file with the reason it may stay Hungarian.", u)
|
||||
}
|
||||
|
||||
// A stale allow-list entry is a lie about what the code does — it must go when its read goes.
|
||||
for key := range metaCopyReadAllowlist {
|
||||
if !seen[key] {
|
||||
t.Errorf("allow-list entry %q no longer matches any read — delete it", key)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user