198 Commits

Author SHA1 Message Date
Serreau Jovann
efe7f75994 Secure /ma-commande URLs with accessToken to prevent brute force
- Add accessToken (32 hex chars) to BilletBuyer, generated at creation
- URLs now: /ma-commande/{orderNumber}/{token} and /ma-commande/{orderNumber}/{token}/billet/{ref}
- Both orderNumber AND token must match to access order page
- Token is random, unpredictable, unique per order
- Migration generates tokens for existing rows

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 16:48:24 +01:00
Serreau Jovann
a18e6d4414 Use order number instead of reference in confirmation email
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 16:44:57 +01:00
Serreau Jovann
b0dead8120 Add security key to BilletOrder, QR code helper text
- securityKey: HMAC-SHA256(reference, APP_SECRET) truncated to 16 hex chars
- Generated automatically at ticket creation via BilletOrderService
- Deterministic: same reference + secret = same key, verifiable server-side
- Cannot be forged without knowing APP_SECRET
- PDF: "Presentez ce QR code pour valider votre ticket" under QR code
- PDF: "Cle de securite" displayed with letter-spacing
- Tests: generateSecurityKey determinism, uniqueness, format

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 16:43:59 +01:00
Serreau Jovann
6cd91a7c8e Add orga/description block before footer, QR code with base64 reference, event QR link
- QR code (top): contains ticket reference in base64 for scanning
- New block before footer: 2 columns - left: orga info (name, SIRET, address,
  email, phone, website), right: event description + QR code linking to event page
- Remove orga info from event info section (moved to dedicated block)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 16:40:14 +01:00
Serreau Jovann
c3fda2f10a Add organizer name, email, phone in billet PDF info section
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 16:37:29 +01:00
Serreau Jovann
ececeef3b4 Replace header with Billet Entree - event name - ticket name
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 16:36:45 +01:00
Serreau Jovann
e1e98e752d Add isInvitation to BilletOrder, orga details in PDF footer, rename Sortie libre
- Add isInvitation (nullable bool) to BilletOrder: null=no badge, true=invitation
- PDF footer: add SIRET, email, phone of organizer
- PDF: show invitation badge based on ticket.isInvitation instead of design
- Rename "Sortie libre" to "Sortie - Entree illimitee"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 16:36:29 +01:00
Serreau Jovann
fba654fad7 Fix PDF taking 50%: set body width to 210mm, use percentage column widths
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 16:34:22 +01:00
Serreau Jovann
0dbc508258 Remove ETICKET reference display from order pages, add event/orga info to public page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 16:32:01 +01:00
Serreau Jovann
50c8fe17a7 Fix PDF template for dompdf (table layout instead of CSS Grid), add order number everywhere
- Rewrite pdf/billet.html.twig with table-based layout compatible with dompdf
- Add order number (orderNumber) and order reference on PDF ticket
- Show order number on all order pages: guest, payment, public, summary partial

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 16:30:04 +01:00
Serreau Jovann
e593c5349c Handle 3DS redirect: generate tickets on success, show error on failure
- Check redirect_status query param on confirmation page
- On succeeded: generate BilletOrders + send email with PDF tickets
- On failed: show error with retry button
- Success page links to /ma-commande/{reference} for ticket download

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 16:14:05 +01:00
Serreau Jovann
d0391e5fda Replace Stripe Checkout with Stripe Elements for in-page payment
- PaymentIntent instead of Checkout Session on connected account
- Stripe Elements Payment Element with neo-brutalist theme
- stripe-payment.js module with waitForStripe() for deferred loading
- No inline scripts (CSP compliant), data attributes on container
- Add order_number (YYYY-MM-DD-increment) to BilletBuyer
- Payment page redesign: full-width vertical layout with event info,
  buyer info, billet listing with images/descriptions, payment form
- CSP: add js.stripe.com to script-src, api.stripe.com to connect-src
- Add stripe_pk parameter in services.yaml
- Add head block to base.html.twig for page-specific scripts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 16:13:06 +01:00
Serreau Jovann
5fefe22e99 Reduce returns in create(), add REF_PATTERN constant, title tag, table headers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:51:22 +01:00
Serreau Jovann
2efb5f176a Replace isScanned with state (valid/invalid/expired) and firstScannedAt on BilletOrder
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:15:32 +01:00
Serreau Jovann
2b48d2081f Remove /ticket/verify route and template
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:13:09 +01:00
Serreau Jovann
52cb19df8b Add BilletOrder entity, PDF generation, email with QR codes, public order page
- BilletOrder entity: individual tickets with unique ETICKET-XXXX reference,
  billetBuyer link, billet link, isScanned, scannedAt for entry control
