1
0
Commit Graph

7 Commits

Author SHA1 Message Date
fs
9a78a81af8 feat(admin-users): dedicated admin profile drawer with own tabs
The first pass had admin/users sharing the address book profile partial,
which surfaced Contact/Address/Organization/About tabs that ignored the
admin-specific context. Separates the admin quick-view so it mirrors the
edit-page tab structure while staying read-only.

- `UserProfileViewService::buildAdminProfile()` extends the base profile
  with `admin_extras` (active, email_verified_at, last_login_at,
  last_login_provider, created, modified).
- `templates/partials/app-admin-user-profile.phtml` is the admin-only
  render path: Master data · Organization · Security · About. Status
  badge under the name; timestamps locale-formatted.
- `pages/admin/users/view-fragment($id).php` / `(none).phtml` switched
  to the admin service method + partial.
- Drawer CSS aligns the aside with the main section's inline padding so
  the content strip does not visually step in/out.

Address book is unchanged — still uses `buildProfile()` + the base
partial. Two i18n keys added (`Login provider`).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 16:30:03 +02:00
fs
c1cf9f94bb feat(core): UserProfileViewService + admin/users detail drawer
Extracts the user profile read-view into a core service + shared partial so
modules no longer duplicate the assignment/scope logic, and migrates the
admin/users list as the drawer's second consumer.

Consolidation:
- `core/Service/User/UserProfileViewService` owns the single read-path that
  resolves tenants/departments/roles for a user UUID, enforces scope-aware
  department visibility, and returns a consistent `{status, user}` shape.
- `templates/partials/app-user-profile.phtml` is the shared render template;
  takes `$profileKey` for storage namespace + lightbox grouping.
- `AddressBookService::buildViewContext()` shrinks to a one-line delegation
  and drops its `UserAssignmentService` dependency. The old
  `modules/addressbook/templates/address-book-profile.phtml` is removed.

admin/users migration:
- `pages/admin/users/view-fragment($id).php` + `(none).phtml` use the core
  service and enforce `ABILITY_ADMIN_USERS_VIEW`.
- `admin-users-index.js` replaces the grid-native `linkColumn` on the first
  name with a formatter that emits `data-drawer-trigger`; `linkColumn` is
  disabled so the drawer click handler wins. `fullUrl` points at the edit
  form — drawer → edit is one click.
- Drawer labels wired via page config.

The new `DetailDrawerFragmentContractTest` validated the users fragment
endpoint automatically — no manual test additions were needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 15:49:10 +02:00
fs
12356e2266 feat(core): generic CSV export primitive + helpdesk domains consumer
Add a reusable CSV-export building block to the core so any Grid.js list
page can gain a filter/sort-aware download with two clicks of glue.

Core primitive:
- core/Service/Export/CsvExportService: flavor-aware writer (plain CSV
  or Excel-compatible UTF-8+BOM+semicolon), with OWASP-aligned formula-
  injection escape (=, @, +, -, TAB, CR) applied to both rows *and*
  headers. Value objects for columns (ExportColumn) carry an extractor
  closure and an allowSignedNumeric flag for phone-number-shaped cells.
- core/Support/helpers/export.php: thin HTTP layer (exportSendCsv,
  exportCapLimit, exportResolveFlavor, exportRequireGetRequest) reusing
  the requestInput() contract for GR-CORE-003 consistency. Filename is
  sanitized and length-clamped; callers must still enforce auth.
- templates/partials/app-list-export-dropdown.phtml: zero-config
  <details class="dropdown"> with CSV + Excel triggers.
- web/js/core/app-list-export.js: initListExport({ gridConfig, exportUrl })
  mirrors the current grid filters + sort onto the export URL and
  navigates, preserving session cookies for download.

First consumer — Helpdesk domains:
- DomainListService extracts the shared filter/enrich/sort logic from
  domains-data so the grid endpoint and the new domains/export endpoint
  cannot drift.
- domains/export endpoint delegates to DomainListService, declares
  ExportColumns (with translated level labels), and exits via
  exportSendCsv.
