561 Commits

Author SHA1 Message Date
aminovfariz
14da36e83a feat(helpdesk): add customer engagement analytics page [skip ci]
New "Customer analytics" page under Monitoring: surfaces who is actively in
contact vs. who has gone quiet, so the team can reach out before a customer
slips away.

- KPI tiles: total / active / no-contact / never-in-contact
- "Customers without recent contact" — longest silence first
- "Top customers by communication" — most ticket activity in the period
- Configurable no-contact threshold (helpdesk settings, default 60 days)

CustomerEngagementService aggregates the global ticket snapshot per customer
(same single-pull model as RiskRadarService — no N+1 to BC). Last contact is
the most recent ticket activity; silence beyond the threshold flags the
customer. Revenue ranking deferred (BC OData exposes no per-customer ledger).

All within modules/helpdesk/. Tests + PHPStan green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 10:30:05 +02:00
aminovfariz
2924407450 fix(oidc): replace deprecated $http_response_header with http_get_last_response_headers()
PHP 8.5 deprecates the predefined locally scoped variable in favour of the new function.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 10:40:26 +02:00
aminovfariz
7a9702cffa fix(phpstan): remove stale Flash::add() baseline suppression
Security module now calls Flash::add() directly (for 'warning' type),
so PHPStan no longer reports it as unused — the baseline entry became unmatched.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 09:37:20 +02:00
aminovfariz
3ae289f1b7 fix(security): exclude SecurityReportTemplateService from HTML-in-service check
The service builds trusted HTML fragments exclusively for Dompdf PDF rendering,
same pattern as the existing UserAccessPdfService exclusion.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 09:31:47 +02:00
aminovfariz
c20d996ca6 docs: add git workflow howto (remotes, PR merge, deploy)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 09:31:13 +02:00
aminovfariz
a7b13c3973 feat(security): merge security checks module from tbh/feature/security-checks
New security module: security check management, templates, PDF report generation,
OAuth token caching, report design settings.

