88 Commits

Author SHA1 Message Date
Serreau Jovann
92548920c2 Migrate SonarQube to sn.e-cosplay.fr, rotate badge token, drop OWASP Dependency-Check, update deploy host
Some checks failed
CI / sonarqube (push) Failing after 5m27s
- .env, .env.test, ansible/env.local.j2: point SONARQUBE_URL to https://sn.e-cosplay.fr
- ansible/vault.yml, .env: rotate sonarqube_badge_token to new value
- .gitea/workflows/ci.yml, sonarqube.yml: remove OWASP Dependency-Check steps and force sonar.host.url via CLI args
- sonar-project.properties: drop dependencyCheck report paths
- .gitea/workflows/deploy.yml: switch SSH target from 34.90.187.4 to 152.228.222.133

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:44:37 +02:00
Serreau Jovann
eb884faea1 Align prod PHP container UID with bot user (1001) and harden restore.sh
Some checks failed
CI / sonarqube (push) Failing after 52s
Sur le serveur prod, l'utilisateur 'bot' (cree par Ansible) a UID 1001
alors que l'utilisateur 'appuser' du conteneur PHP etait hardcode a UID 1000,
ce qui causait des erreurs 'Unable to write in var/cache/prod' apres restore
ou deploiement: les fichiers du host appartenaient a bot:bot (1001) et
appuser (1000) ne pouvait pas y ecrire.

docker/php/prod/Dockerfile:
  - appuser UID/GID passe de 1000 a 1001 pour matcher bot
  - dev/Dockerfile reste a 1000 (les users dev sont generalement 1000)

