Integrate shared JWT authentication into data-entry-app: - Add Oracle pool initialization for auth service - Add AuthenticationMiddleware to protect API routes - Update all receipt endpoints to use CurrentUser from JWT - Add shared auth router (/api/auth/login, /api/auth/refresh) Add nomenclature synchronization feature: - Create SQLite models for synced suppliers, local suppliers, and cash registers - Add nomenclature router with sync triggers and CRUD endpoints - Add sync service for Oracle → SQLite nomenclature data - Update nomenclature_service to use synced SQLite data with fallbacks Create shared frontend components: - Add shared/frontend/ with LoginView.vue, auth store factory, login.css - Integrate shared login and auth into data-entry-app frontend - Add axios-based API service with token refresh interceptor 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
347 lines
12 KiB
Markdown
347 lines
12 KiB
Markdown
# Plan: Implementare Auth SSO + Nomenclatoare Sync
|
|
|
|
> **Plan Handover Document** - Salvat pentru continuare în altă sesiune
|
|
> **Data**: 2025-12-13 | **Branch**: `feature/data-entry-receipts`
|
|
|
|
## Obiectiv
|
|
Integrare autentificare SSO și sincronizare nomenclatoare Oracle în data-entry-app conform `IMPLEMENTATION_PLAN_AUTH_UNITAR.md`.
|
|
|
|
---
|
|
|
|
## Instrucțiuni Implementare
|
|
|
|
### Metodologie
|
|
1. **Execută fazele în paralel** unde e posibil (Faza 1+2 pot rula simultan, Faza 3+4 pot rula simultan)
|
|
2. **Folosește agenți Task** pentru viteza - lansează agenți în paralel pentru task-uri independente
|
|
3. **Testează după fiecare fază** - nu trece la următoarea fără validare
|
|
4. **Urmărește progresul** în acest fișier - marchează task-urile completate cu ✅
|
|
|
|
### Comenzi de Start
|
|
```bash
|
|
# Asigură-te că SSH tunnel rulează (pentru Oracle)
|
|
./ssh_tunnel.sh start
|
|
|
|
# Backend reports (pentru auth API - port 8001)
|
|
cd reports-app/backend && uvicorn app.main:app --reload --port 8001
|
|
|
|
# Backend data-entry (port 8003)
|
|
cd data-entry-app/backend && uvicorn app.main:app --reload --port 8003
|
|
|
|
# Frontend data-entry (port 3010)
|
|
cd data-entry-app/frontend && npm run dev
|
|
```
|
|
|
|
### Progres Implementare
|
|
- [x] **FAZA 1**: Auth Backend - ✅ 6/6 task-uri COMPLETE
|
|
- [x] **FAZA 2**: Auth Frontend - ✅ 6/6 task-uri COMPLETE
|
|
- [x] **FAZA 3**: Nomenclatoare Sync - ✅ 6/6 task-uri COMPLETE
|
|
- [x] **FAZA 4**: OCR + Supplier Search - ✅ 2/2 task-uri COMPLETE
|
|
|
|
> **Status**: ✅ **IMPLEMENTARE COMPLETĂ** - 2025-12-13
|
|
|
|
---
|
|
|
|
## Stare Curentă (IMPLEMENTAT)
|
|
|
|
### Backend Data-Entry ✅
|
|
- ✅ Models: Receipt, ReceiptAttachment, AccountingEntry - complete
|
|
- ✅ CRUD operations - complete
|
|
- ✅ API Routers: receipts.py, ocr.py, **nomenclature.py**
|
|
- ✅ Services: receipt_service, ocr_service, **sync_service**
|
|
- ✅ Workflow: DRAFT → PENDING → APPROVED/REJECTED
|
|
- ✅ **Auth**: Integrare shared/auth (middleware + CurrentUser)
|
|
- ✅ **Nomenclatoare**: SQLite sync (SyncedSupplier, LocalSupplier, SyncedCashRegister)
|
|
- ✅ `sys.path.insert` pentru shared/ în main.py
|
|
|
|
### Frontend Data-Entry ✅
|
|
- ✅ Views: List, Create, Detail, Approval, **LoginView**
|
|
- ✅ Components: OCR components + **Create Supplier Dialog**
|
|
- ✅ Store: receiptsStore.js + **auth.js**
|
|
- ✅ Router: routes + **auth guards + /login**
|
|
- ✅ **Auth Store**: `src/stores/auth.js` - creat
|
|
- ✅ **Login View**: `src/views/LoginView.vue` - creat
|
|
- ✅ **Router Guards**: beforeEach cu requiresAuth
|
|
- ✅ **API Service**: `src/services/api.js` - creat cu interceptors
|
|
|
|
### Shared Auth (disponibil pentru integrare)
|
|
- ✅ `shared/auth/routes.py` - `create_auth_router()` (linia 39-430)
|
|
- ✅ `shared/auth/middleware.py` - `AuthenticationMiddleware`
|
|
- ✅ `shared/auth/dependencies.py` - `get_current_user`
|
|
- ✅ `shared/auth/models.py` - `CurrentUser`, `TokenResponse`
|
|
|
|
### Referință Reports-App (pentru copiere)
|
|
- `reports-app/frontend/src/stores/auth.js` - 119 linii
|
|
- `reports-app/frontend/src/services/api.js` - 141 linii
|
|
- `reports-app/frontend/src/views/LoginView.vue` - 367 linii
|
|
- `reports-app/frontend/src/router/index.js` - auth guard la liniile 96-114
|
|
|
|
---
|
|
|
|
## Faze Implementare
|
|
|
|
### FAZA 1: Auth Backend (6 task-uri)
|
|
|
|
#### Task 1.1: Adaugă AuthenticationMiddleware în main.py
|
|
**Fișier**: `data-entry-app/backend/app/main.py`
|
|
**Acțiune**: După CORS middleware (linia 75), adaugă:
|
|
```python
|
|
from auth.middleware import AuthenticationMiddleware
|
|
app.add_middleware(
|
|
AuthenticationMiddleware,
|
|
excluded_paths=["/docs", "/redoc", "/openapi.json", "/health", "/", "/api/auth/login", "/api/auth/refresh"]
|
|
)
|
|
```
|
|
|
|
#### Task 1.2: Adaugă Auth Router în main.py
|
|
**Fișier**: `data-entry-app/backend/app/main.py`
|
|
**Acțiune**: După include_router pentru ocr (linia 98), adaugă:
|
|
```python
|
|
from auth.routes import create_auth_router
|
|
auth_router = create_auth_router()
|
|
app.include_router(auth_router, prefix="/api/auth", tags=["auth"])
|
|
```
|
|
|
|
#### Task 1.3: Înlocuiește get_current_user în receipts.py
|
|
**Fișier**: `data-entry-app/backend/app/routers/receipts.py`
|
|
**Acțiune**: Șterge liniile 38-59 și înlocuiește cu:
|
|
```python
|
|
from auth.dependencies import get_current_user
|
|
from auth.models import CurrentUser
|
|
```
|
|
Apoi actualizează type hints: `current_user: str` → `current_user: CurrentUser`
|
|
Și accesează `current_user.username` în loc de `current_user`
|
|
|
|
#### Task 1.4: Înlocuiește get_current_user în ocr.py
|
|
**Fișier**: `data-entry-app/backend/app/routers/ocr.py`
|
|
**Acțiune**: Similar cu receipts.py, adaugă importurile auth și folosește `CurrentUser`
|
|
|
|
#### Task 1.5: Actualizează type hints în toate endpoint-urile
|
|
Actualizează toate funcțiile care folosesc `current_user: str` să folosească `current_user: CurrentUser`
|
|
|
|
#### Task 1.6: Testare backend auth
|
|
```bash
|
|
cd data-entry-app/backend
|
|
uvicorn app.main:app --reload --port 8003
|
|
# Test: curl http://localhost:8003/api/receipts/ → 401 Unauthorized
|
|
```
|
|
|
|
---
|
|
|
|
### FAZA 2: Auth Frontend (6 task-uri)
|
|
|
|
#### Task 2.1: Crează API service
|
|
**Fișier NOU**: `data-entry-app/frontend/src/services/api.js`
|
|
**Acțiune**: Copiază din `reports-app/frontend/src/services/api.js` cu modificări:
|
|
- Schimbă BASE_URL pentru a funcționa cu proxy-ul
|
|
- Modifică refresh token URL
|
|
|
|
#### Task 2.2: Crează Auth Store
|
|
**Fișier NOU**: `data-entry-app/frontend/src/stores/auth.js`
|
|
**Acțiune**: Copiază din `reports-app/frontend/src/stores/auth.js`
|
|
- Modifică import apiService din `../services/api`
|
|
|
|
#### Task 2.3: Crează LoginView
|
|
**Fișier NOU**: `data-entry-app/frontend/src/views/LoginView.vue`
|
|
**Acțiune**: Copiază din `reports-app/frontend/src/views/LoginView.vue`
|
|
- Schimbă titlul: "ROA Reports" → "Data Entry"
|
|
- Schimbă subtitle: "Rapoarte ERP" → "Introducere Bonuri Fiscale"
|
|
- Schimbă redirect după login: "/dashboard" → "/"
|
|
|
|
#### Task 2.4: Actualizează Router cu auth guards
|
|
**Fișier**: `data-entry-app/frontend/src/router/index.js`
|
|
**Acțiune**: Adaugă auth guard similar cu reports-app (liniile 96-114)
|
|
```javascript
|
|
import { useAuthStore } from '@/stores/auth'
|
|
// Adaugă rută login
|
|
// Adaugă meta: { requiresAuth: true } la rutele protejate
|
|
// Adaugă beforeEach guard
|
|
```
|
|
|
|
#### Task 2.5: Actualizează vite.config.js pentru auth proxy
|
|
**Fișier**: `data-entry-app/frontend/vite.config.js`
|
|
**Acțiune**: Adaugă proxy pentru auth:
|
|
```javascript
|
|
'/api/auth': {
|
|
target: 'http://localhost:8001',
|
|
changeOrigin: true,
|
|
}
|
|
```
|
|
|
|
#### Task 2.6: Testare frontend auth
|
|
```bash
|
|
cd data-entry-app/frontend
|
|
npm run dev
|
|
# Test: Accesează http://localhost:3010 → Redirect la /login
|
|
# Login cu credențiale Oracle → Redirect la /
|
|
```
|
|
|
|
---
|
|
|
|
### FAZA 3: Nomenclatoare Oracle→SQLite (6 task-uri)
|
|
|
|
#### Task 3.1: Crează modele SQLModel
|
|
**Fișier NOU**: `data-entry-app/backend/app/db/models/nomenclature.py`
|
|
- `SyncedSupplier` - furnizori sincronizați din Oracle
|
|
- `LocalSupplier` - furnizori creați local (din OCR)
|
|
- `SyncedCashRegister` - case/bănci sincronizate
|
|
|
|
#### Task 3.2: Crează Alembic migration
|
|
```bash
|
|
cd data-entry-app/backend
|
|
alembic revision --autogenerate -m "add nomenclature tables"
|
|
alembic upgrade head
|
|
```
|
|
|
|
#### Task 3.3: Crează Sync Service
|
|
**Fișier NOU**: `data-entry-app/backend/app/services/sync_service.py`
|
|
- `sync_suppliers(company_id, schema)` - sync furnizori Oracle→SQLite
|
|
- `sync_cash_registers(company_id, schema)` - sync case/bănci
|
|
- `get_schema_for_company(company_id)` - lookup schema
|
|
|
|
#### Task 3.4: Crează Nomenclature Router
|
|
**Fișier NOU**: `data-entry-app/backend/app/routers/nomenclature.py`
|
|
- `GET /suppliers/search` - căutare furnizor (SQLite + Oracle live)
|
|
- `POST /suppliers/local` - creare furnizor local
|
|
- `POST /sync/suppliers` - trigger manual sync
|
|
|
|
#### Task 3.5: Înregistrează router în main.py
|
|
```python
|
|
from app.routers import nomenclature
|
|
app.include_router(nomenclature.router, prefix="/api/nomenclature", tags=["nomenclature"])
|
|
```
|
|
|
|
#### Task 3.6: Actualizare nomenclature_service.py existent
|
|
Înlocuiește mock data cu query-uri din tabelele SQLite sincronizate
|
|
|
|
---
|
|
|
|
### FAZA 4: Integrare OCR + Supplier Search (2 task-uri)
|
|
|
|
#### Task 4.1: Actualizare ReceiptCreateView.vue
|
|
**Fișier**: `data-entry-app/frontend/src/views/receipts/ReceiptCreateView.vue`
|
|
**Acțiune**: După OCR result, caută automat furnizor după CUI:
|
|
```javascript
|
|
async function handleOCRResult(ocrData) {
|
|
if (ocrData.cui) {
|
|
const result = await receiptsStore.searchSupplier(ocrData.cui);
|
|
if (result.found) {
|
|
form.partner_id = result.supplier.id;
|
|
form.partner_name = result.supplier.name;
|
|
} else {
|
|
showCreateSupplierDialog(ocrData);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Task 4.2: Adaugă supplier search în receiptsStore.js
|
|
**Fișier**: `data-entry-app/frontend/src/stores/receiptsStore.js`
|
|
**Acțiune**: Adaugă action `searchSupplier(fiscalCode)` și `createLocalSupplier(data)`
|
|
|
|
---
|
|
|
|
## Sumar Fișiere
|
|
|
|
### De Modificat
|
|
| Fișier | Faza |
|
|
|--------|------|
|
|
| `data-entry-app/backend/app/main.py` | 1, 3 |
|
|
| `data-entry-app/backend/app/routers/receipts.py` | 1 |
|
|
| `data-entry-app/backend/app/routers/ocr.py` | 1 |
|
|
| `data-entry-app/frontend/src/router/index.js` | 2 |
|
|
| `data-entry-app/frontend/vite.config.js` | 2 |
|
|
| `data-entry-app/frontend/src/views/receipts/ReceiptCreateView.vue` | 4 |
|
|
| `data-entry-app/frontend/src/stores/receiptsStore.js` | 4 |
|
|
|
|
### De Creat (NOU)
|
|
| Fișier | Faza |
|
|
|--------|------|
|
|
| `data-entry-app/frontend/src/services/api.js` | 2 |
|
|
| `data-entry-app/frontend/src/stores/auth.js` | 2 |
|
|
| `data-entry-app/frontend/src/views/LoginView.vue` | 2 |
|
|
| `data-entry-app/backend/app/db/models/nomenclature.py` | 3 |
|
|
| `data-entry-app/backend/app/services/sync_service.py` | 3 |
|
|
| `data-entry-app/backend/app/routers/nomenclature.py` | 3 |
|
|
| `migrations/versions/xxx_nomenclature.py` | 3 |
|
|
|
|
---
|
|
|
|
## Ordine Execuție
|
|
|
|
**Faza 1 + 2 (Auth)** → **Faza 3 + 4 (Nomenclatoare)**
|
|
|
|
Fazele 1-2 sunt blocante pentru funcționalitatea completă, dar Faza 3-4 poate fi amânată dacă e nevoie (nomenclatoarele rămân mock data temporar).
|
|
|
|
---
|
|
|
|
## Strategie Execuție cu Agenți
|
|
|
|
### Agenți Paraleli Recomandați
|
|
|
|
**Round 1 - Auth (Backend + Frontend simultan):**
|
|
```
|
|
Agent A: Faza 1 - Task 1.1-1.5 (Backend auth)
|
|
Agent B: Faza 2 - Task 2.1-2.3 (Frontend auth files)
|
|
```
|
|
După Round 1, testare manuală auth flow.
|
|
|
|
**Round 2 - Finalizare Auth + Start Nomenclatoare:**
|
|
```
|
|
Agent A: Faza 2 - Task 2.4-2.5 (Router guards, vite config)
|
|
Agent B: Faza 3 - Task 3.1-3.2 (Modele SQLModel + migration)
|
|
```
|
|
|
|
**Round 3 - Nomenclatoare + Integration:**
|
|
```
|
|
Agent A: Faza 3 - Task 3.3-3.6 (Sync service + router)
|
|
Agent B: Faza 4 - Task 4.1-4.2 (Frontend OCR supplier)
|
|
```
|
|
|
|
### Validare După Fiecare Fază
|
|
|
|
**După Faza 1:**
|
|
```bash
|
|
curl http://localhost:8003/api/receipts/
|
|
# Expected: 401 Unauthorized
|
|
```
|
|
|
|
**După Faza 2:**
|
|
```bash
|
|
# Browser: http://localhost:3010
|
|
# Expected: Redirect to /login
|
|
# Login cu credențiale Oracle → Redirect la /
|
|
```
|
|
|
|
**După Faza 3:**
|
|
```bash
|
|
curl http://localhost:8003/api/nomenclature/suppliers/search?fiscal_code=RO12345678
|
|
# Expected: Search result sau sugestie creare local
|
|
```
|
|
|
|
**După Faza 4:**
|
|
```
|
|
# Browser: Crează bon nou → Upload poză → OCR
|
|
# Expected: Furnizor găsit automat sau dialog creare
|
|
```
|
|
|
|
---
|
|
|
|
## Context pentru Sesiune Următoare
|
|
|
|
### Fișiere Cheie de Citit
|
|
1. Acest plan: `/home/marius/.claude/plans/unified-orbiting-sonnet.md`
|
|
2. CLAUDE.md principal: `/mnt/e/proiecte/roa2web/CLAUDE.md`
|
|
3. CLAUDE.md data-entry: `/mnt/e/proiecte/roa2web/data-entry-app/CLAUDE.md`
|
|
|
|
### Comenzi Quick Start
|
|
```bash
|
|
cd /mnt/e/proiecte/roa2web
|
|
git status # Verifică branch feature/data-entry-receipts
|
|
./ssh_tunnel.sh start # SSH tunnel pentru Oracle
|
|
```
|
|
|
|
### Dependențe Servicii
|
|
- **reports-backend:8001** - NECESAR pentru auth API (login, refresh)
|
|
- **data-entry-backend:8003** - Backend principal
|
|
- **Oracle DB** - Via SSH tunnel, necesar pentru auth + nomenclatoare
|