2026-03-04 15:56:58 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace MintyPHP\Tests\Architecture;
|
|
|
|
|
|
2026-03-19 19:11:03 +01:00
|
|
|
final class StatusTaxonomyContractFiles
|
2026-03-04 15:56:58 +01:00
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* @return list<string>
|
|
|
|
|
*/
|
2026-03-19 19:11:03 +01:00
|
|
|
public static function taxonomyEnumFiles(): array
|
2026-03-04 15:56:58 +01:00
|
|
|
{
|
|
|
|
|
return [
|
refactor(audit): extract audit domain into self-contained module
Move the entire audit subsystem (system audit, API audit, import audit,
user lifecycle audit, frontend telemetry) from core into modules/audit/.
Core decoupling via interface-based injection:
- AuditRecorderInterface replaces SystemAuditService in 10+ core services
- UserLifecycleAuditInterface / ImportAuditInterface for specialized flows
- NullAuditRecorder fallback when audit module is disabled
- ApiBootstrap/ApiResponse use null-safe callable resolvers
Module structure (modules/audit/):
- Manifest with routes, permissions, scheduler jobs, authorization policy
- 9 services, 8 repositories, 6 domain enums, 4 job handlers
- 33 page files, 4 JS files, 8 test files, migration scripts, i18n
Core cleanup:
- OperationsAuthorizationPolicy, UiCapabilityMap, PermissionService
surgically cleaned of audit-specific constants
- Sidebar template cleared of hardcoded audit navigation
- AuditModuleIsolationContractTest ensures no future core→module coupling
All quality gates pass: 1346 tests (19,276 assertions), PHPStan level 5
clean, architecture contracts verified.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:12:49 +01:00
|
|
|
'modules/audit/lib/Module/Audit/Domain/SystemAuditOutcome.php',
|
|
|
|
|
'modules/audit/lib/Module/Audit/Domain/SystemAuditChannel.php',
|
|
|
|
|
'modules/audit/lib/Module/Audit/Domain/UserLifecycleAction.php',
|
|
|
|
|
'modules/audit/lib/Module/Audit/Domain/UserLifecycleTriggerType.php',
|
|
|
|
|
'modules/audit/lib/Module/Audit/Domain/UserLifecycleStatus.php',
|
|
|
|
|
'modules/audit/lib/Module/Audit/Domain/ImportAuditStatus.php',
|
2026-04-13 23:20:05 +02:00
|
|
|
'core/Domain/Taxonomy/ScheduledJobStatus.php',
|
|
|
|
|
'core/Domain/Taxonomy/ScheduledJobRunStatus.php',
|
|
|
|
|
'core/Domain/Taxonomy/ScheduledJobTriggerType.php',
|
|
|
|
|
'core/Domain/Taxonomy/MailLogStatus.php',
|
|
|
|
|
'core/Domain/Taxonomy/TenantStatus.php',
|
|
|
|
|
'core/Domain/Taxonomy/SchedulerRuntimeResult.php',
|
2026-03-04 15:56:58 +01:00
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return array<string,list<string>>
|
|
|
|
|
*/
|
2026-03-19 19:11:03 +01:00
|
|
|
public static function taxonomySchemaExpectations(): array
|
2026-03-04 15:56:58 +01:00
|
|
|
{
|
|
|
|
|
return [
|
2026-03-26 08:13:37 +01:00
|
|
|
'modules/audit/pages/audit/system-audit/filter-schema.php' => [
|
2026-03-04 15:56:58 +01:00
|
|
|
'SystemAuditOutcome::values()',
|
|
|
|
|
'SystemAuditChannel::values()',
|
|
|
|
|
],
|
2026-04-26 18:03:42 +02:00
|
|
|
'modules/audit/pages/audit/settings-user-lifecycle/filter-schema.php' => [
|
2026-03-04 15:56:58 +01:00
|
|
|
'gridEnumSanitizer(UserLifecycleAction::class)',
|
|
|
|
|
'gridEnumSanitizer(UserLifecycleStatus::class)',
|
|
|
|
|
'gridEnumSanitizer(UserLifecycleTriggerType::class)',
|
|
|
|
|
],
|
2026-03-26 08:13:37 +01:00
|
|
|
'modules/audit/pages/audit/import-audit/filter-schema.php' => [
|
2026-03-04 15:56:58 +01:00
|
|
|
'ImportAuditStatus::values()',
|
|
|
|
|
],
|
|
|
|
|
'pages/admin/scheduled-jobs/filter-schema.php' => [
|
|
|
|
|
'ScheduledJobStatus::values()',
|
|
|
|
|
],
|
|
|
|
|
'pages/admin/scheduled-jobs/runs-filter-schema.php' => [
|
|
|
|
|
'ScheduledJobRunStatus::values()',
|
|
|
|
|
'ScheduledJobTriggerType::values()',
|
|
|
|
|
],
|
|
|
|
|
'pages/admin/mail-log/filter-schema.php' => [
|
|
|
|
|
'MailLogStatus::values()',
|
|
|
|
|
],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return list<string>
|
|
|
|
|
*/
|
2026-03-19 19:11:03 +01:00
|
|
|
public static function taxonomyDataEndpointFiles(): array
|
2026-03-04 15:56:58 +01:00
|
|
|
{
|
|
|
|
|
return [
|
refactor(audit): extract SystemAuditRowPresenter shared by data + export
Move the row formatting that was duplicated between system-audit's
data() and export() endpoints into a single presenter. Both endpoints
now call presentAll() on the same object, so enum label translation,
actor resolution, and timestamp formatting cannot drift between the
Grid.js UI and the CSV download.
- SystemAuditRowPresenter::present()/presentAll(): canonical row shape
with outcome + outcome_label + outcome_badge, channel + channel_label,
actor_user_label with display-name-then-email fallback, and safe
defaults for every missing field.
- data().php shrinks from ~45 to ~15 lines; export().php drops its
inline outcome/channel/actor resolvers and reads the already-
resolved fields from the presenter output.
- AuditContainerRegistrar registers the presenter.
- tests/Module/Audit/Service/SystemAuditRowPresenterTest: 9 cases
covering enum normalization, unknown-value fallback, actor label
precedence (display name → email → "-"), whitespace trimming, safe
defaults for missing keys, and iterable input.
- StatusTaxonomyContractFiles: the taxonomy data contract now points
at the presenter (the single source of truth for badge/label
resolution) instead of the thin data endpoint, and the presenter is
added to the literal-guard file list.
Gates: PHPUnit 1889 OK, PHPStan 0 errors, module:sync ok.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 22:20:39 +02:00
|
|
|
// System audit: data + export endpoints delegate badge/label resolution
|
|
|
|
|
// to SystemAuditRowPresenter, which is the enforced source of truth.
|
|
|
|
|
'modules/audit/lib/Module/Audit/Service/SystemAuditRowPresenter.php',
|
2026-04-26 18:03:42 +02:00
|
|
|
'modules/audit/pages/audit/settings-user-lifecycle/audit-data().php',
|
2026-03-26 08:13:37 +01:00
|
|
|
'modules/audit/pages/audit/import-audit/data().php',
|
2026-03-04 15:56:58 +01:00
|
|
|
'pages/admin/scheduled-jobs/data().php',
|
|
|
|
|
'pages/admin/scheduled-jobs/runs-data($id).php',
|
|
|
|
|
'pages/admin/mail-log/data().php',
|
|
|
|
|
'pages/admin/tenants/data().php',
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return list<string>
|
|
|
|
|
*/
|
2026-03-19 19:11:03 +01:00
|
|
|
public static function taxonomyLiteralGuardFiles(): array
|
2026-03-04 15:56:58 +01:00
|
|
|
{
|
|
|
|
|
return [
|
refactor(audit): extract audit domain into self-contained module
Move the entire audit subsystem (system audit, API audit, import audit,
user lifecycle audit, frontend telemetry) from core into modules/audit/.
Core decoupling via interface-based injection:
- AuditRecorderInterface replaces SystemAuditService in 10+ core services
- UserLifecycleAuditInterface / ImportAuditInterface for specialized flows
- NullAuditRecorder fallback when audit module is disabled
- ApiBootstrap/ApiResponse use null-safe callable resolvers
Module structure (modules/audit/):
- Manifest with routes, permissions, scheduler jobs, authorization policy
- 9 services, 8 repositories, 6 domain enums, 4 job handlers
- 33 page files, 4 JS files, 8 test files, migration scripts, i18n
Core cleanup:
- OperationsAuthorizationPolicy, UiCapabilityMap, PermissionService
surgically cleaned of audit-specific constants
- Sidebar template cleared of hardcoded audit navigation
- AuditModuleIsolationContractTest ensures no future core→module coupling
All quality gates pass: 1346 tests (19,276 assertions), PHPStan level 5
clean, architecture contracts verified.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:12:49 +01:00
|
|
|
'modules/audit/lib/Module/Audit/Service/SystemAuditService.php',
|
refactor(audit): extract SystemAuditRowPresenter shared by data + export
Move the row formatting that was duplicated between system-audit's
data() and export() endpoints into a single presenter. Both endpoints
now call presentAll() on the same object, so enum label translation,
actor resolution, and timestamp formatting cannot drift between the
Grid.js UI and the CSV download.
- SystemAuditRowPresenter::present()/presentAll(): canonical row shape
with outcome + outcome_label + outcome_badge, channel + channel_label,
actor_user_label with display-name-then-email fallback, and safe
defaults for every missing field.
- data().php shrinks from ~45 to ~15 lines; export().php drops its
inline outcome/channel/actor resolvers and reads the already-
resolved fields from the presenter output.
- AuditContainerRegistrar registers the presenter.
- tests/Module/Audit/Service/SystemAuditRowPresenterTest: 9 cases
covering enum normalization, unknown-value fallback, actor label
precedence (display name → email → "-"), whitespace trimming, safe
defaults for missing keys, and iterable input.
- StatusTaxonomyContractFiles: the taxonomy data contract now points
at the presenter (the single source of truth for badge/label
resolution) instead of the thin data endpoint, and the presenter is
added to the literal-guard file list.
Gates: PHPUnit 1889 OK, PHPStan 0 errors, module:sync ok.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 22:20:39 +02:00
|
|
|
'modules/audit/lib/Module/Audit/Service/SystemAuditRowPresenter.php',
|
refactor(audit): extract audit domain into self-contained module
Move the entire audit subsystem (system audit, API audit, import audit,
user lifecycle audit, frontend telemetry) from core into modules/audit/.
Core decoupling via interface-based injection:
- AuditRecorderInterface replaces SystemAuditService in 10+ core services
- UserLifecycleAuditInterface / ImportAuditInterface for specialized flows
- NullAuditRecorder fallback when audit module is disabled
- ApiBootstrap/ApiResponse use null-safe callable resolvers
Module structure (modules/audit/):
- Manifest with routes, permissions, scheduler jobs, authorization policy
- 9 services, 8 repositories, 6 domain enums, 4 job handlers
- 33 page files, 4 JS files, 8 test files, migration scripts, i18n
Core cleanup:
- OperationsAuthorizationPolicy, UiCapabilityMap, PermissionService
surgically cleaned of audit-specific constants
- Sidebar template cleared of hardcoded audit navigation
- AuditModuleIsolationContractTest ensures no future core→module coupling
All quality gates pass: 1346 tests (19,276 assertions), PHPStan level 5
clean, architecture contracts verified.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:12:49 +01:00
|
|
|
'modules/audit/lib/Module/Audit/Repository/SystemAuditLogRepository.php',
|
|
|
|
|
'modules/audit/lib/Module/Audit/Http/ApiSystemAuditReporter.php',
|
|
|
|
|
'modules/audit/lib/Module/Audit/Service/UserLifecycleAuditService.php',
|
|
|
|
|
'modules/audit/lib/Module/Audit/Repository/UserLifecycleAuditRepository.php',
|
|
|
|
|
'modules/audit/lib/Module/Audit/Service/ImportAuditService.php',
|
|
|
|
|
'modules/audit/lib/Module/Audit/Repository/ImportAuditRunRepository.php',
|
2026-04-13 23:20:05 +02:00
|
|
|
'core/Service/Scheduler/SchedulerRunService.php',
|
|
|
|
|
'core/Repository/Scheduler/ScheduledJobRepository.php',
|
|
|
|
|
'core/Repository/Scheduler/ScheduledJobRunRepository.php',
|
|
|
|
|
'core/Repository/Scheduler/SchedulerRuntimeRepository.php',
|
|
|
|
|
'core/Service/Mail/MailService.php',
|
|
|
|
|
'core/Repository/Mail/MailLogRepository.php',
|
|
|
|
|
'core/Service/Tenant/TenantService.php',
|
|
|
|
|
'core/Repository/Tenant/TenantRepository.php',
|
|
|
|
|
'core/Repository/Stats/AdminStatsRepository.php',
|
2026-03-26 08:13:37 +01:00
|
|
|
'modules/audit/pages/audit/system-audit/data().php',
|
2026-04-26 18:03:42 +02:00
|
|
|
'modules/audit/pages/audit/settings-user-lifecycle/audit-data().php',
|
2026-03-26 08:13:37 +01:00
|
|
|
'modules/audit/pages/audit/import-audit/data().php',
|
2026-03-04 15:56:58 +01:00
|
|
|
'pages/admin/scheduled-jobs/data().php',
|
|
|
|
|
'pages/admin/scheduled-jobs/runs-data($id).php',
|
|
|
|
|
'pages/admin/mail-log/data().php',
|
|
|
|
|
'pages/admin/tenants/data().php',
|
2026-03-26 08:13:37 +01:00
|
|
|
'modules/audit/pages/audit/system-audit/index().php',
|
2026-04-26 18:03:42 +02:00
|
|
|
'modules/audit/templates/settings-user-lifecycle-panel.phtml',
|
2026-03-26 08:13:37 +01:00
|
|
|
'modules/audit/pages/audit/import-audit/index().php',
|
2026-03-04 15:56:58 +01:00
|
|
|
'pages/admin/scheduled-jobs/index().php',
|
|
|
|
|
'pages/admin/mail-log/index().php',
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-19 19:11:03 +01:00
|
|
|
/**
|
|
|
|
|
* @return list<string>
|
|
|
|
|
*/
|
|
|
|
|
public static function forbiddenLiteralPatterns(): array
|
2026-03-04 15:56:58 +01:00
|
|
|
{
|
2026-03-19 19:11:03 +01:00
|
|
|
return [
|
2026-03-04 15:56:58 +01:00
|
|
|
"/\\bstatus\\s*=\\s*'(running|success|partial|failed|skipped|queued|sent|active|inactive)'/",
|
|
|
|
|
"/\\boutcome\\s*=\\s*'(success|failed|denied)'/",
|
|
|
|
|
"/\\bchannel\\s*=\\s*'(web|api|scheduler|cli)'/",
|
|
|
|
|
"/\\btrigger_type\\s*=\\s*'(scheduler|manual|cron|system)'/",
|
|
|
|
|
"/\\baction\\s*=\\s*'(deactivate|delete|restore)'/",
|
|
|
|
|
"/['\\\"]statuses['\\\"]\\s*=>\\s*'failed,skipped'/",
|
|
|
|
|
"/['\\\"]actions['\\\"]\\s*=>\\s*'restore'/",
|
|
|
|
|
"/in_array\\([^\\n]*\\[(?:[^\\]]*'(?:success|failed|denied|running|partial|skipped|queued|sent|active|inactive|scheduler|manual|web|api|cli|deactivate|delete|restore|ok|lock_not_acquired|unexpected_error)')/",
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
}
|