Commit Graph

596 Commits

Author SHA1 Message Date
Serreau Jovann
25354f9052 Fix decodeAndVerifyHash to have only 2 returns by merging base64 decode and pipe check guards
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:02:01 +02:00
Serreau Jovann
1b3371cb7f Add comprehensive test coverage for AttestationController, LegalController, AdminController, AccountController and AnalyticsEvent entity
- AttestationController: fix decodeAndVerifyHash to have max 3 returns, add 11 tests covering all routes (check, ventesRef, ventes) and all decodeAndVerifyHash branches (invalid base64, missing pipe, bad signature, bad JSON, valid hash with/without registered attestation), plus generateHash unit tests with unicode
- LegalController: add 6 tests for RGPD POST routes (rgpdAccess and rgpdDeletion) covering empty fields, data found, and no data found scenarios
- AdminController: add 10 tests for analytics page (all period filters + access denied) and orderTickets endpoint (single ticket PDF, multiple tickets ZIP, order not found, no tickets)
- AccountController: add 17 tests for downloadTicket (success/denied/404), resendTicket (success/denied/404), cancelTicket (success/denied/404), createAccreditation (staff/exposant/empty fields/no categories/invalid type), eventAttestation (with categories/billets/empty selection)
- AnalyticsEvent entity: new test file with 8 tests covering constructor defaults, all getters/setters, nullable fields, and fluent interface

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 18:41:18 +02:00
Serreau Jovann
a139feef07 init 2026-04-01 17:19:13 +02:00
Serreau Jovann
626510e692 Add force validate button in admin orders + fix Stripe Connect account in sync
- Add POST /admin/commandes/{id}/forcer-validation to force validate pending
  orders (generates tickets, sends emails, notifies organizer)
- Add "Forcer validation" button in orders template for pending orders
- Fix retrievePaymentIntent to query on organizer's Connect account
- Update stripe:sync to pass organizer stripeAccountId when checking payments
- Add 3 tests for force validation (pending, non-pending, not found)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 14:22:56 +02:00
Serreau Jovann
02519dcfa8 Add pending orders reconciliation to stripe:sync command
- Add retrievePaymentIntent() to StripeService
- StripeSyncCommand now checks pending orders against Stripe API:
  - succeeded: generates tickets, sends emails, notifies organizer
  - canceled: marks order as cancelled + audit log
  - requires_payment_method: marks as cancelled + audit + failure email
  - other statuses: logs as still pending
- Add 13 tests covering accounts sync + all pending order scenarios

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 14:14:29 +02:00
Serreau Jovann
381acd603e Split Stripe webhooks into 2 endpoints: insta (payments) and leger (Connect)
- /stripe/webhook → /webhooks/stripe/insta (paiements, payouts, disputes, subscriptions)
- /stripe/webhook/connect → /webhooks/stripe/leger (gestion comptes Connect)
- Rename env vars: STRIPE_WEBHOOK_SECRET → STRIPE_WEBHOOK_SECRET_INSTA,
  STRIPE_WEBHOOK_SECRET_CONNECT → STRIPE_WEBHOOK_SECRET_LEGER