- BilletOrderService: generates tickets after payment, creates A4 PDF with
  BilletDesign colors if present (default otherwise), real QR code via
  endroid/qr-code, event poster + org logo as base64, sends confirmation
  email with all ticket PDFs attached
- PDF template (pdf/billet.html.twig): A4 layout matching preview design,
  real QR code linking to /ticket/verify/{reference}
- Email template: order recap table, ticket references list, link to
  /ma-commande/{reference}
- Public order page /ma-commande/{reference}: no auth required, shows
  order details, ticket list with individual PDF download links
- Ticket verification page /ticket/verify/{reference}: shows valid/scanned
  status with ticket and event details
- Download route /ma-commande/{ref}/billet/{ticketRef}: generates PDF on-the-fly
- Migration for billet_order table with unique reference index
- BilletOrderTest: 8 tests, 24 assertions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:04:45 +01:00
Serreau Jovann
7167a58c7c Add reservation flow: BilletBuyer, guest checkout, Stripe payment
- Create BilletBuyer entity: event, user (nullable for guests), firstName,
  lastName, email, reference (ETICKET-XXXX-XXXX-XXXX), totalHT, status,
  stripeSessionId, paidAt, items (OneToMany)
- Create BilletBuyerItem entity: billet, billetName (snapshot), quantity,
  unitPriceHT, line total helpers
- OrderController with full checkout flow:
  - POST /evenement/{id}/commander: create order from cart JSON
  - GET/POST /commande/{id}/informations: guest form (name, email)
  - GET /commande/{id}/paiement: payment page with recap
  - POST /commande/{id}/stripe: Stripe Checkout on connected account
    with application_fee, productId, and quantities
  - GET /commande/{id}/confirmation: success page
- Cart JS: POST cart data on Commander click, redirect to guest/payment
- Templates: guest form, payment page, order summary partial, success page
- Stripe payment uses organizer connected account, application_fee based
  on commissionRate, existing productId when available
- Tests: BilletBuyerTest (12), BilletBuyerItemTest (6), cart.test.js (13)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 13:54:17 +01:00
Serreau Jovann
5e099b8af6 Add shopping cart system on event detail billetterie
- Each billet has +/- quantity buttons with max quantity enforcement
- Line total per billet updated in real-time
- Cart total and article count at the bottom
- Commander button disabled when cart is empty
- Full billet description displayed
- JS module cart.js with 10 tests covering all cases

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 13:46:06 +01:00
Serreau Jovann
4785f406f3 Add categories and billets section on event detail page
- Show active, non-hidden categories with their buyable billets
- Display billet name, description, price, quantity, image
- Section placed above the map/emplacement section

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 13:43:15 +01:00
Serreau Jovann
b32cc77e31 Add title attribute to billet preview iframe
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 13:14:45 +01:00
Serreau Jovann
d1b4a6d286 Add title tag to billet preview page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 13:14:28 +01:00
Serreau Jovann
179a0703f8 Add Billet entity, BilletDesign, ticket designer, CRUD billets, commissions
- Create Billet entity: name, position, priceHT, quantity (nullable=unlimited),
  isGeneratedBillet, hasDefinedExit, notBuyable, type (billet/reservation_brocante/vote),
  stripeProductId, description, picture (VichUploader), category (ManyToOne CASCADE)
- Create BilletDesign entity (OneToOne Event): accentColor, invitationTitle, invitationColor
- Billet CRUD: add/edit/delete with access control, Stripe product sync on connected account
- Billet reorder: drag & drop with position field, refactored sortable.js for both categories and billets
- Ticket designer tab (custom offer only): accent color, invitation title/color, live iframe preview
- A4 ticket preview: 4 zones (HG infos+billet, HD affiche, BG association, BD sortie+invitation), fake QR code SVG
- Commission calculator JS: live breakdown of E-Ticket fee, Stripe fee (1.5%+0.25EUR), net amount
- Sales recap on categories tab: qty sold, total HT, total commissions, total net
- DisableProfilerSubscriber: disable web profiler toolbar on preview iframe
- CSP: allow self in frame-src and frame-ancestors for preview iframe
- Flysystem: dedicated billets.storage for billet images
- Upload accept restricted to png/jpeg/webp/gif (no HEIC)
- Makefile: add force_sql_dev command
- CLAUDE.md: add rule to never modify existing migrations
- Consolidate all migrations into single Version20260321111125
- Tests: BilletTest (20), BilletDesignTest (6), DisableProfilerSubscriberTest (5),
  billet-designer.test.js (7), commission-calculator.test.js (7),
  AccountControllerTest billet CRUD tests (11)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 12:19:46 +01:00
