| .devcontainer | ||
| .forgejo/workflows | ||
| backend | ||
| frontend | ||
| .env.example | ||
| .gitignore | ||
| AGENTS.md | ||
| CHANGELOG.md | ||
| docker-compose.yml | ||
| Dockerfile.lfx | ||
| opencode.json | ||
| PLAN_NEXT.md | ||
| README.md | ||
| transkript_ideen.md | ||
| VERSION | ||
Kirche Einfach
AI-assisted administration platform for church organizations.
Staff describe a request in plain words. The platform guides them through the process, checks the rules automatically, and asks a human only when something needs judgment. Every step is documented and traceable.
Features
- Visual flow authoring — design decision flows in Langflow, then bring them into the platform.
- Flows as files — each flow lives as one JSON file under
backend/flows/. The directory is the source of truth: committed to git, reviewable, diffable. - Automatic sync — the API watches
backend/flows/and reconciles every change into the database and the runtime: new files become flows, edits become new versions, deleted files remove the flow (including its runs). Same on every startup; also triggerable viaPOST /api/flows/syncoruv run python scripts/sync_flows.py --sync. - Versioned runtime — every change creates an immutable version; versions deploy to the lightweight LFX runtime and can run synchronously or streamed.
- Approvals — a flow can pause and ask a human for a decision. Approving can automatically start a follow-up ("continuation") flow.
- Access management — public landing page (German) with an access-request
form (request + approval). Approved users get a passwordless magic-link
invite by email (SMTP via
.env); sessions are HttpOnly cookies, tenants come from the session. First admin viaPOST /api/auth/admin-bootstrap(only on an empty user table, email must be inADMIN_EMAILS). - Dynamic forms — flows declare form fields as typed inputs on a
CustomInput*custom component (reusable library inbackend/components/, mounted into Langflow viaLANGFLOW_COMPONENTS_PATH).GET /api/flows/{id}/input-schemaderives a JSON Schema + RJSF uiSchema from the deployed version; the webapp renders the matching form automatically. Flows without such a node fall back to a single textarea. Seebackend/components/kirche/README.mdfor authoring new form fields. - Web UI — landing page (Start), access request (Zugang), and the logged-in webapp: Workflows (choose + run with dynamic form), Aufgaben (approvals), Verwaltung (admin: access requests, import, sync, deploy).
Infrastructure
One docker-compose.yml at the repo root runs the whole stack — identical
services in dev and prod. Dev-only needs (editor, SSH keys, autoreload,
docker CLI) come from .devcontainer/devcontainer.json.
flowchart LR
subgraph Repo["Git repo — source of truth"]
FLOWS["backend/flows/*.json<br/>one Langflow export per flow"]
end
subgraph Stack["Compose stack (dev + prod)"]
UI["frontend — React UI (3000)"]
API["api — FastAPI (8000)<br/>+ embedded flow-watcher"]
DB[("app.db — SQLite file")]
LF["langflow — authoring UI (7860)<br/>langflow.db — SQLite file"]
LFX["lfx — flow runtime (6004)"]
WT["watchtower — nightly image updates (prod)"]
end
UI --> API
FLOWS -->|watch + sync| API
API -->|definitions · versions · runs · approvals| DB
API -->|pull / export| LF
API -->|upload · run · unregister| LFX
LFX -->|approval callbacks| API
WT -.->|updates :latest images| LF
| Service | Purpose | URL |
|---|---|---|
| React frontend | Web UI (Vite, HMR in dev) | http://localhost:3000 |
| FastAPI backend | API + flow orchestration (reload in dev) | http://localhost:8000 |
| API docs | Swagger UI | http://localhost:8000/api/docs |
| Langflow | Visual flow authoring | http://localhost:7860 |
| LFX | Flow runtime (internal, no direct UI) | localhost:6004 |
| SQLite files | backend/data/kirche.db (app), Langflow keeps its own file |
— |
Why SQLite: a flow run needs only a handful of single-row statements, and
Langflow itself runs on SQLite by default — so the whole stack works without
a database server. Postgres can return later by changing DATABASE_URL
(migrations stay portable).
.env holds only ubiquitous variables (identical value in dev and prod:
secrets, service URLs). Dev-only variables travel via devcontainer.json
(APP_ENV=dev); paths resolve from the repo root in code.
Getting Started
- Copy
.env.exampleto.envand fill in the secrets. - Open the repo in VS Code → "Reopen in Container". Setup installs
dependencies and syncs
backend/flows/; the entrypoints migrate and serve automatically. - The stack is already running: UI at http://localhost:3000, API docs at http://localhost:8000/api/docs.
Development
Backend (attached api container, from backend/):
uv run pytest— full test suite (throwaway SQLite file, no external DB).uv run alembic upgrade head— migrate the dev database.uv run python scripts/sync_flows.py --sync— reconcilebackend/flows/.uv run python scripts/sync_flows.py --pull— export all Langflow flows intobackend/flows/first.uv run python scripts/deploy_flow.py --langflow-id <uuid>— import one Langflow flow via the API.uv run python scripts/make_flow_fixtures.py— regenerate the bundled flows (writes test fixtures andbackend/flows/).uv run python scripts/smoke_e2e.py— manual end-to-end smoke.
Frontend (node lives in the frontend container):
docker compose exec frontend npm run dev— HMR dev server (already running via compose; this is for a second instance or flags).docker compose exec frontend npm run build— typecheck + build.- Without a docker socket: VS Code "Attach to Running Container" → frontend.
Flow workflow: design in Langflow → export into backend/flows/<name>.json
(--pull, or UI download) → commit → the watcher deploys it automatically.
Deleting a file removes the flow including its runs (git keeps the JSON).
Production (self-hosted, internal use — no TLS/reverse proxy included)
- Check out the repo on the host, create
.envfrom.env.examplewith real secrets andFRONTEND_MODE=preview. docker compose up -d --build.- Code updates via
git pull+docker compose restart api frontend(the checkout is bind-mounted); image rebuilds only for dependency changes (docker compose up -d --build).
Container updates: registry images (langflowai/langflow:latest)
auto-update nightly via Watchtower (nickfedor/watchtower). Locally built
images (api, lfx, frontend) update with docker compose build --pull.
Continuous integration
Workflows in .forgejo/workflows/ run on Forgejo: backend pytest, frontend
build, compose validation. They need a Runner with the docker label online
(repo Settings → Actions → Runners) and action resolution for
actions/checkout (github proxy or code.forgejo.org mirror).