diff --git a/.gitignore b/.gitignore index 03f14e9..e28346a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,10 @@ composer.phar config/config.php .env +# Agent workflow runs (ephemeral artifacts) +/.agents/runs/* +!/.agents/runs/.gitkeep + # Runtime & generated /web/debugger/ /data/ diff --git a/bin/codex-skills-sync.sh b/bin/codex-skills-sync.sh index f76bcfa..1eb73b8 100755 --- a/bin/codex-skills-sync.sh +++ b/bin/codex-skills-sync.sh @@ -44,7 +44,7 @@ fi script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" repo_root="$(cd -- "${script_dir}/.." && pwd)" -source_dir="${repo_root}/tools/codex-skills" +source_dir="${repo_root}/.agents/skills" codex_home_dir="${CODEX_HOME:-${HOME}/.codex}" target_dir="${codex_home_dir}/skills" managed_skills=( diff --git a/bin/docs-link-check.sh b/bin/docs-link-check.sh index 904ab68..781a391 100755 --- a/bin/docs-link-check.sh +++ b/bin/docs-link-check.sh @@ -9,9 +9,9 @@ tmp_file="$(mktemp)" trap 'rm -f "${tmp_file}"' EXIT rg -n -o '(?:/docs|docs)/[a-z0-9_/-]+\.md' \ - README.md docs tools/codex-skills agent-system \ + README.md docs .agents \ -g '*.md' \ - -g '!agent-system/runs/**' \ + -g '!.agents/runs/**' \ > "${tmp_file}" || true missing=0 @@ -33,4 +33,4 @@ if [[ ${missing} -ne 0 ]]; then exit 1 fi -echo "[OK] docs links resolve (agent-system/runs/** excluded by default)" +echo "[OK] docs links resolve (.agents/runs/** excluded by default)" diff --git a/docs/reference-agents-flow.md b/docs/reference-agents-flow.md deleted file mode 100644 index 0afb5a6..0000000 --- a/docs/reference-agents-flow.md +++ /dev/null @@ -1,42 +0,0 @@ -# Agent Workflow - -Letzte Aktualisierung: 2026-03-06 - -## State Machine -- `planned` -- `executing` -- `review_guard` -- `review_acceptance` -- `finalize` -- `done` - -If a reviewer returns `FAIL`, state goes back to `executing` with explicit findings. - -## Minimum Handover Artifacts -- Planner: `plan.json` -- Executor: `execution-report.json` -- Reviewer Guards: `review-guards.json` -- Reviewer Acceptance: `review-acceptance.json` -- Finalizer: `finalize.json` - -## Guard and Gate Binding -- Planner selects required guard IDs from `agent-system/checks/guard-catalog.json`. -- Planner selects required quality gate IDs from `agent-system/checks/quality-gates.json`. -- Planner assigns stable success criteria IDs (`SC-*`) in `plan.json`. -- Executor must provide guard evidence and gate results by ID. -- Guard reviewer verifies and reports verdict against the same IDs. -- Acceptance reviewer verifies and reports verdict against the same `SC-*` IDs. - -## Fail Loop Rule -- No free-text "please improve". -- Every fail must include: - - `id` - - `severity` - - `file` - - expected fix - -## Practical Rollout -- Start with one small issue. -- Run workflow manually with templates. -- Stabilize contracts first. -- Add automation only after 3 to 5 successful runs. diff --git a/docs/reference-agents-overview.md b/docs/reference-agents-overview.md deleted file mode 100644 index 4ab4846..0000000 --- a/docs/reference-agents-overview.md +++ /dev/null @@ -1,29 +0,0 @@ -# Agent Workflow Overview - -Letzte Aktualisierung: 2026-03-09 - -This project uses a multi-role workflow for issue and feature delivery. - -Roles: -- Planner -- Executor -- Reviewer (guards and best practices) -- Reviewer (feature acceptance) -- Finalizer - -Primary goals: -- predictable handovers -- strict quality gates -- fast retry loop from reviewers back to executor -- explicit guard and gate IDs (`GR-*`, `QG-*`) across all roles - -Source of truth: -- guardrails and planning standards in `tools/codex-skills/` -- contracts and templates in `agent-system/` -- guard catalog: `agent-system/checks/guard-catalog.json` -- quality gates: `agent-system/checks/quality-gates.json` - -Entry points: -- roles: `/docs/reference-agents-roles.md` -- workflow: `/docs/reference-agents-flow.md` -- schemas and prompts: `agent-system/` diff --git a/docs/reference-agents-roles.md b/docs/reference-agents-roles.md deleted file mode 100644 index 3e024a3..0000000 --- a/docs/reference-agents-roles.md +++ /dev/null @@ -1,49 +0,0 @@ -# Agent Roles - -Letzte Aktualisierung: 2026-03-06 - -## Planner -- Input: issue or feature request -- Output: `plan.json` (see `agent-system/contracts/planner.schema.json`) -- Must define: - - scope in and out - - required guard IDs (`GR-*`) - - required quality gate IDs (`QG-*`) - - success criteria with stable IDs (`SC-*`) - - implementation steps - - test and acceptance checks - - risks and mitigations - -## Executor -- Input: approved `plan.json` -- Output: `execution-report.json` -- Must: - - implement the plan - - run relevant checks - - document changed files and commands - -## Reviewer Guards -- Input: code diff and `execution-report.json` -- Output: `review-guards.json` -- Focus: - - architecture boundaries - - security - - coding standards - - guardrail compliance - - explicit validation against required `GR-*` and `QG-*` IDs - -## Reviewer Acceptance -- Input: code diff and plan success criteria -- Output: `review-acceptance.json` -- Focus: - - feature correctness - - edge cases - - acceptance criteria coverage - - explicit check mapping by `SC-*` criterion IDs from `plan.json` - -## Finalizer -- Input: both review files with PASS verdict -- Output: `finalize.json` -- Must: - - verify gates are green - - prepare merge and commit metadata diff --git a/tests/Architecture/FilterDrawerContractTest.php b/tests/Architecture/FilterDrawerContractTest.php deleted file mode 100644 index baa3767..0000000 --- a/tests/Architecture/FilterDrawerContractTest.php +++ /dev/null @@ -1,126 +0,0 @@ -readProjectFile($templateFile); - $matched = preg_match( - "/assetVersion\\('((?:modules\\/[^\\/]+\\/)?js\\/pages\\/[^']+\\.js)'\\)/", - $template, - $captures - ); - $this->assertSame(1, $matched, $templateFile . ' must reference a page module via assetVersion().'); - - return $this->readProjectFile('web/' . ltrim($captures[1], '/')); - } - - private function usesSharedListFiltersPartial(string $content): bool - { - return str_contains($content, "require templatePath('partials/app-list-filters.phtml');"); - } - - /** - * @return list - */ - private function drawerTemplateFiles(): array - { - return [ - 'modules/addressbook/pages/address-book/index(default).phtml', - 'pages/admin/users/index(default).phtml', - 'pages/admin/tenants/index(default).phtml', - 'pages/admin/departments/index(default).phtml', - 'pages/admin/roles/index(default).phtml', - 'pages/admin/permissions/index(default).phtml', - 'pages/admin/mail-log/index(default).phtml', - 'pages/admin/scheduled-jobs/index(default).phtml', - 'pages/admin/api-audit/index(default).phtml', - 'pages/admin/import-audit/index(default).phtml', - 'pages/admin/user-lifecycle-audit/index(default).phtml', - 'pages/admin/system-audit/index(default).phtml', - ]; - } - - public function testDrawerTemplatesUseStandardListWrapperForFilterExperience(): void - { - foreach ($this->drawerTemplateFiles() as $file) { - $content = $this->readProjectFile($file); - $moduleContent = $this->readTemplatePageModule($file); - $usesPartial = $this->usesSharedListFiltersPartial($content); - $this->assertStringContainsString('initStandardListPage(', $moduleContent, $file); - $this->assertStringContainsString("mode: 'drawer'", $moduleContent, $file); - $this->assertStringNotContainsString('initListFilterExperience(', $moduleContent, $file); - if (!$usesPartial) { - $this->assertStringContainsString('role="dialog"', $content, $file); - $this->assertStringContainsString('aria-modal="true"', $content, $file); - $this->assertStringContainsString('aria-labelledby="', $content, $file); - $this->assertStringContainsString('data-filter-live-region', $content, $file); - } - $this->assertStringNotContainsString('data-filter-drawer-draft-hint', $content, $file); - } - } - - public function testAddressBookFilterChipsContract(): void - { - $content = $this->readProjectFile('modules/addressbook/pages/address-book/index(default).phtml'); - $moduleContent = $this->readProjectFile('modules/addressbook/web/js/pages/address-book-index.js'); - - $this->assertStringNotContainsString('const state = collectFilterState();', $moduleContent); - $this->assertStringContainsString('data-filter-chips-clear-all-label', $content); - $this->assertStringContainsString('data-filter-chips-remove-label', $content); - $this->assertStringContainsString('data-filter-live-applied-message', $content); - $this->assertStringContainsString('data-filter-live-removed-message', $content); - $this->assertStringContainsString('data-filter-live-cleared-message', $content); - } - - public function testUsersResetKeepsTenantParam(): void - { - $moduleContent = $this->readProjectFile('web/js/pages/admin-users-index.js'); - $this->assertStringContainsString("preserveFilterParams: ['tenant']", $moduleContent); - } - - public function testFilterDrawerAndExperienceImplementFocusTrapAndDirtyApplyUi(): void - { - $drawerJs = $this->readProjectFile('web/js/components/app-filter-drawer.js'); - $this->assertStringContainsString("drawer.setAttribute('role', 'dialog')", $drawerJs); - $this->assertStringContainsString("drawer.setAttribute('aria-modal', 'true')", $drawerJs); - $this->assertStringContainsString("if (event.key !== 'Tab') {return;}", $drawerJs); - $this->assertStringContainsString('if (lastTrigger && typeof lastTrigger.focus === \'function\'', $drawerJs); - - $experienceJs = $this->readProjectFile('web/js/pages/app-list-filter-experience.js'); - $this->assertStringContainsString('countDraftChanges(', $experienceJs); - $this->assertStringContainsString('countActiveDraftFilters(', $experienceJs); - $this->assertStringContainsString('drawerController.setApplyEnabled(changedCount > 0);', $experienceJs); - $this->assertStringContainsString('drawerController.setApplyCount(activeCount);', $experienceJs); - $this->assertStringContainsString('announceLive(', $experienceJs); - - $stateJs = $this->readProjectFile('web/js/pages/app-list-filter-state.js'); - $this->assertStringContainsString('buildChipsFromMeta', $stateJs); - $this->assertStringContainsString('removeChipFromMetaState', $stateJs); - $this->assertStringContainsString('clearMetaState', $stateJs); - } - - public function testSharedListFiltersPartialKeepsDrawerAccessibilityContract(): void - { - $content = $this->readProjectFile('templates/partials/app-list-filters.phtml'); - $this->assertStringContainsString('renderGridFilterToolbar(', $content); - $this->assertStringContainsString('data-filter-drawer-open', $content); - $this->assertStringContainsString('data-filter-drawer-apply', $content); - $this->assertStringContainsString('data-active-filter-chips', $content); - $this->assertStringContainsString('data-filter-chips-clear-all-label', $content); - $this->assertStringContainsString('data-filter-chips-remove-label', $content); - $this->assertStringContainsString('role="dialog"', $content); - $this->assertStringContainsString('aria-modal="true"', $content); - $this->assertStringContainsString('aria-labelledby=', $content); - $this->assertStringContainsString('data-filter-live-region', $content); - $this->assertStringContainsString('data-filter-live-applied-message', $content); - $this->assertStringContainsString('data-filter-live-removed-message', $content); - $this->assertStringContainsString('data-filter-live-cleared-message', $content); - } -} diff --git a/tests/Architecture/FilterDrawerRuntimeContractTest.php b/tests/Architecture/FilterDrawerRuntimeContractTest.php new file mode 100644 index 0000000..868be95 --- /dev/null +++ b/tests/Architecture/FilterDrawerRuntimeContractTest.php @@ -0,0 +1,37 @@ +readProjectFile('web/js/pages/admin-users-index.js'); + $this->assertStringContainsString("preserveFilterParams: ['tenant']", $moduleContent); + } + + public function testFilterDrawerAndExperienceImplementFocusTrapAndDirtyApplyUi(): void + { + $drawerJs = $this->readProjectFile('web/js/components/app-filter-drawer.js'); + $this->assertStringContainsString("drawer.setAttribute('role', 'dialog')", $drawerJs); + $this->assertStringContainsString("drawer.setAttribute('aria-modal', 'true')", $drawerJs); + $this->assertStringContainsString("if (event.key !== 'Tab') {return;}", $drawerJs); + $this->assertStringContainsString('if (lastTrigger && typeof lastTrigger.focus === \'function\'', $drawerJs); + + $experienceJs = $this->readProjectFile('web/js/pages/app-list-filter-experience.js'); + $this->assertStringContainsString('countDraftChanges(', $experienceJs); + $this->assertStringContainsString('countActiveDraftFilters(', $experienceJs); + $this->assertStringContainsString('drawerController.setApplyEnabled(changedCount > 0);', $experienceJs); + $this->assertStringContainsString('drawerController.setApplyCount(activeCount);', $experienceJs); + $this->assertStringContainsString('announceLive(', $experienceJs); + + $stateJs = $this->readProjectFile('web/js/pages/app-list-filter-state.js'); + $this->assertStringContainsString('buildChipsFromMeta', $stateJs); + $this->assertStringContainsString('removeChipFromMetaState', $stateJs); + $this->assertStringContainsString('clearMetaState', $stateJs); + } +} diff --git a/tests/Architecture/FilterDrawerTemplateContractTest.php b/tests/Architecture/FilterDrawerTemplateContractTest.php new file mode 100644 index 0000000..974f78d --- /dev/null +++ b/tests/Architecture/FilterDrawerTemplateContractTest.php @@ -0,0 +1,59 @@ +drawerListTemplates() as $file) { + $content = $this->readProjectFile($file); + $usesPartial = $this->usesSharedListFiltersPartial($content); + + if (!$usesPartial) { + $this->assertStringContainsString('role="dialog"', $content, $file); + $this->assertStringContainsString('aria-modal="true"', $content, $file); + $this->assertStringContainsString('aria-labelledby="', $content, $file); + $this->assertStringContainsString('data-filter-live-region', $content, $file); + } + + $this->assertStringNotContainsString('data-filter-drawer-draft-hint', $content, $file); + } + } + + public function testAddressBookFilterChipsContract(): void + { + $content = $this->readProjectFile('modules/addressbook/pages/address-book/index(default).phtml'); + $moduleContent = $this->readProjectFile('modules/addressbook/web/js/pages/address-book-index.js'); + + $this->assertStringNotContainsString('const state = collectFilterState();', $moduleContent); + $this->assertStringContainsString('data-filter-chips-clear-all-label', $content); + $this->assertStringContainsString('data-filter-chips-remove-label', $content); + $this->assertStringContainsString('data-filter-live-applied-message', $content); + $this->assertStringContainsString('data-filter-live-removed-message', $content); + $this->assertStringContainsString('data-filter-live-cleared-message', $content); + } + + public function testSharedListFiltersPartialKeepsDrawerAccessibilityContract(): void + { + $content = $this->readProjectFile('templates/partials/app-list-filters.phtml'); + $this->assertStringContainsString('renderGridFilterToolbar(', $content); + $this->assertStringContainsString('data-filter-drawer-open', $content); + $this->assertStringContainsString('data-filter-drawer-apply', $content); + $this->assertStringContainsString('data-active-filter-chips', $content); + $this->assertStringContainsString('data-filter-chips-clear-all-label', $content); + $this->assertStringContainsString('data-filter-chips-remove-label', $content); + $this->assertStringContainsString('role="dialog"', $content); + $this->assertStringContainsString('aria-modal="true"', $content); + $this->assertStringContainsString('aria-labelledby=', $content); + $this->assertStringContainsString('data-filter-live-region', $content); + $this->assertStringContainsString('data-filter-live-applied-message', $content); + $this->assertStringContainsString('data-filter-live-removed-message', $content); + $this->assertStringContainsString('data-filter-live-cleared-message', $content); + } +} diff --git a/tools/codex-skills/core-guardrails/SKILL.md b/tools/codex-skills/core-guardrails/SKILL.md deleted file mode 100644 index a4d2ea3..0000000 --- a/tools/codex-skills/core-guardrails/SKILL.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -name: core-guardrails -description: Verbindliche Guardrails fuer Architektur-, Refactor-, Zentralisierungs-, Standardisierungs- und Implementierungsaufgaben in diesem Starterkit. Verwenden, wenn Code geaendert, neu strukturiert oder gegen bestehende Layer-/UI-/Security-Standards geprueft werden soll. ---- - -# Core Guardrails - -## Ziel - -Durchgaengig dieselben technischen Grenzen durchsetzen, damit Core robust, wartbar und vorhersagbar bleibt. - -## Verbindliche Regeln - -1. MUST Layering einhalten (`pages` -> `Service` -> `Repository`, Templates nur Rendering). -2. MUST Request/Input/Validation-Contract einhalten (`requestInput()`, `FormErrors`, API-Validation ueber `ApiResponse::validationFromFormErrors(...)`, kein `ApiResponse::readJsonBody(...)` in `pages/api/v1/**`, keine direkten Superglobals in `pages/**`). -3. MUST AuthZ/RBAC serverseitig durchsetzen und im UI nur ueber `$viewAuth` steuern. -4. MUST Security-Guards einhalten (CSRF auf POST-Endpunkten, keine unredacted PII/Secrets in Logs/Audit-Meta, SQL nur vorbereitet ueber Repository). -5. MUST UI-Standards und Data-Contracts fuer Listen/Detailseiten nutzen (Wrapper, Partials, globaler Confirm-Dialog statt `window.confirm`, inklusive globaler Grid-Standards fuer rowInteraction/pageSize). -6. MUST Frontend-Hardcuts einhalten (keine inline ESM-Module in Templates/Pages, JS-`src` mit `assetVersion(...)`, zentrale Telemetrie fuer relevante Frontend-Warnings/Fetch-Fehler). -7. MUST Quality-Gates ausfuehren und Ergebnis transparent berichten. -8. MUST bei Konflikten den regelkonformen Weg waehlen oder den Konflikt als Blocker markieren. -9. MUST NOT Extension-Architektur erfinden; dieses Thema ist aktuell Out of Scope. - -## Vorgehen je Aufgabe - -1. Scope bestimmen (`core`, `ui`, `api`, `mixed`). -2. Vorhandene Contracts zuerst suchen, dann wiederverwenden. -3. Aenderung minimal halten, keine Seiteneffekte ohne Grund. -4. Nach Aenderung die relevanten Gates ausfuehren. -5. Rest-Risiken explizit benennen. - -## Out of Scope - -- Extension-Mechanik (Ablageorte, Hooks, Lifecycle) wird hier nicht standardisiert. -- Fuer Extensions nur den Status "nicht definiert" dokumentieren, keine impliziten Regeln erfinden. - -## Referenzen - -- Core-Boundaries: `references/boundaries-core.md` -- UI-Boundaries: `references/boundaries-ui.md` -- Quality-Gates: `references/quality-gates.md` -- Source-Map zu Projekt-Doku: `references/source-map.md` diff --git a/tools/codex-skills/core-guardrails/references/boundaries-core.md b/tools/codex-skills/core-guardrails/references/boundaries-core.md deleted file mode 100644 index c0d20b1..0000000 --- a/tools/codex-skills/core-guardrails/references/boundaries-core.md +++ /dev/null @@ -1,45 +0,0 @@ -# Core Boundaries (MUST / MUST NOT) - -## Schichtgrenzen - -1. MUST SQL nur in `lib/Repository/**` halten. -2. MUST Business-Logik in `lib/Service/**` halten. -3. MUST `pages/**` auf Input, Auth/AuthZ, Orchestrierung, Response begrenzen. -4. MUST NOT Business- oder Permission-Logik in `templates/**` legen. - -## Instanziierung - -1. MUST in Actions/Helpern/Templates nur `app(Foo::class)` verwenden. -2. MUST NOT in `pages/**` direkt `new ...Service|Gateway|Repository` nutzen. -3. MUST NOT in `lib/Service/**` (ausser `*Factory.php`) direkt `new ...Factory|Service|Gateway|Repository` nutzen. -4. MUST NOT in `pages/admin/**` `Factory::class` referenzieren oder `app(...Factory::class)->create...` nutzen. - -## Input / Validation - -1. MUST Input in `pages/**` ueber `requestInput()` lesen. -2. MUST NOT `$_POST`, `$_GET`, `$_FILES`, `REQUEST_METHOD` in `pages/**` verwenden. -3. MUST NOT `$_SESSION`, `$_SERVER`, `$_COOKIE`, `$_ENV` in `pages/**` direkt verwenden. -4. MUST Form-Validation ueber `FormErrors` fuehren. -5. MUST API-Validation-Fehler ueber `ApiResponse::validationFromFormErrors(...)` ausgeben. -6. MUST NOT `ApiResponse::readJsonBody(...)` in `pages/api/v1/**` verwenden. - -## List-Data Endpoints - -1. MUST `pages/**/data().php` als GET-only Endpunkte umsetzen (`gridRequireGetRequest()`). -2. MUST Query-Filter ueber `gridParseFilters(...)` + `filter-schema.php` normalisieren. -3. MUST NOT Query-Filter inline/parallele Alias-Parser in `data().php` neu einfuehren. - -## Security / API - -1. MUST AuthZ serverseitig erzwingen. -2. MUST Tenant-Scope serverseitig erzwingen. -3. MUST CSRF auf POST-Endpunkten vor Body-Verarbeitung verifizieren. -4. MUST NOT PII/Secrets unredacted in Logs oder Audit-Metadata schreiben. -5. MUST SQL nur ueber Repository mit prepared statements ausfuehren. -6. MUST extern UUID-first bleiben. -7. MUST API-Fehler konsistent halten (`error`, optional `errors`). -8. MUST OpenAPI im selben Merge aktualisieren, wenn API geaendert wird. - -## Pruef-Hinweis - -- Harte Repo-Gates: `tests/Architecture/CoreStarterkitContractTest.php` diff --git a/tools/codex-skills/core-guardrails/references/boundaries-ui.md b/tools/codex-skills/core-guardrails/references/boundaries-ui.md deleted file mode 100644 index 5d8fd28..0000000 --- a/tools/codex-skills/core-guardrails/references/boundaries-ui.md +++ /dev/null @@ -1,60 +0,0 @@ -# UI Boundaries (MUST / MUST NOT) - -## Listen-Standard - -1. MUST Listen ueber `initStandardListPage(...)` initialisieren. -2. MUST Filter-Toolbar ueber zentrale Helper/Partials rendern. -3. MUST aktive Chips/Drawer-Verhalten ueber Standard-Contracts laufen lassen. -4. MUST NOT direkt `gridFiltersFromSchema(...)` oder `initListFilterExperience(...)` in Listen-Templates verwenden. -5. MUST NOT Legacy-Filter-Toggle-Markup (`data-toolbar-toggle`, `data-filter-overflow`, `data-filter-toggle`) neu einbauen. -6. MUST rowInteraction-Standard fuer Listen mit Row-Navigation beibehalten (sichtbare Action-Spalte + Enter + Doppelklick-Fallback). -7. MUST pageSize-Standard beibehalten (10/25/50/100, Toolbar rechts, URL > localStorage > default). - -## Detailseiten-Standard - -1. MUST Hauptformular mit `data-standard-detail-form="1"` markieren. -2. MUST Unsaved/Shortcut/Dirty-State ueber `initStandardDetailPage(...)` nutzen. -3. MUST Detail-Aktionen ueber Action-Policy-Contract (`data-detail-action-policy`, `data-detail-action-kind`, `data-detail-confirm-message`) steuern. -4. MUST NOT inline `confirm(...)` (`onclick` / `onsubmit`) auf standardisierten Detailseiten nutzen. - -## Confirm + Telemetry Standard - -1. MUST Confirm-Dialoge zentral ueber den globalen Confirm-Service abwickeln. -2. MUST NOT `window.confirm(...)` in App-JS oder inline HTML-Handlern verwenden. -3. MUST relevante Frontend-Warnpfade zentral ueber Frontend-Telemetrie erfassen. -4. MUST NOT relevante UX-/Fehlerpfade nur als Console-Warnung implementieren. - -## Frontend Page-Module Hard Cut - -1. MUST Seiteninitialisierung ueber dedizierte Module unter `web/js/pages/*` umsetzen. -2. MUST Page-Config ueber `script[type="application/json"]` + `readPageConfig(...)` bereitstellen/lesen. -3. MUST alle JS-`src` in `pages/**` und `templates/**` ueber `assetVersion('...js...')` laden. -4. MUST NOT inline `` in `pages/**` oder `templates/**` verwenden. - -## Component Lifecycle Runtime - -1. MUST migrierte Komponenten ueber `init(root, config)` + `destroy()` standardisieren. -2. MUST NOT migrierte Komponenten per `DOMContentLoaded`/Module-Sideeffect selbst auto-initialisieren. -3. MUST Listener, Timer und Observer, die in `init(...)` entstehen, in `destroy()` wieder abbauen. -4. MUST Runtime-Konfiguration ueber Page-Config (`readPageConfig(...)`) beziehen, keine verteilten Ad-hoc-Globals. -5. MUST host-gebundene UI-Komponenten ueber explizite `data-app-component`-Hosts im Markup binden. -6. Global-Utilities ohne natuerliches Host-Element MAY via Runtime `scope: 'global'` registriert werden, MUESSEN aber denselben Lifecycle-Contract inkl. `destroy()` einhalten. - -## Shared Partials - -1. MUST Listen-Titlebar ueber `templates/partials/app-list-titlebar.phtml` rendern. -2. MUST List-Tabs ueber `templates/partials/app-list-tabs.phtml` rendern. -3. MUST Purge-Action ueber `templates/partials/app-list-purge-action.phtml` rendern. -4. MUST Detail-Validation-Summary ueber `templates/partials/app-details-validation-summary.phtml` rendern. - -## RBAC in Templates - -1. MUST UI-Capabilities nur ueber `$viewAuth` lesen. -2. MUST NOT `can('...')` in Templates verwenden. - -## CSS Boundaries - -1. MUST Styles moeglichst lokal in `web/css/components`, `web/css/layout` oder `web/css/pages` halten. -2. MUST NOT globale unscoped Overrides ohne klaren Scope einfuehren. -3. MUST Vendor-Overrides nur in `web/css/vendor-overrides/**` pflegen. -4. MUST bestehende CSS-Variablen bevorzugen statt neue Inline-Farbwerte zu verteilen. diff --git a/tools/codex-skills/core-guardrails/references/quality-gates.md b/tools/codex-skills/core-guardrails/references/quality-gates.md deleted file mode 100644 index f31120e..0000000 --- a/tools/codex-skills/core-guardrails/references/quality-gates.md +++ /dev/null @@ -1,40 +0,0 @@ -# Quality Gates - -## Pflicht-Gates - -1. `docker compose exec php vendor/bin/phpunit` -2. `docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress` -3. `docker compose exec php vendor/bin/phpunit tests/Architecture/CoreStarterkitContractTest.php` - -## Struktur-Gates (schnell) - -```bash -(rg 'new\s+[^\s(]+Factory\(' lib/Service || true) | wc -l -(rg --glob '!**/*Factory.php' 'new\s+[^\s(]+(Service|Gateway|Repository)\(' lib/Service || true) | wc -l -(rg "\b(accessServicesFactory|directoryServicesFactory|userServicesFactory|authServicesFactory|tenantServicesFactory|settingServicesFactory|userRepositoryFactory|authRepositoryFactory|authGatewayFactory)\(" pages lib templates web || true) | wc -l -(rg -n 'new\s+[^\s(]+(Service|Gateway|Repository)\(' pages -g '*.php' || true) | wc -l -(rg -n '\bDB::' pages -g '*.php' || true) | wc -l -(rg -n 'app\([^\n]*Factory::class\)->create' pages/admin -g '*.php' || true) | wc -l -(rg -n 'Factory::class' pages/admin -g '*.php' || true) | wc -l -(rg -n 'ApiResponse::readJsonBody\(' pages/api/v1 -g '*.php' || true) | wc -l -``` - -Erwartung: jeweils `0`. - -## JS-Scope - -- Bei JS-Aenderungen Browser-Smoke mit DevTools-Console durchfuehren. -- Erwartung: keine neuen JS-Errors. - -## Docs-/Skills-Gates (schnell) - -1. `bin/docs-link-check.sh` - - prueft Doku-Links in `README.md`, `docs/**`, `tools/codex-skills/**` und `agent-system/**` - - `agent-system/runs/**` ist standardmaessig ausgeschlossen (historische Artefakte) -2. `bin/codex-skills-sync.sh --check` - - prueft Drift zwischen Repo-Skills und `~/.codex/skills` - -## Berichtspflicht - -- Bei jedem Gate klar angeben: `passed` / `failed` / `not run`. -- Bei `failed` den blocker explizit benennen. diff --git a/tools/codex-skills/core-guardrails/references/source-map.md b/tools/codex-skills/core-guardrails/references/source-map.md deleted file mode 100644 index fc529f8..0000000 --- a/tools/codex-skills/core-guardrails/references/source-map.md +++ /dev/null @@ -1,25 +0,0 @@ -# Source Map (Single Source of Truth) - -## Kernregeln - -- Architektur- und Schichtgrenzen: `/docs/explanation-architektur.md` -- `lib/**`-Regeln und Instanziierung: `/docs/reference-lib-standards.md` -- Kurzkonventionen: `/docs/reference-konventionen.md` -- Request/Input/Validation: `/docs/howto-request-input-validation.md` - -## UI-/Frontend-Contracts - -- JavaScript-Standards und Wrapper: `/docs/reference-frontend-javascript.md` -- CSS-Standards und Scope-Regeln: `/docs/reference-frontend-css.md` -- DoD-Checks: `/docs/reference-entwickler-checkliste.md` -- Rollen-Workflow (Planner/Executor/Reviewer/Finalizer): `/docs/reference-agents-overview.md` - -## Security / RBAC - -- RBAC-Erweiterungen: `/docs/howto-rbac-permissions-playbook.md` -- Sicherheitsmodell: `/docs/explanation-sicherheitsmodell.md` - -## Betrieb und Qualitaetschecks - -- Entwickler-Checkliste: `/docs/reference-entwickler-checkliste.md` -- Architektur-Request-Flow: `/docs/tutorial-04-architektur-request-flow.md` diff --git a/tools/codex-skills/starterkit-grid-standards/SKILL.md b/tools/codex-skills/starterkit-grid-standards/SKILL.md deleted file mode 100644 index 501ccfe..0000000 --- a/tools/codex-skills/starterkit-grid-standards/SKILL.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: starterkit-grid-standards -description: Standardisierungs-Skill fuer GridJS-Listen im Starterkit. Verwenden, wenn Listen neu gebaut oder refactored werden sollen (rowInteraction, pageSize, filter drawer, URL-state, accessibility). ---- - -# Starterkit Grid Standards - -## Ziel - -GridJS-Listen projektweit einheitlich, zuganglich und wartbar halten. - -## Wann verwenden - -1. Neue Listen mit `initStandardListPage(...)` oder `createServerGrid(...)`. -2. Refactor von Legacy-Listen. -3. Review von UX/Accessibility in Listen. - -## Verbindliche Regeln - -1. MUST `initStandardListPage(...)` als Standard nutzen (nur begruendete Ausnahmen direkt mit `createServerGrid(...)`). -2. MUST `rowDblClick.getUrl(...)` fuer zeilenbezogene Navigation setzen, wenn Row-Navigation vorgesehen ist. -3. MUST globale `rowInteraction`-Defaults respektieren (Action-Spalte, Enter, Doppelklick-Fallback). -4. MUST globale `pageSize`-Standards respektieren (`10/25/50/100`, Toolbar-Placement, URL > storage > default). -5. MUST Filter-Drawer/Chips ueber den Standard-Contract nutzen, keine parallelen Custom-Patterns. -6. MUST NOT pro Seite eigene Row-Action-Hacks bauen, wenn der Factory-Contract ausreicht. - -## Vorgehen - -1. Ist-Liste gegen `references/list-checklist.md` pruefen. -2. Fehlende Standards zuerst zentral in der Factory loesen, danach nur minimale Seitenanpassungen. -3. UI/CSS nur als additive Erweiterung zu bestehenden Komponenten. -4. Relevante Gates und Browser-Smoke (Keyboard + Console) ausfuehren. - -## Referenzen - -- Checkliste: `references/list-checklist.md` -- Row Interaction: `references/row-interaction-standard.md` -- Page Size: `references/page-size-standard.md` diff --git a/tools/codex-skills/starterkit-grid-standards/agents/openai.yaml b/tools/codex-skills/starterkit-grid-standards/agents/openai.yaml deleted file mode 100644 index 929f3f9..0000000 --- a/tools/codex-skills/starterkit-grid-standards/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "Starterkit Grid Standards" - short_description: "Standardize GridJS lists and accessibility patterns" - default_prompt: "Use $starterkit-grid-standards to standardize a list page with rowInteraction, pageSize, and filter drawer contracts." diff --git a/tools/codex-skills/starterkit-grid-standards/references/list-checklist.md b/tools/codex-skills/starterkit-grid-standards/references/list-checklist.md deleted file mode 100644 index c196787..0000000 --- a/tools/codex-skills/starterkit-grid-standards/references/list-checklist.md +++ /dev/null @@ -1,30 +0,0 @@ -# List Checklist - -## Bootstrap - -1. `initStandardListPage({ grid, filters, hooks })` verwendet. -2. `filterSchema` aus Server-Config uebergeben. -3. `urlSync` bewusst gesetzt. - -## Interaction - -1. `rowDblClick.getUrl(...)` liefert stabile Ziel-URL oder leer. -2. Keine Doppel-Action-Spalte (Factory auto-action vs explizite actions). -3. Enter/Pointer/Focus fuer oeffnbare Rows funktionieren. - -## Pagination + URL - -1. Page-size Optionen nur `10/25/50/100`. -2. URL Sync pruefen (`page`, `order`, `dir`, `limit`). -3. Default-Werte erzeugen saubere URL. - -## Filter UX - -1. Search sichtbar. -2. Drawer-Filter und Chips intakt. -3. Reset/Apply Verhalten reproduzierbar. - -## Regression - -1. Sortierung, Selection/Bulk, Doppelklick unveraendert. -2. Keine neuen Console Errors. diff --git a/tools/codex-skills/starterkit-grid-standards/references/page-size-standard.md b/tools/codex-skills/starterkit-grid-standards/references/page-size-standard.md deleted file mode 100644 index 2da7f2f..0000000 --- a/tools/codex-skills/starterkit-grid-standards/references/page-size-standard.md +++ /dev/null @@ -1,20 +0,0 @@ -# Page Size Standard - -## Globale Defaults - -1. Optionen: `10`, `25`, `50`, `100`. -2. Default: `10`. -3. Prioritaet: `URL > localStorage > Default`. -4. Placement: obere `app-list-toolbar`, rechts ausgerichtet. - -## URL Contract - -1. Param: `limit`. -2. Bei Default-Limit optional clean URL (Param entfernen). -3. Bei Hard-Reload muss gesetztes URL-Limit reproduzierbar sein. - -## Verhalten - -1. Aenderung der Seitengroesse setzt Seite auf 1. -2. Sortierung/Filter bleiben erhalten. -3. LocalStorage-Key pro Tabelle (path + dataUrl + container). diff --git a/tools/codex-skills/starterkit-grid-standards/references/row-interaction-standard.md b/tools/codex-skills/starterkit-grid-standards/references/row-interaction-standard.md deleted file mode 100644 index 42285de..0000000 --- a/tools/codex-skills/starterkit-grid-standards/references/row-interaction-standard.md +++ /dev/null @@ -1,31 +0,0 @@ -# Row Interaction Standard - -## Ziel - -Row-Navigation discoverable und keyboard-freundlich machen. - -## Standardverhalten - -1. Sichtbare Action-Spalte rechts (`Open`/`Edit`) fuer Listen mit `rowDblClick`. -2. Enter auf fokussierter Row loest dieselbe Navigation aus. -3. Doppelklick bleibt als Fallback fuer Power-User. -4. Nur Rows mit Ziel-URL erhalten `data-row-open-url`. - -## Contract - -```js -rowInteraction: { - enabled: true, - showActionButton: true, - keepDblClick: true, - enableEnterOnRow: true, - actionColumnLabel: 'Actions', - resolveActionLabel: (url, rowData) => (url.includes('/edit/') ? 'Edit' : 'Open') -} -``` - -## Guardrails - -1. Keine globale Tab-Stop-Flut auf allen Rows. -2. Fokusstil fuer Row und Action-Button sichtbar. -3. Explizite `actions.enabled: true` pro Seite darf Auto-Action uebersteuern. diff --git a/tools/codex-skills/starterkit-php-style-ci/SKILL.md b/tools/codex-skills/starterkit-php-style-ci/SKILL.md deleted file mode 100644 index d3d47b9..0000000 --- a/tools/codex-skills/starterkit-php-style-ci/SKILL.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -name: starterkit-php-style-ci -description: Standard-Skill fuer PHP Coding-Style im Starterkit (php-cs-fixer, dry-run in CI, lokaler fix/check workflow). Verwenden bei Style-Einfuehrung, CI-Checks oder grossen Format-Diffs. ---- - -# Starterkit PHP Style CI - -## Ziel - -Coding-Style pruefbar, reproduzierbar und regressionsarm machen. - -## Wann verwenden - -1. Einfuehrung oder Nachschaerfung von Style-Regeln. -2. CI-Dry-Run fuer Style-Checks. -3. Aufraeumen grosser Style-Diff-Wellen. - -## Verbindliche Regeln - -1. MUST `composer cs:check` fuer nicht-mutierende Pruefung nutzen. -2. MUST `composer cs:fix` nur bewusst und mit Diff-Kontrolle ausfuehren. -3. MUST Style-Check vor Merge gruen halten (lokal und optional CI). -4. MUST nach groesseren Fixes mindestens `phpunit` und `phpstan` laufen lassen. -5. MUST NOT manuell Einzelstellen formatieren, wenn der Fixer sie zentral loesen kann. - -## Workflow - -1. Baseline erfassen: `composer cs:check`. -2. Falls noetig fixen: `composer cs:fix`. -3. Diff fokussiert pruefen (Imports, Braces, Nebenwirkungen). -4. Qualitaetsgates laufen lassen. -5. CI-Dry-Run konfigurieren oder validieren. - -## Referenzen - -- Lokaler Workflow: `references/style-workflow.md` -- CI Dry Run: `references/ci-dry-run.md` diff --git a/tools/codex-skills/starterkit-php-style-ci/agents/openai.yaml b/tools/codex-skills/starterkit-php-style-ci/agents/openai.yaml deleted file mode 100644 index c3e1eca..0000000 --- a/tools/codex-skills/starterkit-php-style-ci/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "Starterkit PHP Style CI" - short_description: "Enforce PHP coding style with safe local and CI checks" - default_prompt: "Use $starterkit-php-style-ci to set up and run php-cs-fixer check/fix workflow with CI dry-run and guardrails." diff --git a/tools/codex-skills/starterkit-php-style-ci/references/ci-dry-run.md b/tools/codex-skills/starterkit-php-style-ci/references/ci-dry-run.md deleted file mode 100644 index 9c0a624..0000000 --- a/tools/codex-skills/starterkit-php-style-ci/references/ci-dry-run.md +++ /dev/null @@ -1,21 +0,0 @@ -# CI Dry Run - -## Ziel - -CI soll nur pruefen, nicht formatieren. - -## Minimaler Check - -```bash -composer cs:check -``` - -## Erwartung - -1. Exit Code 0: Style konform. -2. Exit Code != 0: Diff ausgeben, Entwickler fuehrt lokal `composer cs:fix` aus. - -## Hinweise - -1. Kein Auto-Commit aus CI. -2. Bei initialen Altlasten zuerst einmalige Bereinigung auf dediziertem Branch. diff --git a/tools/codex-skills/starterkit-php-style-ci/references/style-workflow.md b/tools/codex-skills/starterkit-php-style-ci/references/style-workflow.md deleted file mode 100644 index d7d707f..0000000 --- a/tools/codex-skills/starterkit-php-style-ci/references/style-workflow.md +++ /dev/null @@ -1,25 +0,0 @@ -# Local Style Workflow - -## Commands - -```bash -composer cs:check -composer cs:fix -``` - -## Praktikabler Ablauf - -1. Erst `cs:check` laufen lassen. -2. Danach `cs:fix`. -3. Nur relevante Diffs uebernehmen, grosse Misch-Diffs vermeiden. -4. Anschliessend: - -```bash -docker compose exec php vendor/bin/phpunit -docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress -``` - -## Review-Fokus - -1. `ordered_imports`, `braces_position`, `statement_indentation`. -2. Kein semantischer Drift bei anon classes, arrow functions, array maps. diff --git a/tools/codex-skills/starterkit-planner/SKILL.md b/tools/codex-skills/starterkit-planner/SKILL.md deleted file mode 100644 index a0847a8..0000000 --- a/tools/codex-skills/starterkit-planner/SKILL.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -name: starterkit-planner -description: Planungs-Skill fuer Architektur-, Rollout-, Refactor- und Standardisierungsaufgaben im Starterkit. Verwenden, wenn ein decision-complete Plan mit klaren Interfaces, Tests, Risiken und Annahmen benoetigt wird. ---- - -# Starterkit Planner - -## Ziel - -Planungen so strukturieren, dass Implementierung ohne offene Entscheidungen moeglich ist. -Bei Agent-Workflows muss der Plan maschinenlesbar in die Projekt-Contracts passen. - -## Verbindliches Ausgabeformat - -1. Ziel + Success Criteria -2. In/Out-of-Scope -3. Entscheidungsmatrix (Optionen + Gruende) -4. Decision-complete Implementierungsplan -5. Tests/Abnahme -6. Risiken/Migrationshinweise -7. Annahmen/Defaults - -Wenn `agent-system/` verwendet wird: - -1. Plan muss dem Schema `agent-system/contracts/planner.schema.json` entsprechen. -2. Success Criteria muessen stabile IDs tragen (`SC-001`, `SC-002`, ...). -3. Success Criteria muessen so formuliert sein, dass Reviewer Acceptance sie direkt gegen `criterion_id` pruefen kann. -4. Guard- und Quality-Gate-IDs muessen aus den Katalogen kommen (`GR-*`, `QG-*`). - -## Vorgehen - -1. Ist-Zustand kurz aus Repo-Fakten ableiten. -2. Entscheidungen mit Tradeoffs transparent machen. -3. Oeffentliche Contracts explizit benennen. -4. Success Criteria frueh mit stabilen IDs (`SC-*`) definieren. -5. Reihenfolge und Rollout so planen, dass Rueckbau moeglich bleibt. -6. Teststrategie nach Risiko priorisieren. - -## Qualitaetskriterien - -1. Keine vagen TODO-Entscheidungen im Plan. -2. Jeder betroffene Bereich hat klare Akzeptanzkriterien mit stabiler ID (`SC-*`). -3. Risiken sind priorisiert und beobachtbar. -4. Ungeklaerte Themen stehen explizit unter Annahmen. -5. Guard-/Gate-Referenzen sind vollstaendig und pruefbar (`GR-*`, `QG-*`). - -## Out of Scope - -- Extension-Mechanik ist aktuell nicht standardisiert. -- Keine impliziten Extension-Regeln definieren. - -## Referenzen - -- Plan-Grundgeruest: `references/plan-template.md` -- Entscheidungsraster: `references/tradeoff-matrix.md` -- Agent Planner Contract: `agent-system/contracts/planner.schema.json` -- Guard Catalog: `agent-system/checks/guard-catalog.json` -- Quality Gates: `agent-system/checks/quality-gates.json` diff --git a/tools/codex-skills/starterkit-planner/references/plan-template.md b/tools/codex-skills/starterkit-planner/references/plan-template.md deleted file mode 100644 index 8e530da..0000000 --- a/tools/codex-skills/starterkit-planner/references/plan-template.md +++ /dev/null @@ -1,50 +0,0 @@ -# Plan Template (Decision Complete) - -## 1) Ziel + Success Criteria - -- Was wird verbessert? -- Woran ist messbar, dass es erfolgreich ist? -- Success Criteria immer mit stabilen IDs formulieren (`SC-001`, `SC-002`, ...). - -Beispiel: - -- `SC-001`: Delete-Aktion zeigt Confirm-Dialog mit korrekter Gefahr-Variante. -- `SC-002`: Nach Confirm erfolgt genau ein Submit (kein Doppel-Submit). - -## 2) Scope - -- In Scope -- Out of Scope -- Scope-Typ explizit markieren (`core`, `ui`, `api`, `mixed`), wenn der Workflow es verlangt. - -## 3) Oeffentliche Interfaces / Contracts - -- Neue/angepasste APIs, Data-Contracts, CLI-Flags, Markup-Contracts -- Backward-Compatibility-Entscheidung -- Bei Agent-Workflow: verwendete `GR-*` und `QG-*` IDs explizit nennen. - -## 4) Implementierungsschritte - -1. Schritt A -2. Schritt B -3. Schritt C - -Regel: Jeder Schritt ist direkt umsetzbar ohne Nachentscheid. - -## 5) Test- und Abnahmeplan - -- Syntax/Static Checks -- Contract-/Architekturtests -- Fachliche Smoke-Tests -- Abnahmekriterien (klar messbar) -- Abnahme-Checks 1:1 auf `SC-*` Kriterien-ID referenzieren. - -## 6) Risiken / Migration - -- Hauptrisiken -- Mitigation -- Rollout-/Rollback-Hinweis - -## 7) Annahmen / Defaults - -- Alle offenen Themen als explizite Annahme festhalten. diff --git a/tools/codex-skills/starterkit-planner/references/tradeoff-matrix.md b/tools/codex-skills/starterkit-planner/references/tradeoff-matrix.md deleted file mode 100644 index 081833e..0000000 --- a/tools/codex-skills/starterkit-planner/references/tradeoff-matrix.md +++ /dev/null @@ -1,34 +0,0 @@ -# Tradeoff Matrix - -## Bewertungsachsen - -1. Robustheit / Fehlertoleranz -2. Wartbarkeit / Kopplung -3. Migrationsrisiko -4. Testbarkeit -5. Liefergeschwindigkeit - -## Standard-Optionen - -### Option A: Zentralisieren im Core - -- Vorteile: Konsistenz, weniger Duplikate -- Nachteile: Hoher Impact, breiter Testbedarf -- Geeignet wenn: 3+ Stellen betroffen oder Contract-Sicherheit steigt deutlich - -### Option B: Shared Partial/Helper - -- Vorteile: Schneller Nutzen, moderates Risiko -- Nachteile: Teilweise Restduplikate moeglich -- Geeignet wenn: Wiederkehrendes UI-/Glue-Muster mit klaren Datencontracts - -### Option C: Lokal belassen - -- Vorteile: Geringstes kurzfristiges Risiko -- Nachteile: Langfristig mehr Wartung, inkonsistente UX -- Geeignet wenn: Einzelfall oder experimentelle Logik - -## Entscheidungsregel - -- Standardempfehlung: Option B vor Option A, wenn Nutzen hoch und Migrationsradius kleiner ist. -- Option C nur mit expliziter Begruendung (z. B. bewusstes Out-of-Scope oder Legacy-Risiko).