Serreau Jovann
9290411652 Add isHidden to Category, category CRUD tests, coverage improvements
- Add isHidden field to Category entity with migration (DEFAULT false for existing rows)
- Add isHidden checkbox to edit category template and "Masquee" badge on category list
- Save isHidden in editCategory controller method
- Fix Category.isActive() indentation
- Create CategoryTest with full coverage (14 tests): defaults, setters, setEvent logic, isActive, isHidden
- Add category CRUD tests to AccountControllerTest: add/edit/delete/reorder categories with access control
- Add cookie-consent tests for dev env early return and Cloudflare tunnel script
- Exclude PayoutPdfService from phpunit coverage and SonarQube analysis

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 23:35:42 +01:00
Serreau Jovann
0358025fe7 Add category edit page, edit button, and drag & drop sortable with native HTML5
- Add /mon-compte/evenement/{id}/categorie/{categoryId}/modifier route (GET/POST)
- Create edit_category.html.twig with name and date fields
- Add edit button (pencil icon) on category list items
- Add sortable.js module: native HTML5 drag & drop with fetch reorder API
- Auto-correct endAt < startAt on category edit

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 23:16:52 +01:00
Serreau Jovann
ca0527b0db Fix category dates: use event.endAt as default, auto-correct if endAt < startAt
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 23:13:53 +01:00
Serreau Jovann
ba55315977 Fix category dates: ensure endAt is after startAt, use event.startAt as default end
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 23:11:45 +01:00
Serreau Jovann
42ded8fbbe Add Category entity, edit event tabs (info/categories/stats/settings), CRUD categories
- Create Category entity: name, position (sortable), event, startAt, endAt, isActive()
- Default endAt: event.startAt - 1 day
- Add 4 tabs on edit event page: Informations, Categories/Billets, Statistiques, Parametres
- Add routes: add category, delete category, reorder categories (JSON API)
- Categories sorted by position, drag handle for future Sortable.js
- Active/Inactive badge based on date range
- Add migration for category table

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 22:51:25 +01:00
Serreau Jovann
847fc437de Disable analytics in dev env, redirect to edit page after event update
- Skip loading /stats/script.js and /assets/perf.js when data-env=dev
- Add data-env="{{ app.environment }}" to body tag
- Redirect to edit event page instead of events list after saving

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 22:39:38 +01:00
Serreau Jovann
13b6fd95be Extract social icons to shared partial _social_icons.html.twig to reduce duplication
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 21:29:58 +01:00
Serreau Jovann
1f5a9105fa Fix ESLint globals, parseFloat to Number.parseFloat, label for, add AccountController coverage tests
- Add setTimeout, globalThis, navigator, fetch, caches etc to ESLint globals
- Use Number.parseFloat in event-map.js
- Add for attribute to admin events search label
- Add tests: events search, toggle/delete access denied for other user

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 21:25:53 +01:00
Serreau Jovann
156042a640 Simplify pwa() call to defaults
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 20:57:25 +01:00
Serreau Jovann
e10b3bfa5c Remove service worker and workbox from PWA config
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 20:50:43 +01:00
Serreau Jovann
1b72fa8d2b Restore full PWA: service worker, workbox, icons, favicons
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 20:42:21 +01:00
Serreau Jovann
ec0c95f696 Strip PWA to favicon only: remove icons, SW, workbox, shortcuts, display_override
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 20:40:27 +01:00
Serreau Jovann
0172dcfd60 Fix Twig ?? precedence deprecation: add parentheses around concatenation in null coalescing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 20:27:11 +01:00
Serreau Jovann
d22a02f01e Add offline page, navigation preload, page cache, and pwa:create:sw commands
- Create /offline route and neo-brutalist offline page with retry button
- Add navigation_preload: true for faster SW navigation
- Add page_cache: 50 entries, 24h, 3s network timeout
- Add pwa_dev/pwa_prod Makefile commands using pwa:create:sw

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 19:22:28 +01:00
Serreau Jovann
7669fbca8c Add service worker with Workbox: cache manifest, image cache, font cache, skip_waiting
- sw.js with network-first strategy, versioned cache, auto-purge old caches
- Workbox: cache_manifest, image_cache (30 days, 200 entries), font_cache (30 days, 10 entries)
- skip_waiting + clients.claim for instant updates
- CSP nonce for SW registration script
- Remove sw.js and workbox from .gitignore

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 19:20:26 +01:00
Serreau Jovann
bbbf859e8f Increase navbar logo size: h-8 mobile, h-12 desktop
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 19:15:44 +01:00
Serreau Jovann
cae5d11bd8 Full mobile responsive for homepage, fix PHP CS Fixer import order
- Homepage: all text sizes responsive (320px→tablet→desktop)
- Background text text-[10rem] md:text-[30rem]
- Hero title text-4xl sm:text-5xl md:text-7xl lg:text-9xl
- Buttons smaller on mobile (px-6 py-4 md:px-10 md:py-6)
- Cards padding p-6 md:p-8, text sm on mobile
- Marquee text-base md:text-2xl
- CTA section responsive text and button sizes
- Fix AccountController: sort imports, use Event short class name

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 19:15:22 +01:00
Serreau Jovann
6fab96ab44 Full mobile responsive (320px) and tablet (768px) support across all templates
- All text-[20rem] background text → text-[8rem] md:text-[20rem]
- All text-8xl → text-5xl md:text-8xl
- All text-5xl emojis → text-3xl md:text-5xl
- edit_event: w-full md:w-[80%], poster column w-full lg:w-[350px]
- account/index: tab bar overflow-x-auto, events table overflow-x-auto
- admin/events: table overflow-x-auto
- register: tab buttons overflow-x-auto
- error 404/500: responsive padding p-6 md:p-12
- base footer: flex-col sm:flex-row for bottom bar
- Add PWA bundle (spomky-labs/pwa-bundle) with composer require files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 19:11:02 +01:00
Serreau Jovann
681c04bf85 Configure PWA: single pwa() call with favicon/theme injection, Imagick processor, remove duplicates
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:55:21 +01:00
Serreau Jovann
a794a10844 Add PWA bundle config and pwa() Twig function in base template
- Create pwa.yaml with manifest: name, icons (favicon.png), theme color
- Add {{ pwa() }} before stylesheets in base.html.twig head

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:54:11 +01:00
Serreau Jovann
689883b434 Add favicon, PWA commands (pwa_dev/pwa_prod), and prepare PWA deployment
- Add favicon.png link and apple-touch-icon in base.html.twig
- Add theme-color meta tag (#fabf04)
- Add pwa_dev and pwa_prod Makefile commands
- Add PWA asset generation step in Ansible playbook after cache clear
- Update Caddy static paths for favicon.png, marker.png, manifest.json, sw.js

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:53:36 +01:00
Serreau Jovann
b208c7529e Show full event poster without crop: object-contain instead of object-cover
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:44:07 +01:00
Serreau Jovann
4ce562df1f Adapt navbar for wide logo: remove border/shadow box, increase height, remove text label
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:42:37 +01:00
Serreau Jovann
91b52116c7 Replace OSM iframe with Leaflet map: marker, zoom, geocoding via Nominatim
- Add event-map.js module: loads Leaflet dynamically, geocodes address, renders map with marker at zoom 16
- Remove iframe, address text and OSM link below map
- Add CSP entries for unpkg (Leaflet), tile.openstreetmap.org (tiles), nominatim (geocoding)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:35:54 +01:00
Serreau Jovann
bc2b386837 Show full dates (d/m/Y H:i), add OpenStreetMap embed below event description
- Change date display from d/m/Y + H:i to "Du d/m/Y H:i au d/m/Y H:i"
- Add map card with OSM iframe (300px), address text, and link to OpenStreetMap
- Add openstreetmap.org to CSP frame-src

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:31:07 +01:00
Serreau Jovann
de99ca5f62 Event detail: poster 250px left, description right in two-column layout
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:29:30 +01:00
Serreau Jovann
1dcf5a190d Add organizer info section and event contact form on event detail page
- Left: organizer card with logo, name, city, social icons, email
- Right: contact form (name, firstname, email, message) sent to organizer
- Add /evenement/{id}/contact POST route with email to organizer (replyTo sender)
- Create event_contact.html.twig email template
- Add flash messages for success/error

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:17:17 +01:00
Serreau Jovann
e7693b4f42 Redesign event detail page: show title, address, date and organizer in hero
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 17:55:32 +01:00