Commit Graph

45 Commits

Author SHA1 Message Date
Serreau Jovann
04927ec988 Complete TASK_CHECKUP: security, UX, tests, coverage, accessibility, config externalization
Billetterie:
- Partial refund support (STATUS_PARTIALLY_REFUNDED, refundedAmount field, migration)
- Race condition fix: PESSIMISTIC_WRITE lock on stock decrement in transaction
- Idempotency key on PaymentIntent::create, reuse existing PI if stripeSessionId set
- Disable checkout when event ended (server 400 + template hide)
- Webhook deduplication via cache (24h TTL on stripe event.id)
- Email validation (filter_var) in OrderController guest flow
- JSON cart validation (structure check before processing)
- Invitation expiration after 7 days (isExpired method + landing page message)
- Stripe Checkout fallback when JS fails to load (noscript + redirect)

Config externalization:
- Move Stripe fees (STRIPE_FEE_RATE, STRIPE_FEE_FIXED) and admin email (ADMIN_EMAIL) to .env/services.yaml
- Replace all hardcoded contact@e-cosplay.fr across 13 files
- MailerService: getAdminEmail()/getAdminFrom(), default $from=null resolves to admin

UX & Accessibility:
- ARIA tabs: role=tablist/tab/tabpanel, aria-selected, keyboard nav (arrows, Home, End)
- aria-label on cart +/- buttons and editor toolbar buttons
- tabindex=0 on editor toolbar buttons for keyboard access
- data-confirm handler in app.js (was only in admin.js)
- Cart error feedback on checkout failure
- Billet designer save feedback (loading/success/error states)
- Stock polling every 30s with rupture/low stock badges
- Back to event link on payment page

Security:
- HTML sanitizer: BLOCKED_TAGS list (script, style, iframe, svg, etc.) - content fully removed
- Stripe polling timeout (15s max) with fallback redirect
- Rate limiting on public order access (20/5min)
- .catch() on all fetch() calls (sortable, billet-designer)

Tests (92% PHP, 100% JS lines):
- PCOV added to dev Dockerfile
- Test DB setup: .env.test with DATABASE_URL, Redis auth, Meilisearch key
- Rate limiter disabled in test env
- Makefile: test_db_setup, test_db_reset, run_test_php, run_test_coverage_php/js
- New tests: InvitationFlowTest (21), AuditServiceTest (4), ExportServiceTest (9), InvoiceServiceTest (4)
- New tests: SuspendedUserSubscriberTest, RateLimiterSubscriberTest, MeilisearchServiceTest
- New tests: Stripe webhook payment_failed (6) + charge.refunded (6)
- New tests: BilletBuyer refund, User suspended, OrganizerInvitation expiration
- JS tests: stock polling (6), data-confirm (2), copy-url restore (1), editor ARIA (2), XSS (9), tabs keyboard (9)
- ESLint + PHP CS Fixer: 0 errors
- SonarQube exclusions aligned with vitest coverage config

Infra:
- Meilisearch consistency command (app:meilisearch:check-consistency --fix) + cron daily 3am
- MeilisearchService: getAllDocumentIds(), listIndexes()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:14:06 +01:00
Serreau Jovann
61200adc74 Add stock management, order notifications, webhooks, expiration cron, and billet type validation
- Decrement billet quantity after purchase in BilletOrderService::generateOrderTickets
- Block purchase when stock is exhausted (quantity <= 0) in OrderController::buildOrderItems
- Add organizer email notification on new order (order_notification_orga template)
- Add organizer email notification on cancel/refund (order_cancelled_orga template)
- Add ExpirePendingOrdersCommand (app:orders:expire-pending) cron every 5min via Ansible
  - Cancels pending orders older than 30 minutes, restores stock, invalidates tickets
  - Includes BilletBuyerRepository::findExpiredPending query method
  - 3 unit tests covering: no expired orders, stock restoration, unlimited billets
- Add payment_intent.payment_failed webhook: cancels order, logs audit, emails buyer
- Add charge.refunded webhook: sets order to refunded, invalidates tickets, notifies orga and buyer
- Validate billet type (billet/reservation_brocante/vote) against organizer offer
  - getAllowedBilletTypes: gratuit=billet only, basic/sur-mesure=all types
  - Server-side validation in hydrateBilletFromRequest, UI filtering in templates