- Update StripeService, CsrfProtectionSubscriber, vault, env files and all tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 14:07:49 +02:00
Serreau Jovann
1c559263a8 Add analytics.js test suite with 100% line/function coverage (16 tests)
Tests cover: init with missing config, importKey failure, visitor creation,
session reuse, sendBeacon usage, 403 retry flow, network errors, decrypt
failures, setAuth with/without session/key, and authenticated user tracking.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 13:54:43 +02:00
Serreau Jovann
97ef920514 Ignore CSP violations from browser userscripts (source-file: user-script)
Add 'user-script' to ignored source files in CspReportController to filter
out false positive CSP violations triggered by browser extensions/userscripts.
Add corresponding test case.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 11:33:09 +02:00
Serreau Jovann
622e1894ae aa 2026-03-30 13:43:06 +02:00
Serreau Jovann
918a52415d add new system for upgrade speed 2026-03-30 11:13:22 +02:00
Serreau Jovann
2f2da97f68 Fix code style: add blank line before constructor in AttestationController
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 08:58:07 +02:00
Serreau Jovann
fe91d26163 Add AnalyticsControllerTest with 100% coverage (19 tests, 70 assertions)
- Test token validation (invalid token returns 404)
- Test request validation (missing body, missing 'd' field, invalid JSON return 400)
- Test decryption validation (invalid encrypted data returns 403)
- Test new visitor creation with full fields, optional fields, mobile/tablet UA
- Test page view dispatch with valid hash, default values
- Test page view rejection with invalid/missing hash (403)
- Test setUser dispatch with valid hash
- Test visitor UID format (UUID v4), IP hash, UA truncation, language truncation
- Test response hash is verifiable by crypto service

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 08:48:03 +02:00
Serreau Jovann
3468b1288d Improve mobile/tablet responsive, fix structured data, update deploy schedule and fix HTML issues
- Add responsive breakpoints (sm/md) to event_detail.html.twig: adaptive titles, stacked ticket layout on mobile, reduced padding/spacing
- Add responsive breakpoints to order templates (guest, summary, public, payment, success): adaptive typography, padding, and layouts
- Fix BreadcrumbList JSON-LD: escape names with json_encode, remove item URL from last breadcrumb
- Update deploy.yml cron schedule from 3h/13h/19h/23h to 1h/22h
- Add <title> tags to rgpd_deletion.html.twig and rgpd_access.html.twig
- Add scope attributes to all <th> tags in rgpd_access.html.twig
- Replace deprecated width/cellpadding/cellspacing HTML attributes with CSS in scan_force_notification email

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 08:40:28 +02:00
Serreau Jovann
3a40de1ba0 Reduce return counts and fix code smells across controllers and services
- ApiAccountController::lookup: reduce from 4 to 3 returns via ternary
- AttestationController::ventes: reduce from 5 to 2 returns by extracting
  decodeAndVerifyHash() helper; add TPL_NOT_FOUND_VENTES constant for the
  template literal duplicated 5 times
- AnalyticsCryptoService::decrypt: reduce from 4 to 2 returns by extracting
  tryDecryptJsFormat() helper
