Most German docs were written with `ue`/`ae`/`oe`/`ss` ASCII fallbacks
(`fuer`, `aenderung`, `koennen`, `gemaess`) — relic from older toolchain
constraints. Replaced 237 occurrences across 38 .md files with proper
umlauts and ß so the docs read naturally.
Substitutions are constrained to plain prose: fenced code blocks
(```...```), inline code spans (`...`), markdown link targets `[..](..)`,
and HTML comments are preserved verbatim. Path references like
`docs/howto-erste-aenderung.md` keep their original (umlaut-replaced)
filenames — only the surrounding prose is normalised.
Tool: bin/fix-md-umlauts.py (idempotent — no-op on already-clean files).
Re-runnable if ASCII fallbacks creep back in via copy-paste.
Doc-link-check + doc-drift-check stay green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
config/config.php was gitignored and devs had to copy it from
config/config.php.example on every fresh clone. Since the bootstrap
config reads everything from .env via $envString() / $envInt() /
$envBool() defaults, there is nothing developer-specific in the file —
the cp step was dead ceremony.
- Remove config/config.php from .gitignore and track it directly
- Delete config/config.php.example
- Drop the example-existence + per-doc reference checks from
bin/docs-drift-check.sh; add a legacy-pattern check that flags
any new mention of the removed example file
- Update ConfigContractsTest to require config.php and forbid the
example
- Clean stale references in CLAUDE.md, README.md, six docs files,
and the core-guardrails skill
Same commit slims README down from 294 to 47 lines: one setup
checklist (now 3 commands instead of 4), the seeded login table,
the three quality-gate commands, and pointers to CLAUDE.md and
docs/index.md for everything else.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Make the core-primitive-end-to-end rule for Grid.js list exports binding
instead of advisory — so future consumers (and reviewers) cannot quietly
drift back into inline fputcsv / hand-rolled headers / bespoke click
listeners / lurl() for query-carrying URLs.
- CLAUDE.md: new UI Patterns bullet + two "Never Do This" entries
spelling out the server/view/client contract in one place.
- .agents/checks/guard-catalog.json: new GR-UI-EXPORT entry describing
the end-to-end requirement (exportRequireGetRequest + exportCapLimit +
exportSendCsv + ExportColumn + shared filter-schema + dropdown partial
+ endpointUrl() + initListExport).
- .agents/checks/guard-enforcement-map.json: wire the new guard to
tests/Architecture/ListExportContractTest.php as the automated
evidence source.
- .agents/checks/guard-checklist.md & .agents/prompts/reviewer-code.md:
add GR-UI-EXPORT so the Code Reviewer prompt and the checklist flag
violations alongside GR-UI-LIST.
- tests/Architecture/ListExportContractFiles: registry of every list
export (currently helpdesk-domains, admin/users, audit/system-audit).
Adding a new list = one entry, contract test covers the rest.
- tests/Architecture/ListExportContractTest: six checks per registered
entry — endpoint uses the primitive, no hand-rolled output, data and
export share the same filter-schema, template includes the dropdown
partial and uses endpointUrl(), page module imports and invokes
initListExport, and the shared dropdown partial stays zero-config.
- pages/admin/users/export().php: align with the new contract by
switching from ad-hoc requestInput()->queryAll() reads to
gridParseFiltersFromSchemaFile(__DIR__ . '/filter-schema.php'), same
as the data endpoint — eliminates the last place Grid and export
could disagree on what "the current filter" means.
Gates: PHPUnit 1900 OK (+6 contract checks), PHPStan 0 errors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
reviewer-code.md was missing 4 of 17 assigned guards (LAYERS, META,
MODULE, TAXONOMY); reviewer-security.md was missing GR-SEC-010. README
did not list the Scheduled Jobs feature.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update security guard references from 9 to 10 (GR-SEC-010 was missing),
code reviewer guards from 13 to 17 (new GR-CORE-LAYERS, GR-CORE-MODULE,
GR-CORE-META, GR-UI-TAXONOMY), and total guard count from 22 to 27.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add architecture test ViewLayerOutputEscapingContractTest that flags
raw <?php echo in .phtml files. Legitimate uses (pre-built ARIA attrs
from navActive(), hardcoded role values, pre-rendered HTML fragments)
must carry an inline // raw-html-ok: reason marker.
Annotated all 11 existing raw echo sites with justification markers.
Added guard to catalog, enforcement map (automated), CLAUDE.md security
section, and never-do-this list.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix 5 broken FQCN references (runtime errors) where core pages referenced
non-existent MintyPHP\Service\Audit\AuditMetadataEnricher and SystemAuditService.
Add AuditMetadataEnricherInterface with NullAuditMetadataEnricher fallback so
deactivating the audit module no longer crashes core edit pages.
Move audit search resources from core Search*Provider files into the module
via a new AuditSearchResourceProvider implementing the existing
SearchResourceProvider contract. Add module-specific purge permissions
(audit.api.purge, audit.imports.purge) replacing core ABILITY_ADMIN_SETTINGS_UPDATE.
Also fixes: session key prefix convention, hardcoded English string, $_SERVER
superglobal fallback, and manifest schema drift (i18n_path, group in ui_slots).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase A — Gate Reliability:
- Fix typography token violations in app-breadcrumb.css
- Switch QG-006 from composer cs:check to direct php-cs-fixer
- Align all docs/skills with new gate command
Phase B — Production Profile:
- Multi-stage Dockerfile: dev (xdebug) / prod (no xdebug)
- Compose files target explicit build stages
Phase C — Module Runtime Hardening:
- Atomic staging+swap build in ModuleRuntimePageBuilder
- SHA-256 fingerprint from manifest content + page entries
- 11 new regression tests for build safety and fingerprint drift
Task: STARTERKIT-HARDENING-ONPREM-001
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove the dedicated "Edit"/"Open" action button column from all list
pages. Instead, wrap the primary data column (name, description, subject,
etc.) in a clickable <a> link via the new rowInteraction.linkColumn option.
Double-click, Enter-key, and click-to-focus row navigation preserved.
Pages with explicit actions config are unaffected. Address-book opts out
of auto-wrapping (linkColumn: false) and renders the link in its own
formatter to avoid nested <a> with avatar lightbox.
Also fixes pre-existing XSS in insertActionColumn (unescaped href/label)
and updates typography test for --text-page-title token change.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Moves the agent workflow system from agent-system/ to .agents/ (dotfile convention).
Restructured from 5-role to 7-role pipeline: adds Analyst and splits Reviewer into
Code Reviewer + Security Reviewer. Removes all old workflow run artifacts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Six targeted improvements to the modular monolith platform:
1. Fix AddressBook session key prefix to follow module.<id>.* convention
2. Move ADDRESS_BOOK_VIEW permission constant from core PermissionService into module
3. Add declarative JSON schema for module manifests (.agents/contracts/)
4. Add `requires` field with missing-dependency and circular-dependency detection
5. Add lightweight fire-and-forget event dispatcher (user.created/deleted/login/logout)
6. Add module deactivation hook interface and CLI script (bin/module-deactivate.php)
Includes 15 new architecture/unit tests covering all new functionality.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>