Backends (serverseitige Rechteprüfung vor jeder Verarbeitung, requirePermission-Muster wie statusapi/mailapi):
ai/internal/semanticsearchapi: ai.search.read (aus Migration 0018) wird nach der Service-Token-Prüfung für den Mandanten aus dem Anfragekörper (tenant_slug) gegen Core POST /authorize geprüft.
workflow/internal/taskapi: neu workflow.task.read (GET /tasks) und workflow.task.write (PATCH /tasks/{id}/status), geprüft nach Identitäts- und Tenant-Check. Das Paket war bisher in cmd/workflow-app gar nicht verdrahtet (nur im tasks-a11y-fixture); es ist jetzt in buildMux registriert und liegt damit hinter bearerauth.
connect/internal/connectorsetupapi: neu connect.setup.read (Katalog, Verbindungsliste, Mapping lesen) und connect.setup.write (Verbindung/Mapping speichern).
migrations/0029_task_setup_policy_rules.{up,down}.sql: vier neue Rechte je für user und tenant_admin, Muster 0018 (nächste freie Nummer nach 0028).
Wiring (Muster NEXARCH_DMS_APP_POLICY_*): NEXARCH_AI_APP_POLICY_URL/_POLICY_SERVICE_TOKEN, NEXARCH_WORKFLOW_APP_POLICY_URL/_POLICY_SERVICE_TOKEN, NEXARCH_CONNECT_APP_POLICY_URL/_POLICY_SERVICE_TOKEN. In connect-app wird damit auch die bereits vorhandene, bisher nie verdrahtete statusapi.WithPolicy-Prüfung (connect.status.read) scharf.
Frontend: MODULE_REGISTRY um ai_search_chat (3115), workflow_tasks (3116), connect_setup (3117) ergänzt, Icons in web/portal/app/moduleIcons.tsx, Rechteliste in web/portal/lib/modules.test.ts.
Alle drei Module nutzen common/policyclient (POST /authorize, X-Service-Token). Der Client ist fail-closed: Fehler/Nicht-200/Antwort ohne allowed → false, err; die Handler antworten dann mit 503, bei allowed=false mit 403.
Die Verdrahtung ist wie bei DMS/Mail/Connect-Status opt-in per Env: ohne *_POLICY_URL startet der Dienst mit Warnung im Log und ohne Prüfung (Übergang, damit Bestandsinstallationen ohne policy-api nicht ausfallen). URL ohne Token ist ein Startfehler.
Identität: taskapi liest X-User-Id/X-Tenant-Slug, die bearerauth in workflow-app aus den Token-Claims setzt. connectorsetupapi nutzt X-User-Id/X-Tenant-Slug ohne Token-Prüfung (bekannt, nicht Teil dieser Aufgabe). semanticsearchapi ist Modul-zu-Modul (Service-Token), der Mandant kommt aus dem Body.
Rolle ist in allen drei Diensten fest user (wie statusapi): bearerauth reicht Role aus den Claims nicht durch, Connect/AI haben keine Nutzerrolle. Deshalb sind die neuen Rechte für userundtenant_admin angelegt; eine Rollendifferenzierung (z. B. connect.setup.write nur für Admins) ist erst sinnvoll, wenn die Rolle ankommt — eigenes Ticket.
(b) Aufrufer
web/workflow-tasks (Bearer oder userId/tenant-Query), web/connect-setup (NEXT_PUBLIC_USER_ID/_TENANT_SLUG-Header), web/ai-search-chat (Service-Token + EXAMPLE_TENANT_SLUG) senden weiterhin genau das, was die Handler brauchen; die Prüfung kommt serverseitig dazu, keine Frontend-Änderung nötig.
Fixtures cmd/tasks-a11y-fixture, cmd/setup-a11y-fixture, cmd/searchchatapi-a11y-fixture rufen NewServer(...) ohne WithPolicy auf und laufen unverändert (keine Prüfung, wie bisher) — nichts abgeschwächt, nur nicht verdrahtet; sie sind Wegwerf-Testbinaries.
Bestehende Tests der drei Pakete laufen unverändert durch (policy == nil ⇒ bisheriges Verhalten).
(c) Wiring
Keines der drei cmd/*-app hatte einen policyclient; jetzt minimal nach dem DMS-Muster verdrahtet, Env-Variablen in docs/BETRIEB-PORTAL.md und ENG-11 genannt.
Auswirkung / Deploy
Reihenfolge: Migration 0029 auf der Core-DB (policy-api) vor dem Binary-Rollout, sonst antwortet Core für workflow.task.*/connect.setup.* mit allowed=false → 403 in Aufgabenboard und Connect-Setup, sobald *_POLICY_URL gesetzt ist. ai.search.read existiert seit 0018.
Bestands-Mandanten: policy_rules ist mandantenübergreifend (Rolle→Recht); user/tenant_admin erhalten die neuen Rechte sofort, keine Daten-Migration je Mandant. Down-Migration entfernt genau die von 0029 angelegten Zeilen (granted_by).
Ohne gesetzte *_POLICY_URL ändert sich das Laufzeitverhalten nicht (nur eine Warnung im Log). Mit URL: Core nicht erreichbar → 503.
workflow-app beantwortet neu GET /tasks und PATCH /tasks/{id}/status (bisher 404); web/workflow-tasks mit WORKFLOW_TASKS_API_URL auf 9600 funktioniert damit erstmals gegen das echte Binary.
Tests (Host 131 Scratch /root/scratch-i369, DB-Tests gegen dms_dev auf 204, beide Scratch-Verzeichnisse danach gelöscht)
go vet ai/workflow/connect (cmd + geänderte Pakete): sauber; gofmt -l: sauber.
Go ohne DB (131): ai cmd/ai-app, internal/semanticsearchapi, internal/pflichttestgate ok; workflow cmd/workflow-app, internal/taskapi, internal/pflichttestgate ok; connect internal/connectorsetupapi, internal/statusapi ok.
Go mit TEST_TENANT_DSN (204, dms_dev): workflow 13 PASS / 0 SKIP (inkl. TestBuildMux_AllPackagesAnswer mit neuem /tasks-Check und TestHandleList_PolicyAllows_Passes), connect 16 PASS / 0 SKIP, ai 14 PASS / 0 SKIP.
Neue Policy-Tests: semanticsearchapi 4, taskapi 5, connectorsetupapi 5 (403 bei Ablehnung mit Prüfung von permission/tenant im Core-Request, 200 bei Freigabe, 503 bei Ausfall, keine Policy-Abfrage ohne Identität/Service-Token, Ablehnung vor jedem Store-Zugriff).
Migration 0029: auf 204 in einer zurückgerollten Transaktion gegen das 0003-Schema geprüft: up → 8 policy_rules + 8 policy_rule_changes, zweites up idempotent (8), down → 0.
Pflichttest-Gates (Core, AI, Workflow, Mail) mit der Änderungsliste: alle bestanden.
web/shltsc --noEmit: 3 Fehler Cannot find name 'process' in ModuleNavShell.tsx — vorbestehend auf main (Zeilen 122/123 dort identisch, @types/node fehlt im shl-Setup), nicht Teil dieser Änderung.
Nicht geprüft / Annahmen
Kein next build der drei Apps und kein Ende-zu-Ende-Lauf mit laufender policy-api (Dienste auf 131/204 nicht gestartet).
Layout-Einbindung von ModuleNavShell in die drei Apps (wie bei mail_postfach in #368) bewusst nicht gemacht — das Issue verlangt nur den Registry-Eintrag.
Ports 3115–3117 für die drei Apps angenommen (nächste freie nach 3114), nicht in deploy/ports.tsv hinterlegt (dort sind Web-Apps nicht geführt).
Schließt #369.
## Änderung
**Backends (serverseitige Rechteprüfung vor jeder Verarbeitung, `requirePermission`-Muster wie `statusapi`/`mailapi`):**
- `ai/internal/semanticsearchapi`: `ai.search.read` (aus Migration 0018) wird nach der Service-Token-Prüfung für den Mandanten aus dem Anfragekörper (`tenant_slug`) gegen Core `POST /authorize` geprüft.
- `workflow/internal/taskapi`: neu `workflow.task.read` (`GET /tasks`) und `workflow.task.write` (`PATCH /tasks/{id}/status`), geprüft nach Identitäts- und Tenant-Check. **Das Paket war bisher in `cmd/workflow-app` gar nicht verdrahtet** (nur im `tasks-a11y-fixture`); es ist jetzt in `buildMux` registriert und liegt damit hinter `bearerauth`.
- `connect/internal/connectorsetupapi`: neu `connect.setup.read` (Katalog, Verbindungsliste, Mapping lesen) und `connect.setup.write` (Verbindung/Mapping speichern).
- `migrations/0029_task_setup_policy_rules.{up,down}.sql`: vier neue Rechte je für `user` und `tenant_admin`, Muster 0018 (nächste freie Nummer nach 0028).
- Wiring (Muster `NEXARCH_DMS_APP_POLICY_*`): `NEXARCH_AI_APP_POLICY_URL`/`_POLICY_SERVICE_TOKEN`, `NEXARCH_WORKFLOW_APP_POLICY_URL`/`_POLICY_SERVICE_TOKEN`, `NEXARCH_CONNECT_APP_POLICY_URL`/`_POLICY_SERVICE_TOKEN`. In `connect-app` wird damit auch die bereits vorhandene, bisher nie verdrahtete `statusapi.WithPolicy`-Prüfung (`connect.status.read`) scharf.
- Frontend: `MODULE_REGISTRY` um `ai_search_chat` (3115), `workflow_tasks` (3116), `connect_setup` (3117) ergänzt, Icons in `web/portal/app/moduleIcons.tsx`, Rechteliste in `web/portal/lib/modules.test.ts`.
- Doku: `docs/BETRIEB-PORTAL.md` (neuer Abschnitt), `workflow/docs/ENG-11-PRUEFPROTOKOLL.md` (Umgebungsvariablen).
## Vorab-Prüfung (laut Auftrag)
**(a) Policy-Abfrage und Identität**
- Alle drei Module nutzen `common/policyclient` (`POST /authorize`, `X-Service-Token`). Der Client ist fail-closed: Fehler/Nicht-200/Antwort ohne `allowed` → `false, err`; die Handler antworten dann mit 503, bei `allowed=false` mit 403.
- Die Verdrahtung ist wie bei DMS/Mail/Connect-Status opt-in per Env: ohne `*_POLICY_URL` startet der Dienst mit **Warnung im Log und ohne Prüfung** (Übergang, damit Bestandsinstallationen ohne policy-api nicht ausfallen). URL ohne Token ist ein Startfehler.
- Identität: `taskapi` liest `X-User-Id`/`X-Tenant-Slug`, die `bearerauth` in `workflow-app` aus den Token-Claims setzt. `connectorsetupapi` nutzt `X-User-Id`/`X-Tenant-Slug` ohne Token-Prüfung (bekannt, nicht Teil dieser Aufgabe). `semanticsearchapi` ist Modul-zu-Modul (Service-Token), der Mandant kommt aus dem Body.
- **Rolle ist in allen drei Diensten fest `user`** (wie `statusapi`): `bearerauth` reicht `Role` aus den Claims nicht durch, Connect/AI haben keine Nutzerrolle. Deshalb sind die neuen Rechte für `user` **und** `tenant_admin` angelegt; eine Rollendifferenzierung (z. B. `connect.setup.write` nur für Admins) ist erst sinnvoll, wenn die Rolle ankommt — eigenes Ticket.
**(b) Aufrufer**
- `web/workflow-tasks` (Bearer oder `userId`/`tenant`-Query), `web/connect-setup` (`NEXT_PUBLIC_USER_ID`/`_TENANT_SLUG`-Header), `web/ai-search-chat` (Service-Token + `EXAMPLE_TENANT_SLUG`) senden weiterhin genau das, was die Handler brauchen; die Prüfung kommt serverseitig dazu, keine Frontend-Änderung nötig.
- Fixtures `cmd/tasks-a11y-fixture`, `cmd/setup-a11y-fixture`, `cmd/searchchatapi-a11y-fixture` rufen `NewServer(...)` ohne `WithPolicy` auf und laufen unverändert (keine Prüfung, wie bisher) — nichts abgeschwächt, nur nicht verdrahtet; sie sind Wegwerf-Testbinaries.
- Bestehende Tests der drei Pakete laufen unverändert durch (`policy == nil` ⇒ bisheriges Verhalten).
**(c) Wiring**
- Keines der drei `cmd/*-app` hatte einen policyclient; jetzt minimal nach dem DMS-Muster verdrahtet, Env-Variablen in `docs/BETRIEB-PORTAL.md` und `ENG-11` genannt.
## Auswirkung / Deploy
- **Reihenfolge: Migration 0029 auf der Core-DB (policy-api) vor dem Binary-Rollout**, sonst antwortet Core für `workflow.task.*`/`connect.setup.*` mit `allowed=false` → 403 in Aufgabenboard und Connect-Setup, sobald `*_POLICY_URL` gesetzt ist. `ai.search.read` existiert seit 0018.
- Bestands-Mandanten: `policy_rules` ist mandantenübergreifend (Rolle→Recht); `user`/`tenant_admin` erhalten die neuen Rechte sofort, keine Daten-Migration je Mandant. Down-Migration entfernt genau die von 0029 angelegten Zeilen (`granted_by`).
- Ohne gesetzte `*_POLICY_URL` ändert sich das Laufzeitverhalten nicht (nur eine Warnung im Log). Mit URL: Core nicht erreichbar → 503.
- `workflow-app` beantwortet neu `GET /tasks` und `PATCH /tasks/{id}/status` (bisher 404); `web/workflow-tasks` mit `WORKFLOW_TASKS_API_URL` auf 9600 funktioniert damit erstmals gegen das echte Binary.
## Tests (Host 131 Scratch `/root/scratch-i369`, DB-Tests gegen `dms_dev` auf 204, beide Scratch-Verzeichnisse danach gelöscht)
- `go vet` ai/workflow/connect (cmd + geänderte Pakete): sauber; `gofmt -l`: sauber.
- Go ohne DB (131): ai `cmd/ai-app`, `internal/semanticsearchapi`, `internal/pflichttestgate` ok; workflow `cmd/workflow-app`, `internal/taskapi`, `internal/pflichttestgate` ok; connect `internal/connectorsetupapi`, `internal/statusapi` ok.
- Go mit `TEST_TENANT_DSN` (204, dms_dev): workflow 13 PASS / 0 SKIP (inkl. `TestBuildMux_AllPackagesAnswer` mit neuem `/tasks`-Check und `TestHandleList_PolicyAllows_Passes`), connect 16 PASS / 0 SKIP, ai 14 PASS / 0 SKIP.
- Neue Policy-Tests: semanticsearchapi 4, taskapi 5, connectorsetupapi 5 (403 bei Ablehnung mit Prüfung von `permission`/`tenant` im Core-Request, 200 bei Freigabe, 503 bei Ausfall, keine Policy-Abfrage ohne Identität/Service-Token, Ablehnung vor jedem Store-Zugriff).
- Migration 0029: auf 204 in einer zurückgerollten Transaktion gegen das 0003-Schema geprüft: up → 8 `policy_rules` + 8 `policy_rule_changes`, zweites up idempotent (8), down → 0.
- Pflichttest-Gates (Core, AI, Workflow, Mail) mit der Änderungsliste: alle bestanden.
- Frontend (131): `web/shl` vitest 68/68, `web/portal` vitest 72/72 (inkl. Rechteliste, eindeutige Keys, Icon je Modul).
- `web/shl` `tsc --noEmit`: 3 Fehler `Cannot find name 'process'` in `ModuleNavShell.tsx` — **vorbestehend auf `main`** (Zeilen 122/123 dort identisch, `@types/node` fehlt im shl-Setup), nicht Teil dieser Änderung.
## Nicht geprüft / Annahmen
- Kein `next build` der drei Apps und kein Ende-zu-Ende-Lauf mit laufender policy-api (Dienste auf 131/204 nicht gestartet).
- Layout-Einbindung von `ModuleNavShell` in die drei Apps (wie bei `mail_postfach` in #368) bewusst nicht gemacht — das Issue verlangt nur den Registry-Eintrag.
- Ports 3115–3117 für die drei Apps angenommen (nächste freie nach 3114), nicht in `deploy/ports.tsv` hinterlegt (dort sind Web-Apps nicht geführt).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
- semanticsearchapi: ai.search.read per policyclient (WithPolicy), Tenant aus
dem Anfragekoerper, nach Service-Token-Pruefung
- taskapi: workflow.task.read (GET /tasks) und workflow.task.write (PATCH
status); Paket jetzt in cmd/workflow-app verdrahtet (lag bisher nur im
a11y-Fixture) und damit hinter bearerauth
- connectorsetupapi: connect.setup.read/write je Route
- Migration 0029 (up/down): neue Rechte fuer user und tenant_admin
- Wiring: NEXARCH_{AI,WORKFLOW,CONNECT}_APP_POLICY_URL/_POLICY_SERVICE_TOKEN;
ohne URL Warnung und keine Pruefung (Uebergang), URL ohne Token Startfehler;
connect-app setzt die bestehende statusapi-Pruefung damit ebenfalls scharf
- Tests je API: 403 bei Ablehnung, 200 bei Freigabe, 503 bei Ausfall, Policy
wird ohne Identitaet/Service-Token nicht befragt
- MODULE_REGISTRY: ai_search_chat, workflow_tasks, connect_setup (+ Icons,
Portal-Rechteliste)
- Doku: BETRIEB-PORTAL.md, ENG-11 Umgebungsvariablen
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Schließt #369.
Änderung
Backends (serverseitige Rechteprüfung vor jeder Verarbeitung,
requirePermission-Muster wiestatusapi/mailapi):ai/internal/semanticsearchapi:ai.search.read(aus Migration 0018) wird nach der Service-Token-Prüfung für den Mandanten aus dem Anfragekörper (tenant_slug) gegen CorePOST /authorizegeprüft.workflow/internal/taskapi: neuworkflow.task.read(GET /tasks) undworkflow.task.write(PATCH /tasks/{id}/status), geprüft nach Identitäts- und Tenant-Check. Das Paket war bisher incmd/workflow-appgar nicht verdrahtet (nur imtasks-a11y-fixture); es ist jetzt inbuildMuxregistriert und liegt damit hinterbearerauth.connect/internal/connectorsetupapi: neuconnect.setup.read(Katalog, Verbindungsliste, Mapping lesen) undconnect.setup.write(Verbindung/Mapping speichern).migrations/0029_task_setup_policy_rules.{up,down}.sql: vier neue Rechte je füruserundtenant_admin, Muster 0018 (nächste freie Nummer nach 0028).NEXARCH_DMS_APP_POLICY_*):NEXARCH_AI_APP_POLICY_URL/_POLICY_SERVICE_TOKEN,NEXARCH_WORKFLOW_APP_POLICY_URL/_POLICY_SERVICE_TOKEN,NEXARCH_CONNECT_APP_POLICY_URL/_POLICY_SERVICE_TOKEN. Inconnect-appwird damit auch die bereits vorhandene, bisher nie verdrahtetestatusapi.WithPolicy-Prüfung (connect.status.read) scharf.MODULE_REGISTRYumai_search_chat(3115),workflow_tasks(3116),connect_setup(3117) ergänzt, Icons inweb/portal/app/moduleIcons.tsx, Rechteliste inweb/portal/lib/modules.test.ts.docs/BETRIEB-PORTAL.md(neuer Abschnitt),workflow/docs/ENG-11-PRUEFPROTOKOLL.md(Umgebungsvariablen).Vorab-Prüfung (laut Auftrag)
(a) Policy-Abfrage und Identität
common/policyclient(POST /authorize,X-Service-Token). Der Client ist fail-closed: Fehler/Nicht-200/Antwort ohneallowed→false, err; die Handler antworten dann mit 503, beiallowed=falsemit 403.*_POLICY_URLstartet der Dienst mit Warnung im Log und ohne Prüfung (Übergang, damit Bestandsinstallationen ohne policy-api nicht ausfallen). URL ohne Token ist ein Startfehler.taskapiliestX-User-Id/X-Tenant-Slug, diebearerauthinworkflow-appaus den Token-Claims setzt.connectorsetupapinutztX-User-Id/X-Tenant-Slugohne Token-Prüfung (bekannt, nicht Teil dieser Aufgabe).semanticsearchapiist Modul-zu-Modul (Service-Token), der Mandant kommt aus dem Body.user(wiestatusapi):bearerauthreichtRoleaus den Claims nicht durch, Connect/AI haben keine Nutzerrolle. Deshalb sind die neuen Rechte füruserundtenant_adminangelegt; eine Rollendifferenzierung (z. B.connect.setup.writenur für Admins) ist erst sinnvoll, wenn die Rolle ankommt — eigenes Ticket.(b) Aufrufer
web/workflow-tasks(Bearer oderuserId/tenant-Query),web/connect-setup(NEXT_PUBLIC_USER_ID/_TENANT_SLUG-Header),web/ai-search-chat(Service-Token +EXAMPLE_TENANT_SLUG) senden weiterhin genau das, was die Handler brauchen; die Prüfung kommt serverseitig dazu, keine Frontend-Änderung nötig.cmd/tasks-a11y-fixture,cmd/setup-a11y-fixture,cmd/searchchatapi-a11y-fixturerufenNewServer(...)ohneWithPolicyauf und laufen unverändert (keine Prüfung, wie bisher) — nichts abgeschwächt, nur nicht verdrahtet; sie sind Wegwerf-Testbinaries.policy == nil⇒ bisheriges Verhalten).(c) Wiring
cmd/*-apphatte einen policyclient; jetzt minimal nach dem DMS-Muster verdrahtet, Env-Variablen indocs/BETRIEB-PORTAL.mdundENG-11genannt.Auswirkung / Deploy
workflow.task.*/connect.setup.*mitallowed=false→ 403 in Aufgabenboard und Connect-Setup, sobald*_POLICY_URLgesetzt ist.ai.search.readexistiert seit 0018.policy_rulesist mandantenübergreifend (Rolle→Recht);user/tenant_adminerhalten die neuen Rechte sofort, keine Daten-Migration je Mandant. Down-Migration entfernt genau die von 0029 angelegten Zeilen (granted_by).*_POLICY_URLändert sich das Laufzeitverhalten nicht (nur eine Warnung im Log). Mit URL: Core nicht erreichbar → 503.workflow-appbeantwortet neuGET /tasksundPATCH /tasks/{id}/status(bisher 404);web/workflow-tasksmitWORKFLOW_TASKS_API_URLauf 9600 funktioniert damit erstmals gegen das echte Binary.Tests (Host 131 Scratch
/root/scratch-i369, DB-Tests gegendms_devauf 204, beide Scratch-Verzeichnisse danach gelöscht)go vetai/workflow/connect (cmd + geänderte Pakete): sauber;gofmt -l: sauber.cmd/ai-app,internal/semanticsearchapi,internal/pflichttestgateok; workflowcmd/workflow-app,internal/taskapi,internal/pflichttestgateok; connectinternal/connectorsetupapi,internal/statusapiok.TEST_TENANT_DSN(204, dms_dev): workflow 13 PASS / 0 SKIP (inkl.TestBuildMux_AllPackagesAnswermit neuem/tasks-Check undTestHandleList_PolicyAllows_Passes), connect 16 PASS / 0 SKIP, ai 14 PASS / 0 SKIP.permission/tenantim Core-Request, 200 bei Freigabe, 503 bei Ausfall, keine Policy-Abfrage ohne Identität/Service-Token, Ablehnung vor jedem Store-Zugriff).policy_rules+ 8policy_rule_changes, zweites up idempotent (8), down → 0.web/shlvitest 68/68,web/portalvitest 72/72 (inkl. Rechteliste, eindeutige Keys, Icon je Modul).web/shltsc --noEmit: 3 FehlerCannot find name 'process'inModuleNavShell.tsx— vorbestehend aufmain(Zeilen 122/123 dort identisch,@types/nodefehlt im shl-Setup), nicht Teil dieser Änderung.Nicht geprüft / Annahmen
next buildder drei Apps und kein Ende-zu-Ende-Lauf mit laufender policy-api (Dienste auf 131/204 nicht gestartet).ModuleNavShellin die drei Apps (wie beimail_postfachin #368) bewusst nicht gemacht — das Issue verlangt nur den Registry-Eintrag.deploy/ports.tsvhinterlegt (dort sind Web-Apps nicht geführt).🤖 Generated with Claude Code
- semanticsearchapi: ai.search.read per policyclient (WithPolicy), Tenant aus dem Anfragekoerper, nach Service-Token-Pruefung - taskapi: workflow.task.read (GET /tasks) und workflow.task.write (PATCH status); Paket jetzt in cmd/workflow-app verdrahtet (lag bisher nur im a11y-Fixture) und damit hinter bearerauth - connectorsetupapi: connect.setup.read/write je Route - Migration 0029 (up/down): neue Rechte fuer user und tenant_admin - Wiring: NEXARCH_{AI,WORKFLOW,CONNECT}_APP_POLICY_URL/_POLICY_SERVICE_TOKEN; ohne URL Warnung und keine Pruefung (Uebergang), URL ohne Token Startfehler; connect-app setzt die bestehende statusapi-Pruefung damit ebenfalls scharf - Tests je API: 403 bei Ablehnung, 200 bei Freigabe, 503 bei Ausfall, Policy wird ohne Identitaet/Service-Token nicht befragt - MODULE_REGISTRY: ai_search_chat, workflow_tasks, connect_setup (+ Icons, Portal-Rechteliste) - Doku: BETRIEB-PORTAL.md, ENG-11 Umgebungsvariablen Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>