Files
breadcrumb-the-shire/modules/helpdesk/CLAUDE.md
2026-05-26 11:04:57 +02:00

7.8 KiB
Raw Blame History

CLAUDE.md — Helpdesk Module

Self-contained MintyPHP module. Namespace: MintyPHP\Module\Helpdesk\*. All changes stay inside modules/helpdesk/ — never touch core templates or global layout.

After any manifest change (new route, permission, slot): docker compose exec php php bin/console module:sync


Architecture

lib/Module/Helpdesk/
  HelpdeskAuthorizationPolicy.php   — all ability/permission constants + authorize()
  HelpdeskContainerRegistrar.php    — all DI bindings (add new services here)
  Handler/                          — scheduled job handlers
  Providers/HelpdeskLayoutProvider.php  — resolves can_* flags for sidebar nav
  Repository/                       — SQL only, no HTTP
  Service/                          — business logic, no HTML
pages/helpdesk/                     — actions (*.php) + views (*.phtml)
templates/
  aside-helpdesk-panel.phtml        — sidebar navigation
  helpdesk-ticket-detail.phtml      — shared ticket detail body
i18n/default_de.json + default_en.json  — 551 keys each, always add both
migrations/                         — 011 SQL files applied via module:migrate
tests/Module/Helpdesk/Service/      — 20 test files, happy path + edge case required
web/css/helpdesk.css
web/js/                             — 16 JS files, components + page scripts

Page File Naming

URL Action file View file
helpdesk/team pages/helpdesk/team/index().php team/index(default).phtml
helpdesk/handovers/edit/{id} pages/helpdesk/handovers/edit($id).php handovers/edit(default).phtml
helpdesk/dashboard pages/helpdesk/dashboard/index().php dashboard/index(default).phtml
data endpoint pages/helpdesk/foo-data().php
drawer fragment pages/helpdesk/foo-fragment($id).php foo-fragment(none).phtml

View structure pattern (always):

<div class="app-details-container">
  <section>
    <?php
    $titlebar = ['title' => t('Page title')];
    require templatePath('partials/app-details-titlebar.phtml');
    ?>
    <!-- content -->
  </section>
</div>

Permissions (10 total)

All constants in HelpdeskAuthorizationPolicy:

Constant Permission key
ABILITY_ACCESS helpdesk.access — base access, customer search + detail views
ABILITY_SETTINGS_MANAGE helpdesk.settings.manage
ABILITY_TEAM_WORKLOAD helpdesk.team-workload.view
ABILITY_RISK_RADAR helpdesk.risk-radar.view
ABILITY_SOFTWARE_PRODUCTS_MANAGE helpdesk.software-products.manage
ABILITY_HANDOVERS_VIEW helpdesk.handovers.view
ABILITY_HANDOVERS_CREATE helpdesk.handovers.create
ABILITY_HANDOVERS_MANAGE helpdesk.handovers.manage
ABILITY_UPDATES_VIEW helpdesk.updates.view
ABILITY_UPDATES_MANAGE helpdesk.updates.manage

New pages reuse existing permissions — no new permission keys without product decision.

Action file boilerplate:

Guard::requireLogin();
Guard::requireAbilityOrForbidden(HelpdeskAuthorizationPolicy::ABILITY_ACCESS);
$session = app(SessionStoreInterface::class)->all();
$tenantId = (int) ($session['current_tenant']['id'] ?? 0);

Services & Repositories

Gateways (external BC API):

  • BcODataGateway — OData V4 queries (customers, domains, tickets, contacts)
  • BcSoapGateway — SOAP (ticket communication feed, file downloads)

