# Date personale

Ce date despre oameni ține platforma, cine le poate vedea, ce nu ajunge niciodată în jurnale și cum se scoate un om din evidențe.

## Pe scurt

| Cine | Ce se ține | Cine vede |
| --- | --- | --- |
| Conturile platformei | nume, email, ultima activitate, parola (doar ca hash) | membrii firmelor contului; hash-ul parolei nu îl citește nici aplicația |
| Angajații echipei | nume, specialitate, ora de venire, data angajării, tipul contractului, țara, anul nașterii, salariul net și brut, legături către contract și documente, poza | membrii firmei; salariile doar `admin`, `patron`, `finante` |
| Clienții de catering | numele, firma, telefonul, adresa de livrare; la abonați și valoarea lunară | doar `admin` |
| Clienții de fidelitate | numele, telefonul, data acordului și versiunea lui, acordul pentru oferte | dreptul `fidelitate.citeste` |
| Clienții firmei (B2B) | numele, CUI-ul, orașul | membrii firmei, după drepturi |
| Activitatea în platformă | ultima „bătaie” pe pagină, urmele de acțiuni ale contului | firma activă |
| Schimbările de parolă | contul, cine a schimbat, pe ce cale, când, IP-ul (fără hash) | nicio rută a API-ului nu le citește |

## Cine vede ce

### Izolarea pe firmă

Fiecare tabel cu `firma_id` are Row Level Security în mod `FORCE`: o interogare vede doar rândurile firmei active, indiferent ce cere. Asta se aplică angajaților, comenzilor de catering, clienților de fidelitate și clienților B2B (vezi [Securitate](#securitate)).

Conturile nu aparțin unei singure firme: un cont se vede doar dacă are acces la firma activă, sau dacă e chiar contul tău.

### Parola

Aplicația poate citi din tabelul conturilor doar `id`, `nume`, `email`, `ultima_activitate` și `creat_la`. Coloana cu hash-ul parolei nu îi este dată deloc.

### Salariile

`GET /v1/angajati` întoarce lista oricărui membru al firmei, dar cheile `salariuNet` și `salariuBrut` apar doar pentru rolurile `admin`, `patron` și `finante`. Pentru restul, cheile lipsesc din răspuns (nu sunt goale, lipsesc). Cine încearcă să scrie un salariu fără acest drept primește `403 interzis_salarii`.

### Rolurile pe pagini

Restul se decide pe rol și pe drepturi (vezi [Roluri și drepturi](#roluri-si-drepturi)): comenzile de catering doar pentru `admin`, fidelitatea pe drepturile `fidelitate.citeste` și `fidelitate.gestioneaza`.

## Ce nu ajunge în jurnale

Jurnalul serverului ascunde mereu, înlocuind cu `[ascuns]`:

| Ce | Unde |
| --- | --- |
| câmpul `secret` | oriunde în obiectul scris, inclusiv în corpul cererii |
| cookie-ul | antetul `Cookie` |
| autorizarea | antetul `Authorization` |

Două căi poartă un cod secret chiar în adresă. În jurnal, codul e înlocuit cu `[cod]`:

```text title="Căile redactate"
/v1/invitatii/<cod>[/accepta]   →  /v1/invitatii/[cod]
/v1/fidelitate/card/<cod>       →  /v1/fidelitate/card/[cod]
```

Pentru fiecare cerere, jurnalul scrie doar metoda, adresa (redactată), gazda și adresa IP. La o eroare neprevăzută scrie ruta (tiparul, fără valori), metoda, id-ul cererii și eroarea; niciodată corpul, cookie-ul, antetele sau query-ul.

> [!NOTE]
> Fără `LOG=1`, jurnalul scrie doar erorile; cererile obișnuite nu se scriu deloc. Redactarea se aplică oricum, oricare ar fi nivelul.

## Scoaterea unui om

| Cine | Ce se poate face | Ce rămâne |
| --- | --- | --- |
| Contul platformei | administratorul oprește accesul la firmă (`PATCH /v1/acces/oameni/:id` cu `{"acces": false}`) | contul; în API nu există o rută care șterge un cont |
| Poza de profil | omul o scoate (`DELETE /v1/profil/poza`) | fișierul se mută în arhivă, nu se șterge |
| Clientul de fidelitate | anonimizare: `POST /v1/fidelitate/clienti/:id/sterge`, cu dreptul `fidelitate.gestioneaza` | rândul rămâne cu numele `Șters`, telefonul gol, un cod de card nou și data ștergerii; punctele rămân ca registru |
| Comanda de catering | — | aplicația poate citi, adăuga și modifica, dar nu șterge |

```json title="Anonimizarea unui client de fidelitate"
POST /v1/fidelitate/clienti/7c1e.../sterge
→ 200 { "sters": true }
```

A doua cerere pe același client întoarce `404`: clientul e deja șters.

## Acordul clientului de fidelitate

La înscriere, clientul bifează explicit acordul (`acord: true`, nimic altceva nu e acceptat). Acordul pentru mesaje cu oferte este o bifă separată și lipsa ei înseamnă „nu”. Se păstrează data acordului și versiunea textului acceptat. Cardul de fidelitate este un cod aleator, fără date personale în el.

> [!WARNING]
> Anonimizarea schimbă doar numele, telefonul și codul cardului. Date personale scrise în alte câmpuri (note, descrieri, etichete, în alte module) nu se șterg odată cu clientul.
