# AutoLuxe Atelier · CRM pentru detailing, protecție și colantare auto

Versiunea 1.0.0 · PHP 8.1+ · SQLite · HTML/CSS/JavaScript fără dependențe externe.

Aplicația pornește din prototipul „AutoLuxe Atelier” aprobat: același design și aceleași ecrane. Toate datele stau acum pe server. Există conturi și roluri. Toate regulile importante (suprapuneri, etape, predare, garanții, stoc) se verifică pe server. Lista completă a diferențelor față de prototip e în `MODIFICARI.md`.

---

## 1. Structura

```
autoluxe-crm/
├── app/                  codul PHP — NU se pune în dosarul public
│   ├── config.sample.php    model de configurare → se copiază ca config.php
│   ├── bootstrap.php, api.php, schema.sql
│   ├── lib/                 bază de date, securitate, calendar, reguli de business
│   └── routes/              API-ul, pe module
├── data/                 baza SQLite, fotografii, semnături, jurnale, sesiuni — NU se pune în dosarul public
├── public/               SINGURUL dosar servit de web (public_html / document root)
│   ├── index.php            aplicația
│   ├── api.php              API-ul (JSON)
│   ├── intake.php           primirea cererilor din configuratorul de pe site
│   ├── install.php          instalarea la prima pornire (se blochează singur după)
│   ├── paths.php            unde e dosarul app/ (de modificat doar dacă schimbați structura)
│   └── assets/              CSS, JS, fonturi (locale, licență SIL OFL), logo
├── tools/
│   ├── backup.py            copie de siguranță zilnică (cron)
│   └── test_api.py          test de integrare: 94 de verificări, DOAR pe o instalare de test
└── deploy/nginx.conf.example
```

## 2. Cerințe