- Update TASK_CHECKUP.md: all Billetterie & Commandes items now complete

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 00:12:30 +01:00
Serreau Jovann
80b48b9dbf Add financial dashboard for organizer in payouts tab
- 6 KPIs: encaissé, en attente, remboursé, com E-Ticket, com Stripe, net perçu
- Calculated from all orders linked to organizer's events
- Displayed above export buttons and payouts table

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 22:23:59 +01:00
Serreau Jovann
608b746989 Add monthly export CSV + PDF for admin and organizers
- ExportService: monthly stats query, CSV generation, PDF generation via dompdf
- Admin: /admin/export/{year}/{month} (CSV) + /admin/export/{year}/{month}/pdf
- Orga: /mon-compte/export/{year}/{month} (CSV) + /mon-compte/export/{year}/{month}/pdf
- Admin CSV: commande, date, événement, orga, acheteur, billets, total HT, com E-Ticket, com Stripe
- Orga CSV: + net perçu column
- PDF A4 landscape: KPIs + orders table with commissions breakdown
- Buttons in admin dashboard and orga payouts tab (current + previous month)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 22:16:55 +01:00
Serreau Jovann
66ac2379ec Add audit trail: AuditLog entity, AuditService, admin logs page
- AuditLog entity: action, entityType, entityId, data (JSON), performedBy, ipAddress
- AuditService: logs actions with current user and IP
- Audit on: order_created, order_paid, order_cancelled, order_refunded
- Admin /admin/logs: paginated table with action badges, details, user, IP
- Navigation link 'Logs' in admin header

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 20:48:10 +01:00
Serreau Jovann
0e79c65966 Optimize N+1 queries: batch billets, soldCounts, paid orders with items
- AccountController: single query for all billets by categories, single
  GROUP BY query for sold counts, eager-load items on paid orders
- HomeController: single query for all buyable billets of active categories

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 20:13:31 +01:00
Serreau Jovann
233f3d5067 Reduce cognitive complexity: extract computeEventStats from editEvent
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 22:36:57 +01:00
Serreau Jovann
06dcc95a32 Add per-billet sales stats in stats tab
- Calculate sold count and revenue per billet from paid orders
- Display 'Ventes par billet' card between KPIs and orders list

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 20:06:31 +01:00
Serreau Jovann
be630e1c67 Add isInvitation field on BilletBuyer to distinguish invitations from free billets
- isInvitation (nullable bool) on BilletBuyer instead of checking totalHT == 0
- Set isInvitation=true when creating invitation in controller
- Email subject/content based on order.isInvitation
- Invoice shows organizer as buyer when order.isInvitation
- Invitations list filtered by isInvitation=true

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 19:14:45 +01:00
Serreau Jovann
b472399878 Add view order button in stats, resend invitation button
- Stats tab: "Voir" button on each order linking to public order page
- Invitations tab: "Renvoyer" button to resend invitation email
- New route app_account_event_resend_invitation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 19:11:15 +01:00
Serreau Jovann
66ddc297b1 Fix invitation list (use dedicated variable), invitation email subject and content
- Pass invitations from controller instead of Twig filter on paginator
- Email subject: "Votre invitation" for invitations, "Vos billets" for purchases
- Email content: different intro text for invitations

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 19:09:49 +01:00
Serreau Jovann
177f3457b3 Add missing BilletBuyerItem import in AccountController
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 17:48:51 +01:00
Serreau Jovann
7167cb5fe0 Allow multiple billets in invitation form, dynamic add/remove lines
- Form sends items[] array with billet_id and quantity per line
- JS button to add more billet lines with remove button
- Controller iterates over items to create multiple BilletBuyerItems
- Same flow: all tickets generated with isInvitation=true

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 17:30:18 +01:00
Serreau Jovann
58d325f60c Add invitations tab: create free invitation with ticket generation and email
- New tab "Invitations" on event edit page
- Form: name, email, billet type, quantity
- Creates BilletBuyer with totalHT=0 (no payment), generates BilletOrders
  with isInvitation=true, sends email with PDF tickets
- List of sent invitations below the form

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 17:27:18 +01:00
Serreau Jovann
03d14a643b Add stats tab with orders list, search, cancel and refund actions
- OrderIndexService: Meilisearch index order_event_{id} for order search
- Stats tab: 4 KPI cards (orders, tickets sold, CA HT, total percu)
- Orders list with KnpPaginator, search bar via Meilisearch
- Each order shows: number, status, date, buyer, items, total, payment
- Cancel order: sets status cancelled, invalidates all tickets
- Refund order: Stripe refund on connected account, sets status refunded,
  invalidates all tickets