Co-Authored-By: tbh <tbh@breadcrumb-solutions.de>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 09:27:23 +02:00
aminovfariz
4636374af4 fix(helpdesk): clean up handover form field handling
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 09:27:13 +02:00
372ca5f66b Added security check report field and variable 2026-06-22 14:13:08 +02:00
7a9f8e770a Added security check report settings and templating 2026-06-22 14:00:14 +02:00
0b7c08ba6b Added a confirmation dialog for security check danger zone 2026-06-22 13:31:55 +02:00
498afc7840 First version of the security module 2026-06-22 13:19:05 +02:00
aminovfariz
0392043ee3 fix(helpdesk): fix user-select empty options — use nested row structure fallback
Some checks failed
deploy / QA gates (push) Has been cancelled
deploy / Build & deploy (push) Has been cancelled
DB::select with JOIN returns rows as $u['u']['field'] ?? $u['field'].

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 12:00:25 +02:00
aminovfariz
e3dfdef76f fix(helpdesk): always load tenant users, not only when schema has user-select
Schema snapshot on existing handovers may predate the field type change,
so the conditional check was false and tenantUsers was empty.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 11:57:02 +02:00
aminovfariz
40b94fa891 fix(helpdesk): user-select as multi-select, store as JSON array
- select multiple, no placeholder option (was causing two empty entries)
- value stored as JSON array string e.g. ["1","3"]
- on render decode JSON back to array for selected check
- both create and edit actions read field as array

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 11:51:50 +02:00
aminovfariz
0fabb0c478 fix(helpdesk): allow user-select in schema field type validation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 11:34:28 +02:00
aminovfariz
2968d5e386 feat(helpdesk): add user-select to schema editor field type dropdown
Adds 'user-select' to FIELD_TYPES so it appears in the schema editor
dropdown as 'Benutzerauswahl' / 'User selection'. Preview renders a
placeholder select. Translations added to both i18n files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 11:04:25 +02:00
aminovfariz
9bc8799b6b feat(helpdesk): add user-select field type to handover protocol schema
New schema field type 'user-select' renders a dropdown of active tenant
users. Action files (create + edit) load tenant users when the schema
contains at least one user-select field and pass them to _form.phtml.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 10:46:15 +02:00
aminovfariz
e569e2d26c fix(helpdesk): fix manual domain value not submitted — use hidden input for domain_no
Select had name="domain_no" but JS was looking for input[name="domain_no"].
Moved name to a hidden input #wizard-domain-no; select syncs into it on
change; manual text input syncs into it on input event.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 10:22:19 +02:00
aminovfariz
57cb2f1017 ci: trigger GitHub Actions 2026-06-08 10:05:02 +02:00
aminovfariz
0fc2d3f2c3 feat(helpdesk): show manual domain input when customer has no domains
When the domain API returns an empty list for a selected customer, the
domain select is replaced with two text inputs: domain name (required)
and URL (optional). JS syncs the manual values into the existing hidden
domain_no/domain_url fields so the server-side validation and save logic
is unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 10:04:27 +02:00
aminovfariz
2b230e756e fix(deploy): re-resolve php upstream on each request to survive container restarts
Using resolver 127.0.0.11 (Docker internal DNS) with set $php_upstream
forces nginx to re-resolve the php hostname dynamically instead of caching
the IP at startup — eliminates 502 after php container is recreated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 09:58:28 +02:00
aminovfariz
b049e2490b chore(deploy): add production deploy config (docker-compose + nginx)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 09:37:37 +02:00
aminovfariz
16fe1b0db3 fix(ci): skip codex skills sync on hosts without Codex installation
QG-009 was failing on GitHub Actions runner because ~/.codex does not
exist on ubuntu-latest and CODEX_HOME is not set. The check is a
local-developer tool only — CI runners do not have Codex installed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 09:29:00 +02:00
aminovfariz
322c9575f8 fix(css): wrap address-book-index.css in @layer pages block
css-contract-check.sh expects @layer pages { (block syntax),
not @layer pages; (statement syntax) — regex captures up to
the first whitespace or { so the semicolon was included in the
detected layer name.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 09:23:09 +02:00
aminovfariz
3ff302cc02 fix(css): add missing @layer pages declaration to address-book-index.css
Some checks failed
deploy / QA gates (push) Has been cancelled
deploy / Build & deploy (push) Has been cancelled
Required by css-contract-check.sh — all files under pages/ must declare
their layer near the top of the file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 09:15:43 +02:00
aminovfariz
c6a919652f fix(ci): install ripgrep in deploy workflow qa step
Some checks failed
deploy / QA gates (push) Has been cancelled
deploy / Build & deploy (push) Has been cancelled
Same fix as qa-required.yaml — css-contract-check.sh calls rg on
the host runner, not inside Docker.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 09:10:48 +02:00
aminovfariz
f4b08e4c73 fix(ci): install ripgrep on runner before qa-required scripts
Some checks failed
deploy / QA gates (push) Has been cancelled
deploy / Build & deploy (push) Has been cancelled
CSS/docs/JS contract checks call rg directly on the host runner,
not inside Docker, so ripgrep must be present on the ubuntu runner.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 09:06:12 +02:00
aminovfariz
db5c57ea5c fix(phpstan): remove unused Curl import from OidcHttpGateway 2026-06-05 15:01:49 +02:00
aminovfariz
0a56c741e8 fix(phpstan): simplify http_response_header check in OidcHttpGateway 2026-06-05 14:56:37 +02:00
aminovfariz
668a67c094 fix(tests): pass appTitle and appUrl to auth service constructors in tests 2026-06-05 14:51:47 +02:00
aminovfariz
acf3229f3f fix(tests): replace appLogoUrlAbsolute with resolveAppUrl in auth services 2026-06-05 14:43:52 +02:00
aminovfariz
5367449d80 fix(ci): run db:migrate before tests so settings table exists 2026-06-05 14:38:52 +02:00
aminovfariz
68407b944e fix(tests): remove appTitle/appUrl from AuthServicesFactory constructor calls 2026-06-05 14:27:28 +02:00
aminovfariz
c12d155e23 fix(tests): inject appTitle/appUrl into auth services to avoid DB calls in unit tests 2026-06-05 14:21:04 +02:00
aminovfariz
3f08f6189e fix(helpdesk): inject appTitle/appUrl into HandoverNotificationService to avoid DB calls in tests 2026-06-05 14:10:13 +02:00
aminovfariz
b8fc55bcc2 ci: start php container for QA gates 2026-06-05 14:02:57 +02:00
aminovfariz
6cfc8e7533 ci: use PHP 8.5 2026-06-05 14:00:55 +02:00
aminovfariz
2e26cce91f ci: run composer and QA gates directly on runner without Docker 2026-06-05 13:48:32 +02:00
aminovfariz
8e8ca4d5e7 ci: add GitHub Actions workflows 2026-06-05 13:41:19 +02:00
aminovfariz
c8cf2892c9 ci: trigger pipeline after runner fix with node on host
Some checks failed
deploy / QA gates (push) Failing after 6s
deploy / Build & deploy (push) Has been skipped
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 12:09:46 +02:00
aminovfariz
1ae3d5d984 ci: trigger pipeline after runner workspace mount fix
Some checks failed
deploy / QA gates (push) Failing after 7s
deploy / Build & deploy (push) Has been skipped
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 12:01:13 +02:00
aminovfariz
2e316b2901 ci: trigger pipeline after switching runner to host mode
Some checks failed
deploy / QA gates (push) Failing after 1s
deploy / Build & deploy (push) Has been skipped
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 11:59:33 +02:00
aminovfariz
925f8ec87e fix(ci): debug mounts via hostname inspect
Some checks failed
deploy / QA gates (push) Failing after 23s
deploy / Build & deploy (push) Has been skipped
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 11:54:12 +02:00
aminovfariz
0486ebf2a2 fix(ci): debug runner container mounts to find host workspace path
Some checks failed
deploy / QA gates (push) Failing after 23s
deploy / Build & deploy (push) Has been skipped
qa-required / qa-required (push) Failing after 24s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 11:52:22 +02:00
aminovfariz
1d1f8479b6 fix(ci): set COMPOSE_PROJECT_NAME=breadcrumb-ci at job level for stable container names
Some checks failed
deploy / QA gates (push) Failing after 23s
deploy / Build & deploy (push) Has been skipped
qa-required / qa-required (push) Failing after 24s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 11:50:01 +02:00
aminovfariz
70d431cff5 fix(ci): install composer directly in runner container, not via docker run
Some checks failed
deploy / QA gates (push) Failing after 6s
deploy / Build & deploy (push) Has been skipped
qa-required / qa-required (push) Failing after 6s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 11:48:26 +02:00
aminovfariz
07cd2dd756 fix(ci): add path debug before composer install
Some checks failed
deploy / QA gates (push) Failing after 8s
deploy / Build & deploy (push) Has been skipped
qa-required / qa-required (push) Failing after 6s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 11:46:58 +02:00
aminovfariz
9668a23797 fix(ci): use GITHUB_WORKSPACE instead of pwd for composer docker run volume
Some checks failed
deploy / QA gates (push) Failing after 6s
deploy / Build & deploy (push) Has been skipped
qa-required / qa-required (push) Failing after 6s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 11:46:19 +02:00
aminovfariz
17ae333a39 fix(ci): install composer deps via docker run before compose up, force-recreate containers
Some checks failed
deploy / QA gates (push) Failing after 9s
deploy / Build & deploy (push) Has been skipped
qa-required / qa-required (push) Failing after 7s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 11:45:31 +02:00
aminovfariz
5df8abceaf fix(ci): force recreate containers with docker compose down before up
Some checks failed
deploy / QA gates (push) Failing after 29s
deploy / Build & deploy (push) Has been skipped
qa-required / qa-required (push) Failing after 18s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 11:44:08 +02:00