129 lines
9 KiB
Markdown
129 lines
9 KiB
Markdown
# Changelog
|
|
|
|
All notable changes to this project will be documented in this file.
|
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
|
## [Unreleased]
|
|
### Changed
|
|
- Declutter: shared `BaseApiClient` (LFX/Langflow) with tenacity transport retry, single `get_db`, `model_validate` mappers, unified LFX/Langflow error mapping, stream logic moved to `runner.py`, `sync_full_pass` single orchestration (API+CLI), shared model base (`utcnow`/`ts_column`), unified auth counters, `httpx` in `deploy_flow.py`, atomicwrites file writes, `secure`-package headers.
|
|
- Auth: stateless JWT sessions (HS256, 30d, HttpOnly cookie unchanged) replace the `user_sessions` table (Alembic revision drops it; all sessions invalidated at deploy); slowapi run throttle replaces the hand-rolled sliding window; mail via jinja template + fastapi-mail (same copy/fallback contract); CLIs on typer; `JWT_SECRET` enforced by `check_prod.py`.
|
|
- Forms: thin variant components over shared `components/kirche/_form_core.py` (codegen-inlined by `kirche_node()` for LFX; all 5 flows regenerated + level-4 validated), structured `visible_if` key alongside legacy markers, `LangflowClient.upsert_flow` + `scripts/push_flows_to_langflow.py` (6 canonical flows pushed to Langflow UI).
|
|
- Store/sync: single `next_version_no` query per version, validation only at the `create_version` choke point, mtime-cached `.flowsignore`.
|
|
- Tests (full real LFX kept): shared `conftest` helpers + `tests/_harness.py` adopted by fixtures and smoke script, parametrized matrices (export stems, check_prod env, deploy failures, sync listing failures, API auth probes, input_schema types), relaxed brittle asserts (ui:order sets, per-flag cookie asserts, SSE any-match).
|
|
- Frontend: react-query reads + notifications, `useForm`+zod static forms, shared `DecisionButtons`/`ErrorAlert`/`JsonView`/`FormattedDate`/`RunsTable`/`Landing` blocks, new aggregate `GET /api/runs` kills the Tasks N+1, `Promise.all` version fetches, `sharp` icons, selector-based screenshots, dead photo removed.
|
|
### Added
|
|
- Aggregate `GET /api/runs` (tenant-scoped runs with flow names, single query).
|
|
- Branched questionnaires: `[visible_if feld=Wert]` markers in a
|
|
`CustomInputForm` field's `info` (code editor) show the field only when
|
|
the condition holds — nested to any depth, with `&` for AND conditions
|
|
and quotes for values with spaces. The parser emits `allOf`/`if`/`then`
|
|
branches (branch-scoped `required`, template-order placement); unknown
|
|
triggers, cycles, and unsupported trigger types fail open (always
|
|
visible). New demo flow `bauvorhaben.json` (4 levels + sibling branch +
|
|
bool trigger). Values of hidden fields are kept and submitted.
|
|
- Run envelope carries the asked field names (`fields`, from the
|
|
version's form schema): `collect()` emits defaults only for asked
|
|
AND currently visible fields (hidden branch fields stay out, like the
|
|
frontend never submits them), so templates may declare fields unknown
|
|
to the component code and unasked code defaults stay out of the run
|
|
output. Without the list (raw dicts, Langflow playground) all visible
|
|
declared defaults apply.
|
|
- Standalone `CustomInputBauvorhaben` component ("Bauvorhaben Form" in
|
|
the kirche palette, zero shared code with `CustomInputForm` — the LFX
|
|
runtime executes embedded module source without our package); the
|
|
bauvorhaben flow uses it, and Langflow no longer normalizes the node
|
|
back to the default form on import.
|
|
- Form parser also recognizes user-built `CustomComponent` nodes whose
|
|
display name ends with `"Form"` (e.g. Mitarbeiter Einstellen Form) —
|
|
same template contract, no kirche base needed.
|
|
- Standalone `CustomInputMitarbeiter` component ("Mitarbeiter Einstellen
|
|
Form") with hiring flow incl. Gehaltsrechner, rebuilt generator-owned.
|
|
- Admin flow table shows one row per flow (latest version, with live
|
|
version note when an older version is deployed) instead of one row
|
|
per version.
|
|
- Step-by-step guide for new workflow modules: `docs/new_workflow_module.md`
|
|
(linked from README).
|
|
### Changed
|
|
- `CustomInputForm.collect()` is now dynamic and returns `Data` (JSON)
|
|
instead of `Message`: fields can be renamed, added, or removed in the
|
|
Langflow code editor with no `collect()` change, and values travel as a
|
|
real JSON object. The form parser keeps `name` keys verbatim (empty
|
|
names skipped, collisions suffixed) and the run envelope merges unknown
|
|
keys. Note: a terminal `ChatOutput` renders `Data` as a fenced ```json
|
|
block, and downstream components should read `.data`, not `.text`.
|
|
### Added
|
|
- Flow-Sync ist jetzt ein manueller Full-Pass: `POST /api/flows/sync`
|
|
(Button "Aus Langflow synchronisieren" in der Verwaltung) holt erst alle
|
|
Flows aus Langflow nach `backend/flows/*.json` und deployed sie danach
|
|
automatisch (Report mit `pulled`-Liste). Der Hintergrund-Beobachter und der
|
|
Startup-Sync bleiben dateibasiert. Die Verwaltung zeigt eine deutsche
|
|
Schritt-Anleitung direkt beim Sync-Button.
|
|
- LLM-Provider-Umgebung für Langflow: `OPENAI_API_KEY` + `OPENAI_BASE_URL`
|
|
in `.env` (OpenAI-kompatible Endpoints) erzeugen automatisch
|
|
restart-feste Global Variables in Langflow; LFX liest dieselben Werte.
|
|
- Langflow-Sitzungen halten länger: `LANGFLOW_REFRESH_TOKEN_EXPIRE_SECONDS`
|
|
(Default weiter 7 Tage, Dev-Beispiel 90) + stabile JWT-Signatur via
|
|
`LANGFLOW_SECRET_KEY` — kein Re-Login nach Container-Restarts.
|
|
### Fixed
|
|
- Flow-Sync aus Langflow: neue Flows blieben unsichtbar, weil LFX-Uploads
|
|
mit `Permission denied` scheiterten (named Volume root-owned, LFX läuft
|
|
rootless). `lfx-entrypoint.sh` chownt `/flows` per gosu vor dem Start;
|
|
zusätzlich Pull-Dedup (wiederverwendet gleichnamige/identische Dateien
|
|
statt Bindestrich-Duplikate wie `simple-rule.json`, die jede Sync-Meldung
|
|
mit Namenskonflikten füllten).
|
|
- Sync-Dateinamen behalten die Langflow-Namen (`test_flow.json` statt
|
|
`test-flow.json`; nur dateisystem-reservierte Zeichen werden ersetzt).
|
|
- Gezogene Flow-Dateien sind world-readable (0o644): `mkstemp` erzeugte
|
|
0o600-Dateien, die Langflow beim Start abstürzen ließen
|
|
(`Permission denied` in `/app/flows`, Crash-Loop) und der API Fehler
|
|
(`unreadable`) verursachten.
|
|
- `LANGFLOW_SECRET_KEY` muss ein gültiger Fernet-Key sein (44 Zeichen,
|
|
urlsafe-base64): ein Hex-String brach die Variablen-Verschlüsselung mit
|
|
`Fernet key must be 32 url-safe base64-encoded bytes` (500 beim Anlegen
|
|
von Global Variables — Provider-Keys ließen sich nicht speichern).
|
|
`.env.example` dokumentiert die Erzeugung.
|
|
- LFX runtime user gets a home directory (`useradd -m`, `HOME` set):
|
|
without one every flow run failed with "Settings service not found".
|
|
### Security
|
|
- Production ops: `scripts/check_prod.py` validates `.env` secrets and
|
|
modes before deploy (with tests); README production checklist
|
|
(proxy gates for Langflow, secret rotation, upgrade runbook).
|
|
### Security
|
|
- API authorization: flow management is admin-only, runs and run/approval
|
|
reads require login with strict session-tenant scoping, approval
|
|
decisions record the session user, and flow callbacks authenticate with
|
|
a shared `X-Callback-Token` (`CALLBACK_TOKEN`). Request-controlled
|
|
`tenant_id`, `callback_base_url` and `continuation_flow_id` were
|
|
removed (SSRF / cross-tenant / flow-chaining hardening);
|
|
continuations now resolve from the admin-authored definition.
|
|
- Frontend: `/app/*` routes require login; approver is the session user.
|
|
- Edge hardening: interactive API docs only with debug, security headers
|
|
(nosniff/frame/Referrer-Policy), 2 MiB body cap, per-IP run throttle,
|
|
generic upstream-error responses, magic links never logged.
|
|
- Containers run rootless (api/vite as uid 1000, lfx as `lfx` user);
|
|
frontend fails closed to preview mode unless `FRONTEND_MODE=dev`.
|
|
### Added
|
|
- Landing page: status-quo problem block, 5-step process with quote,
|
|
portal overview with admin areas, AI platform parts, exception tiers,
|
|
quantified benefits, integrations, use-case examples, pilot-program
|
|
section, expanded FAQ (8 items incl. KI data usage, price model,
|
|
responsibility).
|
|
### Changed
|
|
- Landing page copy overhauled after 3 reviewer rounds (church-admin
|
|
compliance wording: "entwickelt nach DSG-EKD/DSGVO" + AVV/TOMs,
|
|
human release responsibility, honest pilot framing instead of
|
|
invented testimonials; CTA now "Pilotgespräch vereinbaren").
|
|
- New photo `pilot-meeting.webp` (consultation scene, self-hosted).
|
|
- Backend lint + format standards via ruff (pinned dev dependency,
|
|
enforced in CI): `uv run ruff check .`, `uv run ruff format`.
|
|
|
|
## [0.1.0] - 2026-09-13
|
|
### Added
|
|
- Repo scaffold: docker-compose dev/prod, version-pinned images, devcontainer.
|
|
- Magic-link auth, access requests, RBAC, frontend access-management UI.
|
|
- File-based flow source of truth + sync engine + LFX runtime.
|
|
- RJSF dynamic forms, router, Mantine dark-mode design system.
|
|
- Conversion landing page, automated screenshots, bell-tower favicon.
|
|
- Email-first login, branded multipart HTML magic-link mails.
|
|
- lfx level-4 validation on all canonical flows + regression test.
|