- Orders indexed in Meilisearch after payment

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 17:19:58 +01:00
Serreau Jovann
8d772328f7 Show real stats on homepage and real sold counts in event categories
- Homepage: count BilletOrders for tickets sold, sum paid orders for totalHT
- Event categories: count BilletOrders per billet for real sold counts
- Remove placeholder text from tickets stat block

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 17:15:34 +01:00
Serreau Jovann
85c2b1baa5 Show purchased tickets in /mon-compte billets tab
- Load user's BilletOrders via BilletBuyer orders
- Display each ticket with: name, status badge (Actif/Expire/Annule),
  first scan date, event info (name, date, address), reference,
  order number, price, download PDF and view order buttons

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 17:01:13 +01:00
Serreau Jovann
36b66d27dc Improve coverage: billet with picture tests, codeCoverageIgnore on Stripe methods
- Add testAddBilletWithPicture and testEditBilletWithPicture for line 904
- Add billet to categoriesTab test for line 363
- Extract deleteBilletFromStripe with @codeCoverageIgnore
- Add @codeCoverageIgnore to syncBilletToStripe

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 13:30:38 +01:00
Serreau Jovann
1e63b8337f Reduce cognitive complexity: extract syncBilletToStripe, remove temp variable, fill empty catch blocks
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 13:13:35 +01:00
Serreau Jovann
c8ddbbcf59 Extract EVENT_CATEGORIES_SUFFIX constant, add comments in empty catch blocks
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 13:11:54 +01:00
Serreau Jovann
bcb12bca5c Deduplicate AccountController: extract hydrateBilletFromRequest, EVENT_BASE_URL constant, move formatEur to outer scope
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 13:10:40 +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
f2bce4f191 Sortable tests, deduplicate event hydration, disable php:S1448
- Add sortable.js tests (12 tests): drag/drop, reorder, early returns, edge cases
- Use target.before()/after() instead of list.insertBefore() in sortable.js
- Extract hydrateEventFromRequest() to eliminate duplicated code in createEvent/editEvent
- Disable SonarQube rule php:S1448 (too many methods per class)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 10:12:17 +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
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
1f6cb5db1e Keep event online/secret status when editing, don't reset to false
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 22:35:42 +01:00
Serreau Jovann
2ed17defe0 Extract searchEvents() to EventIndexService, reduce duplication across controllers
- Add searchEvents() method: Meilisearch search with DB fallback
- Use in HomeController, AdminController, AccountController (removes ~45 duplicated lines)
- Add assets/vendor/ to ESLint ignores
- Update EventIndexServiceTest for new constructor

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 21:33:37 +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
e18f79b2e5 Require Stripe validation to put event online, disable button and block route
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 17:47:31 +01:00
Serreau Jovann
61362096d8 Redesign edit event page: two-column layout, action buttons, poster display
- Left column: edit form (title, description, dates, address, image upload)
- Right column: sticky poster preview card with image or placeholder
- Top action bar: toggle online/offline, toggle secret/public, status badges
- Add routes: /mon-compte/evenement/{id}/en-ligne and /mon-compte/evenement/{id}/secret
- Remove is_online checkbox from form (replaced by dedicated toggle buttons)
- Meilisearch re-indexed on toggle actions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 17:42:08 +01:00
Serreau Jovann
abd2fef638 Add search bar for events in /mon-compte using Meilisearch per-account index
- Search form with query parameter ?q= on events tab
- Uses event_{accountId} Meilisearch index for search
- Falls back to database query if Meilisearch unavailable

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 17:23:01 +01:00
Serreau Jovann
e6213ca66f Add Meilisearch event indexing with 3 indexes: global, admin, per-account
- Create EventIndexService with indexEvent() and removeEvent()
- event_global: online events where isSecret=false (public search)
- event_admin: all events regardless of status (admin search)
- event_{accountId}: all events per organizer (account search)
- Integrate indexing in create/edit/delete event controllers
- Try/catch for Meilisearch unavailability (graceful degradation)
- Add 5 unit tests for EventIndexService

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 17:18:45 +01:00
Serreau Jovann
146a0d4da0 Add event list with pagination, edit and delete actions in account page
- Display events table sorted by startAt ASC with status (en ligne/hors ligne)
- Add KnpPaginator for events (10 per page)
- Add edit event page (/mon-compte/evenement/{id}/modifier) with all fields + isOnline toggle
- Add delete event route (/mon-compte/evenement/{id}/supprimer) with confirmation
- Add Modifier/Supprimer buttons in events table
- Move Stripe warning outside the card
- Fix test to use fresh EntityManager for event assertion

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 17:02:56 +01:00
Serreau Jovann
8b3b1dab13 Add Event entity, create event page, and custom WYSIWYG editor component
- Create Event entity with fields: account, title, description (text), startAt, endAt, address, zipcode, city, eventMainPicture (VichUploader), isOnline, createdAt, updatedAt
- Create EventRepository
- Add migration for event table with all columns
- Add "Creer un evenement" button on account events tab
- Add create event page (/mon-compte/evenement/creer) with full form
- Build custom web component <e-ticket-editor> WYSIWYG editor:
  - Toolbar: bold, italic, underline, paragraph, bullet list, remove formatting
  - contentEditable div with HTML sync to hidden textarea
  - HTML sanitizer (strips disallowed tags, XSS safe)
  - Neo-brutalist CSS styling
  - CSP compliant (no inline styles)
