No description
Find a file
2026-09-25 10:44:13 +02:00
.devcontainer fix: edge hardening, rootless containers, fail-closed frontend mode 2026-09-14 21:35:06 +02:00
.forgejo/workflows chore: enforce ruff lint and format standards across backend 2026-09-14 08:10:14 +02:00
backend fix: keep Langflow flow names in sync files, write them world-readable 2026-09-25 10:44:13 +02:00
frontend fix: keep Langflow flow names in sync files, write them world-readable 2026-09-25 10:44:13 +02:00
.env.example chore: prod env checker, secret guidance, internet-exposure runbook 2026-09-14 21:39:06 +02:00
.gitattributes fix: keep shell scripts LF so dash entrypoint starts 2026-09-15 14:50:56 +02:00
.gitignore chore: phase 0 reproducible docker/dev setup with version pinning 2026-09-09 09:44:59 +00:00
AGENTS.md chore: enforce ruff lint and format standards across backend 2026-09-14 08:10:14 +02:00
CHANGELOG.md fix: keep Langflow flow names in sync files, write them world-readable 2026-09-25 10:44:13 +02:00
docker-compose.prod.yml chore: add prod compose override for the Pi deployment 2026-09-24 09:48:35 +02:00
docker-compose.yml fix: edge hardening, rootless containers, fail-closed frontend mode 2026-09-14 21:35:06 +02:00
Dockerfile.lfx fix: make Langflow-synced flows visible (lfx volume perms, pull dedup) 2026-09-25 08:19:42 +02:00
lfx-entrypoint.sh fix: make Langflow-synced flows visible (lfx volume perms, pull dedup) 2026-09-25 08:19:42 +02:00
opencode.json feat: initial project setup 2026-09-04 10:17:22 +00:00
README.md feat: manual full-pass sync Langflow -> files -> DB+LFX with admin guide 2026-09-24 22:33:33 +02:00
ROADMAP.md chore: add ROADMAP.md as authoritative future-ideas file 2026-09-13 21:40:18 +02:00
transkript_ideen.md feat: initial project setup 2026-09-04 10:17:22 +00:00
VERSION chore: version 0.1 — changelog, VERSION file, agent workflow rules 2026-09-13 19:32:41 +02:00

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).

Future

Ideas and planned features live in ROADMAP.md (the single authoritative place for future implementation ideas).

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

  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 <uuid> — 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 → press "Aus Langflow synchronisieren" in Verwaltung (manual full pass: Langflow → backend/flows/<name>.json → DB + LFX deploy) → commit. File-only alternatives: scripts/sync_flows.py --pull --sync, UI download, or the single-flow import by Langflow ID. The watcher deploys file edits automatically. Deleting a file removes the flow including its runs (git keeps the JSON).

Production (self-hosted — TLS/reverse proxy required, not included)

  1. Check out the repo on the host, create .env from .env.example with real secrets (openssl rand -hex 32) and FRONTEND_MODE=preview.
  2. Validate it: uv run python scripts/check_prod.py --env ../.env (run from backend/; blocks on weak secrets or dev modes).
  3. docker compose up -d --build.
  4. 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).

Internet exposure checklist (both forwarded ports sit behind your HTTPS proxy — nothing here substitutes for it):

  • Proxy: force HTTPS (+ HSTS), and put an extra login (basic-auth or OIDC) in front of Langflow :7860. Langflow has a history of critical unauthenticated RCEs — treat its UI as privileged tooling, never share flows publicly ("Shareable Playground" = RCE risk).
  • Secrets: all *_KEY/*_TOKEN/*_PASSWORD long and random; rotate after any incident or staff change; re-run check_prod.py.
  • Langflow/LFX upgrades (pinned in lockstep): bump LANGFLOW_VERSION (.env), Dockerfile.lfx ARG, and backend lfx~= together, then lfx upgrade --upgrade-flow=safe + lfx validate --level 4 on backend/flows/*.json. Check Langflow security advisories monthly.
  • Backups: backend/data/ (SQLite) and the langflow-data volume.

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).