ansible/deploy.yml:
  - chown des dossiers public/uploads/* et var/payouts passe de 1000 a 1001

restore.sh:
  - Nouvelle option --owner USER:GRP (defaut: bot:bot, override via RESTORE_OWNER)
  - Chown automatique en fin de restore sur var/, public/uploads/, config/cert/, .env.local
  - Purge automatique de var/cache (sera reconstruit par PHP)
  - Verification root au demarrage (sudo requis pour chown)
  - Verification de l'existence du user et group cibles
  - Option --skip-chown pour bypass (deconseille)
  - Etapes post-migration mises a jour (ajout de make build_prod en premier)

Procedure de migration sur le serveur apres ce commit:
  cd /var/www/e-ticket
  git pull origin master
  make build_prod              # rebuild image PHP avec UID 1001
  make stop_prod
  sudo chown -R bot:bot var public/uploads config/cert .env.local
  sudo rm -rf var/cache
  make start_prod
  make clear_prod

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:04:14 +02:00
Serreau Jovann
7e2706b04f Pin Meilisearch image to v1.40.0 to match database version and prevent incompatible auto-upgrades
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 14:06:16 +02:00
Serreau Jovann
a139feef07 init 2026-04-01 17:19:13 +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
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
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
98b0b41064 Use SECRET_ANALYTICS env var, regenerated at each deployment
- New SECRET_ANALYTICS variable replaces kernel.secret for analytics
- Ansible generates a random 32-char secret at each deploy
- Endpoint token and encryption key change with every deployment
- Existing sessions will get new visitor_id after deploy (expected)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 12:27:05 +01:00
Serreau Jovann
3bb676bfda Adjust container resource limits for 6 CPU / 30 GB RAM server
Resource allocation (limits / reservations):
- php x2:        1.5 CPU / 1G    |  0.5 CPU / 256M
- db-master:     2.0 CPU / 4G    |  0.5 CPU / 1G    (shared_buffers=1GB, effective_cache_size=3GB)
- db-slave:      1.5 CPU / 2G    |  0.25 CPU / 512M
- pgbouncer:     0.5 CPU / 128M  |  0.1 CPU / 32M
- messenger x2:  1.0 CPU / 512M  |  0.25 CPU / 128M
- redis:         1.0 CPU / 1G    |  0.25 CPU / 128M  (maxmemory 768mb)
- meilisearch:   1.0 CPU / 1G    |  0.25 CPU / 256M

Total max with replicas: ~12 CPU / ~13G RAM (overcommit OK, reservations fit)
Total reservations: ~3.6 CPU / ~4G RAM (guaranteed minimum)
Added PostgreSQL tuning: shared_buffers, effective_cache_size, work_mem.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:25:35 +01:00
Serreau Jovann
04c9df7638 Add CPU and memory limits to all production containers
Resource allocation (limits / reservations):
- php x2:        1.0 CPU / 512M  |  0.25 CPU / 128M
- db-master:     1.5 CPU / 2G    |  0.5 CPU / 512M
- db-slave:      1.0 CPU / 1G    |  0.25 CPU / 256M
- pgbouncer:     0.25 CPU / 64M  |  0.05 CPU / 16M
- messenger x2:  0.5 CPU / 384M  |  0.1 CPU / 64M
- redis:         0.5 CPU / 256M  |  0.1 CPU / 64M  (maxmemory 200mb)
- meilisearch:   0.5 CPU / 512M  |  0.1 CPU / 128M

Total max: ~8.5 CPU / ~6.5G RAM (with 2 php + 2 messenger replicas)
Redis maxmemory with allkeys-lru eviction policy added.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:24:27 +01:00
Serreau Jovann
d2fb17bf50 Add app:infra:snapshot command, page reads from var/infra.json
The /admin/infra page was slow because Docker stats API blocks per container.
Now a cron (every 5min) generates var/infra.json via app:infra:snapshot,
and the page reads the static JSON file instantly.
Mount Docker socket in cron container for snapshot access.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 11:19:26 +01:00
Serreau Jovann
7a370b1e02 Fix Docker socket access: add docker GID to PHP container group
The PHP container user needs the docker group to read the socket.
Uses DOCKER_GID env var in dev (defaults to 989) and dynamic GID
detection via Ansible stat in prod.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 10:53:28 +01:00
Serreau Jovann
8db44017d2 Redesign admin Infra page: full-screen 4-column layout with Docker stats
Complete rewrite of /admin/infra into 4 columns:
- Col 1 (Serveur): CPU, RAM, Disk, System, Services (Caddy, Docker, SSL cert)
- Col 2 (Containers): All Docker containers with CPU%, RAM, state via Docker API
- Col 3 (Redis): Global stats + per-DB (Messenger, Sessions, Cache)
- Col 4 (PostgreSQL): Instance stats + PgBouncer pools/stats

Extract all infra logic into InfraService. Mount Docker socket (read-only)
in PHP container for container stats. Check SSL cert expiry and Caddy status.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 10:51:04 +01:00
Serreau Jovann
d2be7311d9 Add admin/stats users to PgBouncer config for SHOW commands
Without admin_users/stats_users, connecting to the pgbouncer virtual
database fails with "database pgbouncer does not exist".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 10:35:43 +01:00
Serreau Jovann
e4edc76f58 Add Redis cache for Meilisearch search results and admin dashboard stats
- Configure Redis DB 2 as Symfony cache adapter
- Cache Meilisearch search results for 5 minutes (invalidated on writes)
- Cache admin dashboard stats for 10 minutes
- Add invalidateSearchCache() called after each Meilisearch write
- Update tests to support cache mock injection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 10:24:35 +01:00
Serreau Jovann
fd1162b7af Add Stripe sync cron (every 6h) to Ansible deploy playbook
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 09:58:14 +01:00
Serreau Jovann
aa2add2696 fix error navbar 2026-03-26 09:42:20 +01:00
Serreau Jovann
7e9f99a88e fix error navbar 2026-03-26 09:37:28 +01:00
Serreau Jovann
3a7f92c02d Remove Meilisearch healthcheck, use service_started instead
The getmeili/meilisearch image (Debian slim) has neither curl nor wget,
so healthcheck commands always fail. Use condition: service_started
and rely on Messenger retry mechanism for brief startup delays.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 09:32:22 +01:00
Serreau Jovann
264a82a97c Fix Meilisearch healthcheck: use wget instead of curl
The getmeili/meilisearch image does not include curl, causing the
healthcheck to fail and blocking messenger startup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 09:24:35 +01:00
Serreau Jovann
23b92f101c Add admin event actions (online/offline, edit, delete) and fix Meilisearch depends_on
- Add toggle online/offline and delete routes in AdminController
- Add action buttons (En ligne, Modifier, Supprimer) in admin events template
- Bypass requireEventOwnership and requireStripeReady for ROLE_ROOT so admin can edit any event
- Add Meilisearch healthcheck and depends_on in messenger service (prod + dev)
- Add tests for all new admin routes and ROLE_ROOT bypass

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 09:04:27 +01:00
Serreau Jovann
7d81fa3604 Update ansible vault
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 10:05:07 +01:00
Serreau Jovann
8223e0b954 Fix indentation in deploy.yml after LibreTranslate removal
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 09:49:30 +01:00
Serreau Jovann
6dfffac457 Remove LibreTranslate tasks from deploy, add SESSION_HANDLER_DSN to prod env
- Remove Start/Wait/Translate LibreTranslate tasks from deploy.yml
- Add SESSION_HANDLER_DSN with Redis in env.local.j2 for prod sessions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 09:46:47 +01:00
Serreau Jovann
2987dbfd28 Fix Redis session DSN, remove LibreTranslate from prod, track all translations
- Fix SESSION_HANDLER_DSN: use Redis db index (/1) instead of /sessions
  which caused "dbindex must be a number" error
- Remove LibreTranslate service and volume from docker-compose prod
- Remove gitignore rules for translation files (en, es, de, it)
  so all languages are tracked in git
- Apply PHP CS Fixer style fixes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 09:35:13 +01:00
Serreau Jovann
d44e75e3fd Fix SonarQube issues, store sessions in Redis, use direct analytics URLs
- ApiSandboxController: reduce scan() returns from 4 to 3 via ternary
- ApiDocController: add MIME_JSON constant, extract buildInsomniaRequest()
  and buildInsomniaBody() to reduce cognitive complexity
- Store sessions in Redis to fix SSO disconnect with 2 PHP replicas
  (round-robin load balancing caused session loss on filesystem storage)
- Configure session cookie: 24h lifetime, secure auto, samesite lax
- Replace Caddy analytics proxies (/stats/*, /assets/perf.js, /sperf)
  with direct URLs to tools-security.esy-web.dev and cloudflareinsights.com
- Update JS tests for new direct analytics URLs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 09:21:19 +01:00
Serreau Jovann
d4e30abffb fix error navbar 2026-03-23 18:37:24 +01:00
Serreau Jovann
f508ce2751 Fix backup script: use db-master container name and default db credentials
- Container name: database → db-master (matches docker-compose-prod.yml)
- Variables: vault_postgres_user/db → db_user/db_name with defaults 'e-ticket'
- No vault variable required, falls back to docker-compose-prod defaults

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 18:34:48 +01:00
Serreau Jovann
82c90f5b8b Fix LibreTranslate deploy: healthcheck from PHP container, ignore_errors, add QR code tests
- Ansible: healthcheck via PHP container (curl from php, not libretranslate)
- Ansible: exit 0 if LibreTranslate not ready (don't block deploy)
- Ansible: ignore_errors on translation step (non-blocking)
- AccountControllerTest: add testEventQrCode (PNG response) and testEventQrCodeDeniedForOtherUser (403)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 18:12:18 +01:00
Serreau Jovann
acccd4a0c4 Fix LibreTranslate timeout: increase wait to 3min, add Ansible healthcheck wait
- TranslateCommand: increase waitForApi retries from 30 to 90 (3 minutes total)
- Ansible deploy: add explicit healthcheck wait step (60×5s = 5min max) before translation
- First launch downloads ~2-4GB of language models, needs more time

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 18:10:54 +01:00
Serreau Jovann
da0076fa51 aa 2026-03-23 16:58:27 +01:00
Serreau Jovann
42d06dd49f Add LibreTranslate auto-translation, improve test coverage, fix code duplication
Translation system:
- Add LibreTranslate container (dev + prod), CPU-only, no port exposed, FR/EN/ES/DE/IT
- Create app:translate command: reads *.fr.yaml, translates incrementally, preserves placeholders
- Makefile: make trans / make trans_prod (stops container after translation)
- Ansible: start libretranslate -> translate -> stop during deploy
- Prod container restart: "no" (only runs during deploy)
- .gitignore: ignore generated *.en/es/de/it.yaml files
- 11 tests for TranslateCommand (API unreachable, empty, incremental, obsolete keys, placeholders, fallback)

Test coverage improvements:
- OrderController: event ended (400), invalid cart JSON, invalid email, stock zero (4 new tests)
- AccountController: finance stats all statuses (paid/pending/refunded/cancelled), soldCounts (2 new tests)
- JS cart: checkout without error elements, hide error on retry, stock polling edge cases (singular, no label, qty zero, unknown billet) (8 new tests)
- JS editor: comment node sanitization (1 new test)
- JS tabs: missing panel, generated id, parent null, click no-panel (5 new tests)

Code duplication fixes:
- MeilisearchConsistencyCommand: extract diffAndReport() method (was duplicated 3x)
- Email templates: extract _order_items_table.html.twig partial (shared by notification + cancelled)
- SonarQube: exclude src/Entity/** from CPD (getters/setters duplication)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:44:13 +01:00
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
add8d8f5af Change backup retention to 1 day
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 19:53:25 +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
615e1c2eab Encrypt vault with updated Stripe webhook secrets
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 22:33:24 +01:00
Serreau Jovann
3e8eed4edb Split Stripe webhooks: /stripe/webhook for payouts, /stripe/webhook/connect for v2 Connect
- Separate webhook routes with different secrets
- Add verifyConnectWebhookSignature() to StripeService
- Add STRIPE_WEBHOOK_SECRET_CONNECT env var
- Update vault with prod secrets for both endpoints

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 22:31:00 +01:00
Serreau Jovann
0860c1b08c Fix /sperf tunnel: keep rewrite to /cdn-cgi/rum (original Cloudflare endpoint)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 21:40:42 +01:00
Serreau Jovann
13321edd8e Rename /rum to /sperf tunnel, exclude editor.js and event-map.js from coverage
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 21:39:39 +01:00
Serreau Jovann
361548d65c Add /rum tunnel to bypass adblock for Cloudflare RUM endpoint
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 21:38:17 +01:00
Serreau Jovann
bbe727b1d4 Add unavailable page when PHP-FPM is down: Caddy handle_errors on 502/503
- Create unavailable.html static page with neo-brutalist design and retry button
- Add handle_errors in Caddy for 502/503: serve unavailable.html
- Add dial/read/write timeouts to php_fastcgi (5s/30s/30s)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 20:14:41 +01:00
Serreau Jovann
7c0149b785 Update sw.js from pwa:create:sw, add PWA static paths to Caddy prod
- sw.js regenerated by Workbox with full cache strategies
- Add screen.png, site.webmanifest, workbox/*, idb/*, pwa/* to Caddy static paths

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 19:52:20 +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