- Register editor in app.js via customElements.define
- Add editor CSS in app.scss
- Add 16 Event entity tests (all fields + isOnline + picture upload + updatedAt)
- Add 16 editor JS tests (sanitizer + custom element lifecycle)
- Add 3 AccountController tests (create event page, submit, access control)
- Update placeholders to generic examples (no association-specific data)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 12:49:24 +01:00
Serreau Jovann
563393c1df Fix PHP CS Fixer: add blank line after class constants
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 11:02:16 +01:00
Serreau Jovann
c2169eb5e8 Add coverage tests, extract breadcrumb constants, add thead to detail table, ignore css:S4662
- Add test for sitemap orgas with logo image coverage
- Add test for organizer settings with logo file upload
- Extract BREADCRUMB_HOME/BREADCRUMB_ACCOUNT constants in AccountController
- Extract BREADCRUMB_HOME/BREADCRUMB_ORGANIZERS constants in HomeController
- Extract BREADCRUMB_HOME/BREADCRUMB_REGISTER constants in RegistrationController
- Add thead with th headers to organizer detail info table
- Ignore SonarQube css:S4662 rule for assets (Tailwind @source directive)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 11:00:08 +01:00
Serreau Jovann
2ce71025f1 Fix PHP CS Fixer: remove spaces around string concatenation operator
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 10:47:56 +01:00
Serreau Jovann
198d684fb8 Add organizer pages, SEO breadcrumbs, Open Graph, homepage redesign, and infrastructure updates
- Add public organizers list page (/organisateurs) with neo-brutalist card grid, social icons, and logo display
- Add organizer detail page (/organisateur/{id}-{slug}) with company info, SIRET, email, address, social links, and events placeholder
- Add slug-based URLs with 301 redirect on wrong slug, getSlug() method on User entity
- Add "Voir les evenements" button on organizer cards linking to detail page
- Add JSON-LD BreadcrumbList to all 17 pages that were missing breadcrumbs (login, forgot_password, register_success, email_verified, legal/*, attestation/*, account/*)
- Add Open Graph meta tags (og:title, og:description, og:image, og:type, og:locale, og:site_name) in base.html.twig with automatic inheritance from title/description blocks
- Add og:image with organizer logo on detail page
- Update sitemap: add /organisateurs to sitemap-main, generate organizer detail URLs in sitemap-orgas with logo images
- Update navbar to highlight "Organisateurs" on detail pages
- Redesign homepage with hero section, marquee, stats counters, how-it-works, and CTA sections
- Add Tailwind v4 @source "../templates" directive to app.scss and admin.scss
- Migrate Flysystem from S3 to local storage (uploads/events, uploads/logos)
- Update Liip Imagine config with FormatExtensionResolver for webp conversion
- Add User entity social fields (website, facebook, instagram, twitter, tiktok), logo upload (Vich), __serialize/__unserialize for session safety
- Add account page settings tab with profile, logo upload, and social media for organizers
- Add Stripe Connect status display and sub-account management in account page
- Delete WebpExtensionSubscriber (replaced by FormatExtensionResolver)
- Add migration for social fields and logo columns
- Add deploy.yml chmod tasks for uploads directories
- Add HomeController tests (detail success, wrong slug redirect, 404 cases)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 10:44:31 +01:00
Serreau Jovann
641c37699b Add coverage annotations, sub-account tests, and PDF improvements
- Add @codeCoverageIgnore to Stripe API methods in AccountController
- Add @codeCoverageIgnore to PayoutPdfService generate/generateToFile
- Add title tag and role=presentation to PDF attestation tables
- Fix DejaVu Sans font in PDF template
- Add 4 sub-account tests: create with email, edit page, edit submit, delete
- Fix duplicate PHPDoc in AccountControllerTest

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 00:05:17 +01:00
Serreau Jovann
ab52a8d02f Add payouts, PDF attestations, sub-accounts, and webhook improvements
Payout system:
- Create Payout entity (stripePayoutId, status, amount, currency, destination, arrivalDate)
- Webhook handles payout.created/updated/paid/failed/canceled with email notification
- Payout list in /mon-compte virements tab with status badges
- PDF attestation on paid payouts with email attachment

PDF attestation:
- dompdf with DejaVu Sans font, yellow-orange gradient background
- Orange centered title bar, E-Cosplay logo, emitter/beneficiary info blocks
- QR code linking to /attestation/check/{payoutId} for authenticity verification
- Public verification page: shows payout details if valid, error if altered
- Legal disclaimer and CGV reference
- Button visible only when status is paid, opens in new tab

Sub-accounts:
- Add parentOrganizer (self-referencing ManyToOne) and subAccountPermissions (JSON) to User
- Permissions: scanner (validate tickets), events (CRUD), tickets (free invitations)
- Create sub-account with random password, send email with credentials
- Edit page with name/email/permissions checkboxes
- Delete with confirmation
- hasPermission() helper method

Account improvements:
- Block entire page for unapproved organizers with validation pending message
- Display stripeStatus in Stripe Connect banners
- Remove test payout button

Webhook v2 Connect events:
- v2.core.account.created/updated/closed → update stripeStatus
- capability_status_updated → sync charges/payouts enabled from capabilities
- PayoutPdfService for reusable PDF generation

Migrations: stripeStatus, Payout table, sub-account fields, drop pdfPath

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 23:49:48 +01:00
Serreau Jovann
93e5ae67c0 Refactor Stripe integration: single Connect webhook, account pages, cleanup
Stripe webhook:
- Single webhook endpoint /stripe/webhook for Connect + payment events
- v2 Connect events configured manually in Stripe Dashboard (not via API)
- account.updated syncs charges_enabled/payouts_enabled via API retrieve
- Remove StripeSyncCommand and saveWebhookSecret (secret managed via Ansible vault)

Account page (/mon-compte):
- Buyer tabs: Billets, Achats, Factures, Parametres
- Organizer tabs: Evenements/Brocantes, Sous-comptes, Virements + buyer tabs
- Stripe Connect status banner: setup required, pending verification, active, refused
- Stripe Connect onboarding: create account, complete verification (GET links)
- Dashboard Stripe: opens in new tab via createLoginLink (Express dashboard)
- Cancel/close Stripe account: deletes via API + resets local fields
- Stripe required message on events/subaccounts/payouts tabs when not active
- Settings: organizer fields locked (name, address), email/phone editable
- Return/refresh routes for Stripe Connect onboarding flow
- Error handling with flash messages on all Stripe operations
- Auto-sync Stripe status on /mon-compte visit

StripeService cleanup:
- Remove syncWebhook, saveWebhookSecret, getWebhookUrl, projectDir
- Add deleteAccount method
- Keep: verifyWebhookSignature, createAccountConnect, createAccountLink, createLoginLink

Security:
- Add connect.stripe.com and dashboard.stripe.com to nelmio whitelist
- Add STRIPE_SK, STRIPE_WEBHOOK_SECRET, OUTSIDE_URL to .env.test

Tests: 19 AccountControllerTest, 4 StripeWebhookControllerTest, 1 StripeServiceTest

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 22:41:31 +01:00
Serreau Jovann
8193930f60 Add application source code, configs and assets
- Controllers, Entity, Repository, Services, Twig extensions
- Templates (account, emails, home, legal, security, unsubscribe)
- Symfony config updates (bundles, security, framework, services)
- Vite + Bun setup with PostCSS
- Caddy config, CLAUDE.md, README
- Update .gitignore (node_modules, .idea, cert)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 20:16:01 +01:00