Core services:

  • EffectiveHelpdeskSettingsService — resolves BC config per tenant (global + override)
  • HelpdeskOAuthTokenService — OAuth2 token acquisition + cache
  • DebitorSearchService — debtor search by name/number
  • DebitorDetailService — debtor master data + contacts + tickets
  • DomainDetailService — domain/contract data + handover/update enrichment
  • DomainListService — domain list with security level enrichment
  • HandoverService — handover protocol CRUD + status transitions
  • HandoverRevisionService — revision snapshots for audit trail
  • UpdateService — software update tracking + assignment
  • SoftwareProductService — product catalog + handover schema
  • SoftwareProductSyncService — BC sync (scheduled daily 02:00 CET)
  • RiskRadarService — risk scoring engine (5 dimensions, 0100 score)
  • DomainSecurityLevelService — security level get/set (niedrig/normal/hoch/kritisch)
  • SystemRecommendationEngine — rule-based recommendation engine (no constructor)

Repositories:

  • HandoverRepository — insert, findById, listPaged, updateFieldValues, updateStatus, deleteByIds, findByDomainNo, transactions
  • UpdateRepository — insert, findByTicketNo, findByDomainNo, findAllByTenant, updateAssignment
  • SoftwareProductRepository — upsertByCode, listPaged, updateHandoverSchema, softDeleteNotInCodes
  • HandoverRevisionRepository — insert, getLatestRevisionNumber, listByHandover
  • DomainSecurityLevelRepository — findByTenantAndDomainNo, listLevelsByDomainNos, upsert
  • HelpdeskTenantSettingsRepository — findByTenantId, upsert, deleteByTenantId
  • HelpdeskTokenRepository — findValidToken, storeToken, deleteByTenantId (encrypted)

New service → register in HelpdeskContainerRegistrar::register() + add @api annotation if called from pages.


Sidebar Navigation

HelpdeskLayoutProvider resolves these flags → passed as $layoutNav['helpdesk.nav']:

can_view_dashboard, can_manage_settings, can_view_team, can_view_risk_radar, can_manage_software_products, can_view_handovers, can_create_handovers, can_manage_handovers, can_view_updates

aside-helpdesk-panel.phtml — 5 collapsible groups:

  1. Overview (bi-speedometer2) — Dashboard
  2. Lookup (bi-search) — Customers, Domains
  3. Monitoring (bi-bar-chart-line) — Team workload, Risk radar
  4. Operations (bi-clipboard-check) — Handovers, Updates
  5. Administration (bi-sliders) — Software products, Settings

Adding a nav item = 3 steps: (1) add can_* flag to HelpdeskLayoutProvider, (2) add $dashboardActive = navActive(...) + item to group in aside-helpdesk-panel.phtml, (3) add condition to $customersActive override if needed.


DB Schema (relevant tables)

Table Key columns
helpdesk_handovers id, tenant_id, status (draft/in_progress/completed/archived), debitor_no, domain_no
helpdesk_handover_revisions handover_id, revision_number, snapshot_json
helpdesk_updates id, tenant_id, status (open/assigned/done/resolved/closed), ticket_no, domain_no
helpdesk_software_products code, name, handover_schema_json
helpdesk_domain_security_levels tenant_id, domain_no, level, note
helpdesk_tenant_settings tenant_id, encrypted BC connection overrides
helpdesk_oauth_token_cache tenant_id, token (encrypted), expires_at

Tenant scope enforced on every query — always pass $tenantId to repository methods.


Tests

Location: tests/Module/Helpdesk/Service/ Pattern: ->method('foo')->willReturn([...]) — no ->with() (PHPUnit 12 incompatible with PHPStan). Every new/changed Service or Gateway needs happy path + at least one edge case test.

Run: docker compose exec php vendor/bin/phpunit modules/helpdesk/tests/


JS Components

Registered via data-app-component="<name>" on the container div:

  • helpdesk-detail — customer search detail
  • helpdesk-domain-detail — domain detail
  • helpdesk-ticket — ticket view
  • helpdesk-team — team workload
  • helpdesk-risk-radar — risk radar
  • helpdesk-settings — settings config
  • helpdesk-communication — ticket communication feed
  • helpdesk-handover-domain-select — domain picker in handover wizard
  • helpdesk-handover-schema-editor — handover schema JSON editor

CSS class prefix: helpdesk- for module-specific styles in web/css/helpdesk.css.