Commit Graph

22 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
207e985821 Add Messenger monitor command, uploads backup, hourly cron
- MonitorMessengerCommand: checks failed messages, emails admin with details
- Backup script: add /public/uploads tar.gz alongside DB dump
- Ansible: cron every hour for messenger monitor
- TASK_CHECKUP: mark infrastructure tasks done

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 19:55:35 +01:00
Serreau Jovann
30eceeccf9 Add database backup cron every 30 minutes via Ansible
- backup.sh.j2: pg_dump via Docker, gzip, 7 days retention
- deploy.yml: create backup dir, deploy script, configure cron
- TASK_CHECKUP: mark backup as done

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 19:52:52 +01:00
Serreau Jovann
0dd89d1b54 Add pwa_dev and pwa_prod commands using pwa:compile
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:59:58 +01:00
Serreau Jovann
f652665a06 Remove asset-map:compile commands, PWA bundle works dynamically via Twig
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:59:24 +01:00
Serreau Jovann
759436d850 Fix PWA: remove pwa:create (not exists), use asset-map:compile, fix favicon path
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 18:56:38 +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
acc9e2a5b8 Add S/MIME private key to vault and deploy cert directory in Ansible playbook
- Store smime_private_key in encrypted vault
- Add playbook tasks: create cert directory + deploy private key with 0600 permissions
- Certificate public already in git at config/cert/certificate.pem

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 16:38:02 +01:00
Serreau Jovann
9420bbf357 Remove Supervisor config from Ansible playbook, messenger runs via Docker
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 14:30:41 +01:00
Serreau Jovann
764f596771 Fix pgbouncer config permissions: 0644 so container can read mounted files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 14:22:25 +01:00
Serreau Jovann
f8de531973 Fix DB wait: use shell loop instead of inline PHP to avoid Ansible escaping issues
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 14:21:15 +01:00
Serreau Jovann
e154df7ae1 Run composer/bun commands on host instead of Docker exec
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 14:18:29 +01:00
Serreau Jovann
3e9875a8a6 Run composer/bun commands via Docker exec instead of host in Ansible playbook
- composer install, bun install, bun run build now run inside php container
- Reorder: start containers first, then install dependencies via docker exec
- All php bin/console and dependency commands go through Docker

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 14:17:06 +01:00
Serreau Jovann
8dfaf0c9c8 Fix DB connectivity: remove host network, add wait for database before migration
- Remove unused host network from docker-compose-prod template
- Add 30s wait loop for pgbouncer connectivity before running migrations

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 14:12:04 +01:00
Serreau Jovann
de945add75 Fix PgBouncer auth: template pgbouncer.ini and userlist.txt with vault db_password
- Create pgbouncer.ini.j2 with auth_type plain (no MD5 hash needed)
- Create userlist.txt.j2 with vault db_password
- Add Ansible tasks to deploy both files before docker-compose
- Mount pgbouncer files as read-only in compose template

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 14:07:16 +01:00
Serreau Jovann
6b61df7597 Move docker-compose-prod.yml template generation before build step
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 13:31:07 +01:00
Serreau Jovann
d11c0cbea4 Convert docker-compose-prod.yml to Ansible template with vault secrets
- Create docker-compose-prod.yml.j2 with vault variables (db_password, redis_password, meilisearch_master_key)
- Add template deployment step in playbook after stop containers
- Remove docker-compose-prod.yml from git tracking (now generated by Ansible)
- Add docker-compose-prod.yml to .gitignore

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 13:26:38 +01:00
Serreau Jovann
2dc4326b66 Add build_prod step to Ansible playbook before pulling images
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 13:23:55 +01:00
Serreau Jovann
12eadc95a9 Simplify Ansible playbook: remove Cloudflare tasks, add git pull and direct dependency install
- Remove entire Cloudflare configuration play (DNS, SSL, HSTS, bot management)
- Replace make install_prod with direct git pull, composer install, bun install, bun run build
- Add Docker image pull step before container restart
- Keep server deployment: env, containers, migrations, cache, uploads, Caddy, Supervisor

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 13:05:07 +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
46a84a9f9a Merge deploy playbooks, add env.local template, update MailerService
- Fuse deploy-caddy.yml and cloudflare.yml into deploy.yml
- Add env.local.j2 template for production secrets
- Vault: add all production secrets
- Workflow: single deploy.yml playbook
- MailerService: rewrite with S/MIME signing, email tracking, unsubscribe
- ngrok-sync: run as root for .env.local write access
- Fix domain references to ticket.e-cosplay.fr

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