# 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 via `POST /api/flows/sync` or `uv 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 via `POST /api/auth/admin-bootstrap` (only on an empty user table, email must be in `ADMIN_EMAILS`). - **Dynamic forms** — flows declare form fields as typed inputs on a `CustomInput*` custom component (reusable library in `backend/components/`, mounted into Langflow via `LANGFLOW_COMPONENTS_PATH`). `GET /api/flows/{id}/input-schema` derives 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. See `backend/components/kirche/README.md` for 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`. ```mermaid flowchart LR subgraph Repo["Git repo — source of truth"] FLOWS["backend/flows/*.json
one Langflow export per flow"] end subgraph Stack["Compose stack (dev + prod)"] UI["frontend — React UI (3000)"] API["api — FastAPI (8000)
+ embedded flow-watcher"] DB[("app.db — SQLite file")] LF["langflow — authoring UI (7860)
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 1. Copy `.env.example` to `.env` and fill in the secrets. 2. Open the repo in VS Code → "Reopen in Container". Setup installs dependencies and syncs `backend/flows/`; the entrypoints migrate and serve automatically. 3. 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` — reconcile `backend/flows/`. - `uv run python scripts/sync_flows.py --pull` — export all Langflow flows into `backend/flows/` first. - `uv run python scripts/deploy_flow.py --langflow-id ` — import one Langflow flow via the API. - `uv run python scripts/make_flow_fixtures.py` — regenerate the bundled flows (writes test fixtures and `backend/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/.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) 1. Check out the repo on the host, create `.env` from `.env.example` with real secrets and `FRONTEND_MODE=preview`. 2. `docker compose up -d --build`. 3. 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).