- PHP 8.1 sau mai nou, cu extensiile: `pdo_sqlite`, `gd`, `fileinfo`, `mbstring` (opțional `exif`, pentru rotirea automată a fotografiilor)
- Apache cu `mod_rewrite` și `mod_headers`, sau nginx + PHP-FPM
- HTTPS obligatoriu (certificat Let's Encrypt sau al găzduirii)
- Python 3.8+ pe server, doar pentru copia de siguranță automată (`tools/backup.py`)
- Spațiu: aproximativ 300–600 KB pe mașină, cu 8 fotografii

## 3. Instalare

### 3.1 Varianta recomandată (cod în afara dosarului public)

1. Încărcați `app/`, `data/` și `tools/` **lângă** `public_html`, nu în el:
   ```
   /home/cont/autoluxe/app
   /home/cont/autoluxe/data
   /home/cont/autoluxe/tools
   /home/cont/public_html/   ← conținutul dosarului public/
   ```
2. Dacă `public_html` nu e la același nivel cu `app/`, modificați `public_html/paths.php`:
   `define('ALX_APP', '/home/cont/autoluxe/app');`
3. Copiați `app/config.sample.php` ca `app/config.php` și completați:
   - `base_url`: adresa exactă, de exemplu `https://crm.autoluxe.ro`
   - `data_dir`: calea absolută la `data/`, de exemplu `/home/cont/autoluxe/data`
   - `install_key`: un șir aleator, generat cu `php -r "echo bin2hex(random_bytes(24)), PHP_EOL;"`
4. Dați drept de scriere pe `data/` utilizatorului PHP (pe cPanel e de obicei chiar contul dvs.): `chmod -R 750 data`.
5. Deschideți `https://crm.autoluxe.ro/install.php`. Pagina verifică extensiile, drepturile, poziția dosarului de date și HTTPS. Introduceți cheia de instalare, datele atelierului și contul de administrator.
   Bifele „catalog” și „echipă” încarcă serviciile, prețurile, consumabilele și echipa din prototip. Toate se pot modifica după aceea.
6. După instalare, `install.php` răspunde 404. Ștergeți-l de pe server și goliți `install_key` din config.

### 3.2 Varianta cu totul în `public_html` (găzduire fără acces deasupra)

Puneți `app/` și `data/` în `public_html` și schimbați în `paths.php`: `define('ALX_APP', __DIR__ . '/app');`.
Fișierele `.htaccess` din `app/`, `data/` și `data/uploads/` blochează accesul din web. **Verificați după instalare** că:
`https://crm.autoluxe.ro/data/autoluxe.sqlite` și `https://crm.autoluxe.ro/app/config.php` răspund 403. Dacă nu, serverul ignoră `.htaccess` (`AllowOverride None`) și trebuie folosită varianta 3.1.

### 3.3 nginx

Vezi `deploy/nginx.conf.example`. Pe nginx `.htaccess` nu are efect; regulile echivalente sunt în fișierul de exemplu.

## 4. Primii pași după instalare

1. **Setări → Atelier**: adresa confirmată (pe site apar două), telefonul, programul, numărul de boxe, linkul de recenzii Google.
2. **Setări → Atelier → „Ore de lucru pe zi de boxă”**: configuratorul de pe site calculează durata ca ore ÷ 24. Confirmați cu atelierul dacă orele din catalog sunt ore de manoperă (atunci puneți 10–12) sau durată totală.
3. **Setări → Servicii și prețuri**: verificați prețurile. Doar pachetele LUXE sunt cele publicate; restul vin din prototip și sunt orientative. Tot aici se editează consumul din stoc pentru fiecare serviciu.
4. **Consumabile → Editează → Inventar**: introduceți stocul real numărat. Stocul pornește de la 0, de aceea la început toate produsele apar „sub minim”.
5. **Setări → Utilizatori**: creați conturile. Parola dată de dvs. e temporară; utilizatorul e obligat s-o schimbe la prima intrare.
6. Configurați copia de siguranță automată (secțiunea 7).

## 5. Roluri

| | Administrator | Recepție | Tehnician |
|---|:-:|:-:|:-:|
| Panou, calendar, lucrări, echipă | ✓ | ✓ | ✓ (fără sume) |
| Recepție, raport de stare, fotografii, procese-verbale | ✓ | ✓ | ✓ |
| Avansarea etapelor de lucru | ✓ | ✓ | ✓ (fără predare) |
| Cereri, programare, mutare, alocare tehnicieni | ✓ | ✓ | — |
| Predare și încasare | ✓ | ✓ | — |
| Clienți, mesaje, garanții, reamintiri | ✓ | ✓ | — |
| Încasări, rapoarte | ✓ | ✓ | — |
| Mașini de vânzare, cursuri | ✓ | ✓ | — |
| Intrări în stoc | ✓ | ✓ | — |
| Setări, prețuri, echipă, utilizatori, backup, jurnal | ✓ | — | — |
| Ștergerea plăților, anularea predării, prețuri negociate | ✓ | — | — |
| Export și anonimizare GDPR | ✓ | — | — |

Restricțiile se aplică pe server, nu doar în meniu: un tehnician nu primește sume nici dacă apelează direct API-ul.

## 6. Configuratorul de pe site → Cereri

Activare: **Setări → Legături → Configuratorul de pe site**.

**Varianta recomandată, de la server la server.** Serverul site-ului trimite cererea:
```
POST https://crm.autoluxe.ro/intake.php
Content-Type: application/json
X-Api-Key: <cheia generată în Setări → Legături>

{
  "name": "Elena Vasile",
  "phone": "0746 302 718",
  "email": "elena@exemplu.ro",
  "car": { "brand": "Tesla", "model": "Model 3", "year": 2025, "plate": "DJ 25 ELV", "color": "Alb" },
  "services": ["ppf_front", "cer_4"],
  "desired_date": "2026-11-03",
  "pickup": false,
  "pickup_addr": "",
  "note": "Text liber din formular",
  "website": ""
}
```
- `services`: codurile serviciilor din **Setări → Servicii** (coloana Cod). Un cod necunoscut sau inactiv întoarce 422.
- `website`: câmp-capcană pentru roboți. Trebuie să rămână gol; dacă e completat, cererea nu se salvează, dar răspunsul e tot 200.
- Răspunsuri: `201 {"ok":true,"id":123}`, `422` date invalide, `401` cheie greșită, `429` prea multe cereri.

**Varianta directă din navigator.** E acceptată doar de pe originile trecute în Setări, fără cheie, cu limita de 5 cereri pe oră de la același IP. E mai expusă la spam. **Cheia nu se pune niciodată în JavaScript-ul site-ului.**

## 7. Copii de siguranță

**Automat (recomandat):** în cron, zilnic:
```
17 3 * * * /usr/bin/python3 /home/cont/autoluxe/tools/backup.py --data /home/cont/autoluxe/data >> /home/cont/autoluxe/data/logs/backup.log 2>&1
```
Scriptul face următoarele: copiază baza cu API-ul de backup SQLite (sigur în timpul funcționării), verifică integritatea, comprimă copia, arhivează fotografiile noi și păstrează 30 de zile plus câte o copie pe lună timp de 12 luni.

**Copiați periodic `data/backups/` în altă locație** (alt server, S3, NAS), de exemplu cu `rclone`. O copie pe același server nu vă protejează dacă se pierde serverul.

**Manual:** Setări → Siguranță → „Descarcă baza de date”.

**Restaurare:** opriți accesul (redenumiți temporar `public/index.php`), decomprimați copia (`gunzip`) și puneți-o ca `data/autoluxe.sqlite`, ștergeți `autoluxe.sqlite-wal` și `-shm`, apoi dezarhivați fotografiile în `data/`.

## 8. Actualizări

1. Faceți o copie de siguranță.
2. Înlocuiți `app/` (fără `config.php`) și `public/` (fără `paths.php`, dacă l-ați modificat).
3. Schema bazei se actualizează din `migrate()` în `app/lib/db.php`, pe baza `SCHEMA_VERSION`. Pentru versiunile viitoare: adăugați pașii de migrare acolo și creșteți versiunea.

## 9. Ce rămâne manual în această versiune

- **Factura fiscală** se emite în SmartBill; numărul ei se trece la plată, iar Încasări semnalează plățile fără număr de factură. Legătura automată cere cheia API SmartBill și acordul contabilului pentru seria de facturare.
- **WhatsApp**: mesajele se deschid gata scrise în WhatsApp (link `wa.me`) și se salvează în jurnalul clientului. Trimiterea automată și primirea mesajelor cer WhatsApp Business API (cont Meta verificat).
- **Grosimea vopselei** se introduce manual, după măsurarea cu aparatul.

## 10. Limite tehnice cunoscute

- SQLite e potrivit pentru un atelier: zeci de utilizatori, zeci de mii de lucrări. Scrierile se fac pe rând (cu așteptare de până la 8 secunde). Pentru mai multe ateliere sau mai mult de ~30 de utilizatori simultan, recomandăm migrarea pe MySQL sau PostgreSQL; codul folosește PDO și SQL standard, cu excepția câtorva `PRAGMA` și `ON CONFLICT`.
- Toate datele afișate sunt în ora României (`timezone` din config). Calculul zilelor și al săptămânilor se face pe date calendaristice, deci nu e afectat de schimbarea orei.

## 11. Testare

Pe o instalare de **test**, nu de producție (testul creează date):
```
php -S 127.0.0.1:8080 -t public          # server local
python3 tools/test_api.py http://127.0.0.1:8080 admin@test.ro 'parola-admin'
```
Testul verifică fluxul complet: cerere → programare → recepție → fotografii → proces-verbal → predare → garanții → stoc → rapoarte. Verifică și securitatea: CSRF, origine, roluri, încărcări malițioase, sesiuni, configurator.