- domains-data now ~20 lines, delegating to DomainListService.

Tests:
- CsvExportServiceTest (10 cases): both flavors, BOM/no-BOM, formula
  escapes incl. TAB/CR, header escape, signed-numeric allowlist,
  quoting, multiline, empty columns, generator-compatible iterable.
- ExportHelpersTest (5 cases): exportCapLimit bounds.
- DomainListServiceTest (8 cases): filter, search, "all" sentinel,
  sort, paging, enrichment, BC failure, tenant-scoped security filter.

Gates: PHPUnit green, PHPStan clean on touched files, module:sync ok.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 21:57:19 +02:00
fs
3f0db68b27 refactor: fix all 105 PHPStan 2 strict type findings across core and modules
Resolve all non-false-positive PHPStan 2 findings, reducing the baseline
from 486 to 382 entries (only unused-public false positives remain).

Categories fixed:
- Remove 39 redundant type checks (is_string, is_array, is_object, method_exists)
- Remove 12 no-op array_values() on already-sequential lists
- Simplify 13 null-coalesce on guaranteed offsets
- Remove 8 always-true instanceof checks
- Replace 12 redundant test assertions (assertTrue(true) → addToAssertionCount)
- Simplify 6 unnecessary nullsafe operators (?-> → ->)
- Fix 6 always-true !== '' comparisons
- Fix remaining: unset.offset, return.unusedType, staticMethod narrowing

53 files changed across core/, modules/, pages/, and tests/.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 12:54:20 +02:00
fs
94b746ddf8 refactor: remove 13 dead code artifacts across core/
Dead methods (9):
- Command::bootstrapModuleApp() — unused by all subclasses
- SearchConfig::providerCoverageGaps() — diagnostic method, never called
- RequestInput::queryArray() — no callers
- LocaleResolver::getAvailableLocales() / getDefaultLocale() — unused getters
- EmailVerificationService::getExpiryMinutes() — constant wrapper, never called
- AuthService::loginAndRedirect() — convenience wrapper, never called
- DepartmentService::listForUserAssignments() — no callers
- UserTenantContextService::getAvailableDepartmentsByTenant() — no callers

Dead functions (3):
- navActivePublicPages(), appNormalizeStringList(), appNormalizePositiveIntList()

Dead constant (1):
- PermissionService::API_DOCS_VIEW — duplicated via other paths

Orphaned file (1):
- bin/cli-bootstrap.php — never included anywhere

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 08:48:29 +02:00
fs
b1a907b79c feat(modules): harden module platform with event constants, validation checks, and CLI improvements
- Add ModuleEvents constants class with all 8 event strings; update dispatch call sites
- ValidateCommand: check AuthorizationPolicy container registration (check 20)
- ValidateCommand: warn on unknown event_listeners keys (check 21)
- make:module --simple flag for minimal manifests
- module:deactivate reverse-dependency warning
- 12 new PHPUnit tests covering all improvements

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 08:23:04 +02:00
fs
0e86925464 refactor: rename lib/ to core/ for clearer core-module separation
Rename the top-level lib/ directory to core/ so the project root
immediately communicates which code is core platform and which lives
in modules/. PHP namespaces (MintyPHP\*) are unchanged — only the
Composer PSR-4 path mapping moves from lib/ to core/.

Module-internal lib/ directories (modules/*/lib/) are untouched.

Updated across the full stack:
- composer.json PSR-4 mapping
- bootstrap entry points (web/index.php, bin/*, tests/bootstrap.php)
- tooling configs (phpstan.neon, phpunit.xml, php-cs-fixer)
- 26 architecture contract tests
- enforcement-policy, guard-catalog, quality-gates
- all documentation (CLAUDE.md, README, 25 docs/, .agents/skills/)
- bin/qa-extended.sh search paths
- .claude/settings.local.json permission paths

Workflow: .agents/runs/CORE-LIB-RENAME-001/ (Analyst → Planner →
Executor → Code Review (4 findings fixed) → Security Review →
Acceptance Test → Finalizer)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 23:20:42 +02:00