2026-06-22 13:19:05 +02:00
|
|
|
|
# CLAUDE.md — Security Module
|
|
|
|
|
|
|
|
|
|
|
|
Self-contained MintyPHP module. Namespace: `MintyPHP\Module\Security\*`. **Standalone** —
|
|
|
|
|
|
`requires: []`, no dependency on helpdesk. All changes stay inside `modules/security/`.
|
|
|
|
|
|
|
|
|
|
|
|
After any manifest change (route, permission, slot): `docker compose exec php php bin/console module:sync`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## What it does
|
|
|
|
|
|
|
|
|
|
|
|
Lets the security officer run **security checks** for customers. A check is created via a wizard
|
|
|
|
|
|
(select customer → domain → software product), then tracked on a checklist workspace that combines:
|
|
|
|
|
|
|
|
|
|
|
|
1. A **fixed 7-step internal process** (`SecurityCheckProcess`, identical for every check), and
|
|
|
|
|
|
2. A **per-product technical checklist** defined as a reusable **template** (the product catalog is
|
|
|
|
|
|
owned by this module — the templates *are* the product list).
|
|
|
|
|
|
|
|
|
|
|
|
Overall status (`open` → `in_progress` → `completed`, plus manual `archived`) is **derived** from
|
|
|
|
|
|
checklist progress. Each step/item records who completed it and when (completion log).
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Architecture
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
lib/Module/Security/
|
|
|
|
|
|
SecurityAuthorizationPolicy.php — ability/permission constants + authorize()
|
|
|
|
|
|
SecurityContainerRegistrar.php — all DI bindings (add new services here)
|
|
|
|
|
|
Providers/SecurityLayoutProvider.php — resolves can_* flags for the sidebar
|
|
|
|
|
|
Repository/ — SQL only (tenant-scoped, prepared statements)
|
|
|
|
|
|
Service/
|
|
|
|
|
|
SecurityCheckProcess.php — fixed 7-step process + progress/status math (pure, no DI)
|
|
|
|
|
|
SecurityCheckService.php — check CRUD, saveState, status derivation, archive
|
|
|
|
|
|
SecurityCheckTemplateService.php— template CRUD + tech-schema validation/slugify
|
|
|
|
|
|
SecurityBcSettingsGateway.php — global BC connection settings (core settings table, encrypted)
|
|
|
|
|
|
SecurityOAuthTokenService.php — OAuth2 token acquire + encrypted cache
|
|
|
|
|
|
SecurityBcGateway.php — thin BC OData (ONLY customer-search + domains-for-customer)
|
2026-06-22 14:00:14 +02:00
|
|
|
|
SecurityReportPdfService.php — customer PDF report (Dompdf); picks custom template or built-in PHTML default
|
|
|
|
|
|
SecurityReportSettingsGateway.php— report HTML/CSS template (core settings table, clear text)
|
|
|
|
|
|
SecurityReportTemplateService.php— {{var}} substitution into the admin template + default scaffold (pure)
|
|
|
|
|
|
SecurityReportLogoService.php — report logo upload/serve (storage/security/report-logo, ImageUploadTrait)
|
2026-06-22 13:19:05 +02:00
|
|
|
|
pages/security/ — actions (*.php) + views (*.phtml)
|
|
|
|
|
|
checks/report($id).php — streams the customer report PDF (gated on steps 1–5 complete)
|
2026-06-22 14:00:14 +02:00
|
|
|
|
report-design/ — report look config: logo upload + HTML/CSS template editor; logo-file() serves the logo (settings.manage)
|
2026-06-22 13:19:05 +02:00
|
|
|
|
templates/aside-security-panel.phtml— sidebar navigation
|
2026-06-22 14:00:14 +02:00
|
|
|
|
templates/pdf/customer-report.phtml — built-in default report layout (used when no custom template is stored)
|
2026-06-22 13:19:05 +02:00
|
|
|
|
i18n/default_de.json + default_en.json — keep both in sync (identical key sets)
|
|
|
|
|
|
migrations/ — 003 SQL files (module:migrate)
|
|
|
|
|
|
web/css/security.css | web/js/ — module styles + runtime components + page scripts
|
2026-06-22 14:00:14 +02:00
|
|
|
|
tests/Module/Security/Service/ — 10 test files (happy path + edge case)
|
2026-06-22 13:19:05 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Permissions (6)
|
|
|
|
|
|
|
|
|
|
|
|
All constants in `SecurityAuthorizationPolicy`:
|
|
|
|
|
|
|
|
|
|
|
|
| Constant | Key |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| `ABILITY_ACCESS` | `security.access` — gates the main-menu entry |
|
|
|
|
|
|
| `ABILITY_CHECKS_VIEW` | `security.checks.view` |
|
|
|
|
|
|
| `ABILITY_CHECKS_CREATE` | `security.checks.create` — create + edit the checklist |
|
|
|
|
|
|
| `ABILITY_CHECKS_MANAGE` | `security.checks.manage` — archive, delete |
|
|
|
|
|
|
| `ABILITY_TEMPLATES_MANAGE` | `security.templates.manage` |
|
|
|
|
|
|
| `ABILITY_SETTINGS_MANAGE` | `security.settings.manage` |
|
|
|
|
|
|
|
|
|
|
|
|
Gate every action with `Guard::requireAbilityOrForbidden(...)`; tenant scope enforced in repositories.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## DB schema
|
|
|
|
|
|
|
|
|
|
|
|
| Table | Key columns |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| `security_check_templates` | tenant_id, product_code (uniq), product_name, tech_schema_json, active, version |
|
|
|
|
|
|
| `security_checks` | tenant_id, debitor_no, domain_no, product_code, template_id, owner_user_id, status, process_state_json, tech_schema_snapshot_json, tech_state_json |
|
|
|
|
|
|
| `security_oauth_token_cache` | tenant_id, access_token_encrypted, expires_at |
|
|
|
|
|
|
|
|
|
|
|
|
`tech_schema_snapshot_json` freezes the template's checklist onto the check at creation time, so later
|
|
|
|
|
|
template edits never mutate in-flight checks. JSON state shapes:
|
|
|
|
|
|
- tech schema: `{version, items:[ {type:"section",label}, {type:"check",key,label,hint?} ]}`
|
|
|
|
|
|
- process_state: `{<stepKey>: {done, by, at, note, fields?}}`
|
|
|
|
|
|
- tech_state: `{<itemKey>: {done, by, at, note}}`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Routes / pages
|
|
|
|
|
|
|
|
|
|
|
|
Main menu entry via the `aside.tab_panel` slot (icon `bi-shield-check`, permission `security.access`).
|
|
|
|
|
|
Pages: `security/checks` (list), `security/checks/create` (wizard), `security/checks/edit/{id}`
|
|
|
|
|
|
(workspace), `security/checks/report/{id}` (streams the customer PDF report),
|
2026-06-22 14:00:14 +02:00
|
|
|
|
`security/templates` (+create/edit/{id}), `security/settings`, `security/report-design`
|
|
|
|
|
|
(customer report look: logo + HTML/CSS template), plus data endpoints
|
2026-06-22 13:19:05 +02:00
|
|
|
|
`security/checks-data`, `security/templates-data`, `security/customer-search-data`,
|
2026-06-22 14:00:14 +02:00
|
|
|
|
`security/customer-domains-data`, `security/settings/test-connection-data`,
|
|
|
|
|
|
`security/report-design/logo-file` (serves the uploaded report logo).
|
|
|
|
|
|
|
|
|
|
|
|
`report-design` reuses the `security.settings.manage` permission (no new permission key).
|
2026-06-22 13:19:05 +02:00
|
|
|
|
|
|
|
|
|
|
## JS runtime components
|
|
|
|
|
|
|
|
|
|
|
|
`data-app-component` on the container: `security-customer-domain-select` (wizard domain picker),
|
|
|
|
|
|
`security-check-workspace` (live progress), `security-template-schema-editor` (checklist editor),
|
|
|
|
|
|
`security-settings` (auth-mode toggle + connection test). List pages load their own
|
|
|
|
|
|
`web/js/pages/*-index.js` via `<script type="module">`.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Tests
|
|
|
|
|
|
|
|
|
|
|
|
`docker compose exec php vendor/bin/phpunit modules/security/tests/`
|
|
|
|
|
|
Pattern: mock repositories, `->willReturn(...)` / `->willReturnCallback(...)` to capture args
|
|
|
|
|
|
(avoid `->with()`). Every new/changed Service or Gateway needs happy path + edge case.
|
|
|
|
|
|
|
|
|
|
|
|
## Deferred (not built)
|
|
|
|
|
|
|
|
|
|
|
|
Internal report PDF (the customer report is built — see `SecurityReportPdfService`),
|
|
|
|
|
|
per-tenant BC connection overrides, per-step assignment, revision history.
|