- InfraService::fmtDuration: reduce from 4 to 1 return using match(true)
- InfraService: replace nested ternary with match(true) for SSL status

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 20:23:08 +01:00
Serreau Jovann
0df78f75ae Fix self-referencing constant NO_SNAPSHOT_MSG in AdminController
The constant was incorrectly defined as self::NO_SNAPSHOT_MSG = self::NO_SNAPSHOT_MSG
causing a PHP fatal error. Replace with the actual string value.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 19:06:51 +01:00
Serreau Jovann
ea50f8e740 Add POST /api/account/lookup route for account lookup by email
New API endpoint secured by X-App-Secret header (no JWT auth required).
Accepts an email in the request body and returns the user's id and
stripeAccountId if present. Includes 6 unit tests covering all cases
(success, missing secret, invalid secret, missing email, user not found).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 19:03:15 +01:00
Serreau Jovann
f2f8b31d6e Reduce method returns and cognitive complexity across controllers
- AnalyticsController::track: extract handleTrackData(), reduce from 7 to 3 returns
- ApiAuthController::ssoValidate: extract ssoError/ssoSuccess helpers, reduce from 6 to 3 returns
- ApiLiveController::scan: extract findTicketFromRequest(), reduce from 4 to 3 returns
- ApiLiveController::scanForce: flatten logic, reduce from 6 to 3 returns
- ApiLiveController::processScan: extract isAlwaysValidTicket, checkRefusal,
  markScannedAndRespond, reduce cognitive complexity from 16 to under 15

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 22:22:41 +01:00
Serreau Jovann
5062f356f1 Extract DQL_EXCLUDE_INVITATIONS and NO_SNAPSHOT_MSG constants in AdminController
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 22:20:36 +01:00
Serreau Jovann
b2c1cee51a Fix MeilisearchServiceTest: use ArrayAdapter instead of CacheInterface mock
ArrayAdapter implements both CacheInterface and CacheItemPoolInterface,
matching the intersection type on the constructor parameter.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 22:07:24 +01:00
Serreau Jovann
25564e4244 Fix all PHPStan errors: add missing iterable types and fix CacheInterface::clear()
- Add @param array<string, mixed> to AnalyticsController::createVisitor()
- Add @param/@return array<string, mixed> to AnalyticsCryptoService encrypt/decrypt
- Add @param array<string, mixed>|null to InfraService calcCpuPercent/calcMemory
- Merge duplicate docblocks on InfraService::calcMemory()
- Use intersection type CacheInterface&CacheItemPoolInterface for MeilisearchService cache

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:57:21 +01:00
Serreau Jovann
aeb4df8d92 Add Attestation, AnalyticsEvent, AnalyticsUniqId to PHPStan $id ignore list
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:54:41 +01:00
Serreau Jovann
af6cea00a8 Fix PHPStan errors and SonarQube warnings
- Remove redundant && $fix checks in MeilisearchConsistencyCommand (always true after early return)
- Add @param PHPDoc for Attestation::__construct $payload parameter
- Extract PDF_SUFFIX constant to avoid duplicated ".pdf"" literal

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:53:48 +01:00
Serreau Jovann
d77ee25bcf Apply PHP CS Fixer code style fixes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:40:52 +01:00
Serreau Jovann
e0245afca5 Refactor AccountController: extract constants, reduce returns and cognitive complexity
- Add DQL_EXCLUDE_INVITATIONS, DQL_BB_EXCLUDE_INVITATIONS, CONTENT_TYPE_PDF constants
- Reduce createAccreditation from 4 to 3 returns by combining validations
- Extract collectAttestationBillets, buildAttestationStats, buildAttestationTicketDetails
  from eventAttestation to reduce cognitive complexity from 18 to under 15
