<!-- Generated: 2026-07-02 | Updated: 2026-07-02 -->

# vulcan-aff-v2

## Purpose
E-commerce and showcase website for **Vulcan' Affûtage**, an artisan knife-maker and precision sharpening business in Clermont-Ferrand (France, since 1981). The site presents the company, sells handmade knives online (cart, PayPal checkout, PDF invoices), manages customer accounts, and gives the owner an admin back office for products, orders, and visit statistics. Built on **Symfony 7.2 / PHP 8.2+** with Doctrine ORM.

## Key Files
| File | Description |
|------|-------------|
| `composer.json` | PHP dependencies and project metadata (Symfony 7.2, Doctrine, dompdf, PayPal via HTTP client) |
| `symfony.lock` | Symfony Flex recipe lock |
| `importmap.php` | AssetMapper importmap (Stimulus 3.2, Turbo 7.3) — note: real frontend JS lives in `public/scripts/`, not here |
| `.env` | Environment config — **contains committed SMTP credentials and app secrets (security issue, see below)** |
| `.env.dev` / `.env.test` | Per-environment overrides |
| `phpinfo.php` | Standalone `phpinfo()` dump — **publicly exposed, should be deleted (security issue)** |
| `phpunit.xml.dist` | PHPUnit configuration |
| `.php-cs-fixer.dist.php` | PHP-CS-Fixer coding-standard config |
| `sitemap.xml` / `robots.txt` | SEO files |
| `logo.svg` | Company logo |

## Subdirectories
| Directory | Purpose |
|-----------|---------|
| `src/` | Application PHP source: controllers, entities, services (see `src/AGENTS.md`) |
| `config/` | Symfony/bundle configuration (see `config/AGENTS.md`) |
| `templates/` | Twig templates for all pages and emails (see `templates/AGENTS.md`) |
| `migrations/` | Doctrine schema migrations (see `migrations/AGENTS.md`) |
| `assets/` | AssetMapper source (Stimulus stubs, app.css) — largely unused (see `assets/AGENTS.md`) |
| `public/` | Web root: `index.php`, real CSS/JS, images, fonts (see `public/AGENTS.md`) |
| `tests/` | PHPUnit bootstrap (see `tests/AGENTS.md`) |
| `translations/` | Empty translation catalog directory |
| `var/` | Runtime cache/logs (git-ignored) |
| `vendor/` | Composer dependencies (git-ignored) |

## For AI Agents

### Working In This Directory
- This is a **Symfony 7.2** app. Use `bin/console` for all framework tasks (cache clear, migrations, debug).
- Run `composer install` after touching `composer.json`.
- Clear cache with `php bin/console cache:clear` after config changes.

### Architecture Notes (important, non-obvious)
- **Authentication is custom session-based, NOT Symfony's security firewall.** `config/packages/security.yaml` declares a firewall with an in-memory user provider, but real admin/client auth is done manually in controllers by storing IDs in the session (`client_id`, `client_ob`, admin session keys) and checking them per-request. Do not assume `#[IsGranted]` or `getUser()` protects a route — most protection is hand-rolled and several routes are unguarded.
- **Frontend uses a custom CSS framework (`public/styles/kycss.css`) and vanilla JS (`public/scripts/`), loaded directly in templates.** Stimulus/Turbo/AssetMapper are installed but effectively unused. Prefer the existing plain-JS pattern when editing UI.
- PayPal integration lives in `src/Service/PayPalService.php` and `src/Controller/PaymentController.php` (order → capture flow).
- **Invoices (redesigned 2026-08-02)** live in `src/Service/Facture/` : `FactureBuilder` builds the
  single view model, `FacturePdfGenerator` renders it with dompdf (`templates/facture/pdf.html.twig`),
  and `templates/facture/index.html.twig` shows the same document on the site (Design 2.0).
  Preview without touching the DB : `php bin/console app:facture:exemple` or, in dev, `/facture/apercu-exemple`.
- **Points de dépôt (2026-08-02)** : `PointDepot` stores a partner drop-off shop with BAN-geocoded
  coordinates — admin CRUD at `/gestion/points-depot`, public proximity search at
  `/affutage/points-depot?lat=&lng=` (30 km radius, 20 results max, Haversine in `AffutageController`).
  A point without coordinates is rejected at save time: it would be invisible client-side.
  Address autocomplete everywhere uses `api-adresse.data.gouv.fr` (no API key).

### Known Issues / Security (surface before "improving")
- **`phpinfo()` is exposed** via `phpinfo.php` and several controller routes (e.g. `/phpInfo`) — publicly leaks PHP config.
- **SMTP credentials are committed in `.env`** — rotate and move to secrets, do not commit real creds.
- **`PayPalService` return_url is hardcoded to `localhost`** — breaks in production.
- **Session lifetime config comment says "2 minutes" but values are 2–3 days** (`config/packages/framework.yaml`).
- Several `/compte` and `/facture` routes lack auth guards or use inconsistent identity keys.

### Testing Requirements
- Test scaffolding exists but there are effectively no functional tests. Verify changes manually via `symfony server:start` or `php -S`.

## Dependencies

### External
- Symfony 7.2 (framework-bundle, form, mailer, security-bundle, twig, asset-mapper, ux-turbo, stimulus)
- Doctrine ORM 3 / DBAL 3 / migrations-bundle
- `dompdf/dompdf` — PDF invoice rendering
- `knplabs/knp-paginator-bundle` — pagination
- `amphp/http-client` + `symfony/http-client` — PayPal REST calls
- PHP 8.2+ (`ext-ctype`, `ext-iconv`)

<!-- MANUAL: Custom project notes can be added below -->
