Introduces a reusable core detail-drawer primitive that slides in from the
right and loads any view via a `*-fragment(none).phtml` endpoint. Bundles the
address book list overhaul that is its first consumer.
Core additions:
- `app-detail-drawer.js` — generic drawer with stepper, focus trap, body
scroll-lock, URL-hash deep-linking, session-expiry detection
- `app-fragment-init.js` — auto-wires tabs/lookups/confirm/file-upload/
fslightbox inside injected HTML; consumers do not re-initialize components
- `app-focus-trap.js` — shared focus-trap + refcounted scroll-lock, used by
both filter-drawer and detail-drawer
- `getHtml()` in `app-http.js` + `SessionExpiredError`; drawer reloads the
page on auth redirect instead of rendering the login form in the panel
- `DetailDrawerFragmentContractTest` enforces that every `initDetailDrawer`
consumer ships matching `*-fragment($id).php` + `*-fragment(none).phtml`
Address book list:
- Grid collapses from 9 columns to 4 (identity / context / phone / actions)
with a two-line identity cell (avatar + name + email)
- Tenant register tabs above the grid using the `app-list-tabs` partial;
tenant filter wired via hidden toolbar field so grid.js forwards it on
every data fetch
- Profile body extracted to a shared partial so the full-page view and the
new drawer fragment share the same markup
- New i18n keys for the drawer/list labels
Also refactors `app-filter-drawer` to reuse the shared focus-trap and
scroll-lock instead of maintaining its own copy, and documents the
detail-drawer convention in CLAUDE.md.
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>
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>
Replace bare <input type="file"> across all upload locations with a
card-based dropzone component via shared partial. Three visual states:
current server file (thumbnail + Replace/Delete), empty dropzone, and
pending file preview (local FileReader thumbnail + metadata). Delete
actions use data-confirm-message for confirmation dialog.
Centralized as templates/partials/app-file-upload.phtml to prevent
markup drift — documented as deliberate exception to plain-HTML inputs
convention in CLAUDE.md and developer checklist.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- remove legacy bin/module-*.php and bin/doctor.php entry scripts
- move module/doctor execution into class-based runners under lib/Console
- add stable JSON output for doctor and module:sync
- introduce bin/dev for init/up/down/logs/console/qa workflow
- update DI wiring, phpstan scan config, tests, and docs to new CLI contract
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>
Surface binding rules from .agents/ (guards, quality gates, security)
directly in CLAUDE.md so they are enforced from conversation start.
Adds: Mandatory Workflow section, Security (non-negotiable) section,
Never Do This anti-patterns, module isolation constraints, and
structured quality gate table with gate IDs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>