- Remove unused $totalRevenue, duplicate $label, and securityKey from attestation details

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:39:20 +01:00
Serreau Jovann
02cce5608c Fix MeilisearchConsistencyCommand: remove unused variable, redundant array_values, always-true condition
- Remove unused $indexes variable (listIndexes() kept as health check)
- Make $fixMissing parameter required (always passed), remove && $fixMissing check
- Remove redundant array_values() on array_map result (already a list)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:36:14 +01:00
Serreau Jovann
59cf8dccde Fix linter warnings in analytics module: codePoint, const, optional chaining, Number.parseInt
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:34:22 +01:00
Serreau Jovann
20a6be0504 Destructure browser globals from globalThis in analytics module
Fixes linter warnings for sessionStorage, navigator, document, location, screen, fetch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:11:15 +01:00
Serreau Jovann
73adc0a735 Use globalThis for TextEncoder, TextDecoder, and atob browser globals
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:08:37 +01:00
Serreau Jovann
a71493b87c Replace charCodeAt with codePointAt in analytics module
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:07:26 +01:00
Serreau Jovann
b062a5203b Use globalThis.atob/btoa in analytics module for linter compatibility
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:06:55 +01:00
Serreau Jovann
176b70650b Add SRI integrity hashes for CDN scripts and replace md5 with xxh128 for cache keys
- Add integrity/crossorigin attributes to chart.js and html5-qrcode CDN scripts
- Replace md5() with hash('xxh128') for Meilisearch cache key generation (non-sensitive context)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:06:00 +01:00
Serreau Jovann
1fe2c3a1d3 Fix scanner manifest test: update expected start_url to /scanner/
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 18:37:51 +01:00
Serreau Jovann
1796f2d022 Add e_ticket_test database to pgbouncer-dev config for test environment
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 18:31:17 +01:00
Serreau Jovann
2d14075d54 Fix infra page: add missing error key for redis/postgres/pgbouncer defaults
Template accesses redis_global.error, postgres.error and pgbouncer.error
in the else branch when connected=false, but the key was not provided.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 18:27:52 +01:00
Serreau Jovann
e8d2744333 Fix infra page crash when snapshot missing: provide default server values
Template accesses server.hostname etc. but server was passed as empty array
when infra.json does not exist. Now provides all expected keys with '?' defaults.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 18:13:26 +01:00
Serreau Jovann
21aa94c833 Fix cookie-consent tests: remove tests for analytics/cloudflare script loading
The script loading logic was removed from initCookieConsent() but tests
still expected it. Removed 5 obsolete tests, kept 7 core consent tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:21:55 +01:00
Serreau Jovann
58e139e261 Apply PHP CS Fixer code style fixes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:19:15 +01:00
Serreau Jovann
4caff2e032 Fix SonarQube warnings: reduce returns, extract constants, fix viewport
- Reduce requireStripeReady() from 4 returns to 2 by combining conditions
- Extract SCANNER_PATH constant in ScannerController to avoid duplicated "/scanner/" literal
- Remove user-scalable=no from scanner viewport meta (WCAG accessibility)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:16:36 +01:00
Serreau Jovann
d8508f3c96 Refactor MeilisearchConsistencyCommand: reduce cognitive complexity and extract constants
- Extract filterUsers() and createUserIndex() from checkUserIndex() to reduce cognitive complexity from 16 to under 15
- Add INDEXES_ENDPOINT constant to replace duplicated "/indexes" literal

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:15:41 +01:00
Serreau Jovann
61946f724e Fix scanner service worker CDN URL and clean up MeilisearchConsistencyCommand
- Replace unpkg.com with cdn.jsdelivr.net in sw.js cache list
- Fix sw.js scope to /scanner/
- Remove unused $indexes parameter from checkAllIndexes()
- Extract duplicated " [%s] Index missing" literal to INDEX_MISSING_MSG constant

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:14:33 +01:00
Serreau Jovann
15616167d0 Add attestation system with digital signature, public verification, and detailed ticket listing
- Create Attestation entity with reference, signature hash (HMAC-SHA256), event, user, payload
- Add migration Version20260326180000 for attestation table
- Save each attestation in DB with unique signature for tamper-proof verification
- Add public route /attestation/ventes/r/{reference} for QR code verification (short URL)
- Keep fallback /attestation/ventes/{hash} route for base64-signed verification
- Public page shows "Attestation conforme" with signature proof, no detailed data
- QR code on PDF now uses short reference URL instead of full base64 hash (scannable)
- Increase QR code resolution to 300px for better readability
- Display verification URL on PDF next to QR code

Attestation PDF improvements:
- Rename "ATTESTATION DE VENTES" to "ATTESTATION"
- Add two modes: "Attestation detaillee" (with ticket list) and "Attestation simple" (certification only)
- Simple mode: certifies figures are valid, only paid billets/votes confirmed by Stripe count
- Detailed mode: adds full ticket listing with reference, order number, billet name, buyer name
- No amounts displayed in either mode
- Gold color scheme (#fabf04) for headers, borders, table headers, summary box
- Larger text in QR verification box for readability

Scanner: ROLE_ROOT buyer tickets always validate at scan

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:13:40 +01:00
Serreau Jovann
822bf8915f Scanner: SSO login, 2 scan modes (camera/security key), sound feedback, order details, force validation, staff/exposant badges
- Add SSO login button to scanner PWA with Keycloak redirect flow via session state
- Add manual scan mode via security key (16 chars) alongside QR camera scan
- Add audio feedback: good (accepted), warning (already scanned), refused sounds
- Add unique scan counter per reference (no double counting same ticket)
- Add order details display in scan results (order number, email, total, items)
- Add force validation button for refused tickets (organizer/ROLE_ROOT only), sends email notification
- Add already_scanned warning only for same-day scans, exit_definitive only same day
- Staff and exposant tickets always validate regardless of state

API: ROLE_ROOT access to all events, categories, billets, and scan endpoints

- ROLE_ROOT bypasses ownership checks on all /api/live/* endpoints
- ROLE_ROOT can login via API (email/password and SSO)
- Scan API accepts securityKey parameter in addition to reference
- Scan response includes billetType, buyerEmail, and full order details with items

Event management: tickets tab, staff/exposant accreditations, attestation PDF

- Add Tickets tab listing all sold tickets with search, download PDF, resend email, cancel actions
- Add Staff/Exposant accreditation form in Invitations tab, generates dedicated non-buyable billet
- Add Attestation tab to generate sales certificate PDF with category/billet selection
- PDF billet template shows STAFF/EXPOSANT badge with distinct colors (black/purple)
- Exclude invitations from all financial stats (event stats, admin dashboard, organizer finances)
- Fix sold counts to exclude invitations in categories recap
- Use actual Stripe fee parameters instead of hardcoded values in commission calculations
- Add commission detail breakdown (E-Ticket + Stripe) in categories and stats tabs

Admin: download tickets for orders

- Add download button on admin orders page (single PDF or ZIP for multiple tickets)

Scanner PWA fixes: CSP (unpkg -> jsdelivr), service worker scope (/scanner/)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 15:50:42 +01:00
Serreau Jovann
6ce56c11e0 Clear sessionStorage on 403 and retry with fresh visitor
When SECRET_ANALYTICS changes (deploy), old uid/hash become invalid.
On 403, clear session and auto-retry with a new visitor creation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 13:41:34 +01:00
Serreau Jovann
832387876e Fix robots.txt: replace /track/ with /t/ for analytics endpoint
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 13:01:30 +01:00
Serreau Jovann
19b973ebc0 Allow indexing of legal pages in robots.txt
Mentions legales, CGU, CGV, hebergement, cookies, RGPD, conformite
are now allowed for crawling instead of disallowed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 13:00:06 +01:00
Serreau Jovann
6062a35d97 Fix WCAG contrast on organizers page: text-gray-400 -> text-gray-600
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 12:57:43 +01:00
Serreau Jovann
220ea937dc Fix WCAG contrast on events page and add width/height to logo
- Labels and card text: text-gray-400 -> text-gray-600 on #fbfbfb bg
- Empty state message: text-gray-400 -> text-gray-600 on white bg
- Add explicit width/height to navbar logo to prevent CLS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 12:56:54 +01:00
Serreau Jovann
d1fed64d72 Fix WCAG contrast issues: yellow-500->700, indigo-600->800 on links
- text-yellow-500 on white bg had ratio ~1.9 (need 4.5), now text-yellow-700
- text-indigo-600 links on white bg had ratio ~3.8, now text-indigo-800
  with permanent underline for link visibility (WCAG 1.4.1)
- Cookie banner link also updated

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 12:55:56 +01:00
Serreau Jovann
3b4b51e3f2 Clear Symfony + Redis cache before migrations in deploy
Prevents stale Doctrine L2 cache and app cache from causing issues
after schema changes. Clears both filesystem cache and Redis pool.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 12:50:35 +01:00
Serreau Jovann
83583e0d3d Enable Doctrine L2 cache and add Redis cache pools
Doctrine Second Level Cache (NONSTRICT_READ_WRITE) on:
- Event, User, Category, Billet, BilletDesign
- Default region: 1h TTL, short_lived region: 5min TTL

Redis cache pools added:
- app.cache.events (30min) — for event listings
- app.cache.homepage (5min) — for homepage data
- doctrine.result_cache_pool — DQL result cache via Redis
- doctrine.system_cache_pool — metadata/query cache

All pools backed by Redis DB 2. Reduces DB queries significantly
for read-heavy pages (event listings, user profiles, categories).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 12:50:13 +01:00