diff --git a/.env.example b/.env.example index bf04a59..0199847 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,5 @@ # ───────────────────────────────────────────────────────────────────────────── -# PecFlow – Variabili d'ambiente +# PEChub – Variabili d'ambiente # Copia questo file in .env e personalizza i valori # NON committare mai il file .env con valori reali # ───────────────────────────────────────────────────────────────────────────── @@ -25,12 +25,12 @@ ENCRYPTION_KEY=change-me-generate-a-random-64-char-hex-string-here-11111111111 # ── Database PostgreSQL ─────────────────────────────────────────────────────── POSTGRES_HOST=db POSTGRES_PORT=5432 -POSTGRES_DB=pecflow -POSTGRES_USER=pecflow -POSTGRES_PASSWORD=pecflow_dev_password +POSTGRES_DB=pechub +POSTGRES_USER=pechub +POSTGRES_PASSWORD=pechub_dev_password -DATABASE_URL=postgresql+asyncpg://pecflow:pecflow_dev_password@db:5432/pecflow -DATABASE_URL_SYNC=postgresql://pecflow:pecflow_dev_password@db:5432/pecflow +DATABASE_URL=postgresql+asyncpg://pechub:pechub_dev_password@db:5432/pechub +DATABASE_URL_SYNC=postgresql://pechub:pechub_dev_password@db:5432/pechub # ── Redis ───────────────────────────────────────────────────────────────────── REDIS_URL=redis://redis:6379/0 @@ -39,7 +39,7 @@ REDIS_URL=redis://redis:6379/0 MINIO_ENDPOINT=minio:9000 MINIO_ACCESS_KEY=minioadmin MINIO_SECRET_KEY=minioadmin -MINIO_BUCKET=pecflow +MINIO_BUCKET=pechub MINIO_USE_SSL=false # ── CORS ────────────────────────────────────────────────────────────────────── @@ -58,4 +58,4 @@ SYSTEM_SMTP_HOST= SYSTEM_SMTP_PORT=587 SYSTEM_SMTP_USER= SYSTEM_SMTP_PASSWORD= -SYSTEM_SMTP_FROM=noreply@pecflow.it +SYSTEM_SMTP_FROM=noreply@pechub.it diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 771c64a..e288c78 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,4 +1,4 @@ -# PecFlow – Architettura di Sistema +# PEChub – Architettura di Sistema > **Documento redatto il:** 2026-03-18 | **Ultima revisione:** 2026-03-18 > **Versione:** 2.0 @@ -26,7 +26,7 @@ Monorepo con workspace separati. Il confine di responsabilità è netto: ogni cartella di primo livello è un deployable (o una libreria condivisa) indipendente. ``` -PecFlow/ ← root del monorepo +PEChub/ ← root del monorepo │ ├── .github/ ← CI/CD GitHub Actions │ ├── workflows/ @@ -279,14 +279,14 @@ PecFlow/ ← root del monorepo │ ├── nginx/ │ │ ├── nginx.conf # reverse proxy, rate limiting, TLS termination │ │ └── conf.d/ -│ │ └── pecflow.conf +│ │ └── pechub.conf │ ├── redis/ │ │ └── redis.conf # maxmemory, eviction policy │ ├── prometheus/ │ │ └── prometheus.yml │ └── grafana/ │ └── dashboards/ -│ └── pecflow.json +│ └── pechub.json │ └── docs/ ═══════════════════════════════ ├── api/ ← OpenAPI spec generata (non commitare auto-gen) @@ -326,7 +326,7 @@ CREATE EXTENSION IF NOT EXISTS "pgcrypto"; -- gen_random_bytes per nonce AES -- ============================================================ CREATE TABLE tenants ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - slug VARCHAR(63) NOT NULL UNIQUE, -- usato come subdomain: acme.pecflow.it + slug VARCHAR(63) NOT NULL UNIQUE, -- usato come subdomain: acme.pechub.it name VARCHAR(255) NOT NULL, plan VARCHAR(50) NOT NULL DEFAULT 'starter', -- starter|pro|enterprise is_active BOOLEAN NOT NULL DEFAULT TRUE, @@ -1000,7 +1000,7 @@ Il conservatore AgID può essere temporaneamente non disponibile (manutenzione, **Strategia:** 1. **Backoff esponenziale con jitter:** tentativo 1 subito, poi 1h, 4h, 24h (max 3 retry oltre il primo) -2. **Dead letter queue:** dopo tutti i retry falliti, il batch va in stato `failed` e genera un alert email all'admin del tenant + al team ops PecFlow +2. **Dead letter queue:** dopo tutti i retry falliti, il batch va in stato `failed` e genera un alert email all'admin del tenant + al team ops PEChub 3. **Idempotenza:** prima di ogni retry, verificare se il conservatore ha già ricevuto il versamento (`GET /versamento/{id}`) per evitare duplicati 4. **Finestra di versamento:** i versamenti periodici (es. mensili) devono completarsi entro la scadenza normativa; se il sistema prevede che non ce la farà, genera alert anticipato a 72h dalla scadenza 5. **Circuit breaker:** se il conservatore fallisce 5 volte in 1 ora, si sospendono tutti i versamenti verso quel conservatore per 30 minuti (evita tempesta di retry) @@ -1418,7 +1418,7 @@ alla Fase 1, le altre possono essere sviluppate in parallelo al frontend (Fase 5 - [ ] API `POST /notifications/rules` (crea regola evento → canale + filtri) - [ ] `notification_service.py`: al salvataggio di ogni messaggio, valuta regole applicabili e accoda job - [ ] `worker/notifications/dispatcher.py`: smista per tipo canale -- [ ] `webhook.py`: POST JSON con header `X-PecFlow-Signature: sha256=` per verifica autenticità +- [ ] `webhook.py`: POST JSON con header `X-PEChub-Signature: sha256=` per verifica autenticità - [ ] `email_smtp.py`: template HTML notifica (oggetto, mittente, link messaggio) - [ ] `telegram.py`: messaggio Telegram con MarkdownV2, link deep al messaggio - [ ] `whatsapp.py`: Meta Cloud API `POST /messages` con template pre-approvato (o freeform in 24h window) @@ -1668,10 +1668,10 @@ Evento PEC (trigger: salvataggio nuovo messaggio o cambio stato) **Webhook** ```json -POST https://your-endpoint.com/pecflow-hook +POST https://your-endpoint.com/pechub-hook Headers: - X-PecFlow-Event: message.received - X-PecFlow-Signature: sha256= + X-PEChub-Event: message.received + X-PEChub-Signature: sha256= Content-Type: application/json Body: @@ -1685,7 +1685,7 @@ Body: "mailbox": "info@azienda.it", "received_at": "2026-03-18T14:00:00Z", "state": "received", - "url": "https://app.pecflow.it/messages/..." + "url": "https://app.pechub.it/messages/..." } } ``` @@ -1702,7 +1702,7 @@ Notifica in HTML via template configurabile. Il mittente usa un relay SMTP dedic 📋 Oggetto: Convocazione riunione del 20/03/2026 🕐 Ricevuta: 18/03/2026 14:00 -🔗 Visualizza: https://app.pecflow.it/messages/... +🔗 Visualizza: https://app.pechub.it/messages/... ``` **WhatsApp (Meta Cloud API)** diff --git a/KnowledgeBaseCline.md b/KnowledgeBaseCline.md index dcf3133..d3795f3 100644 --- a/KnowledgeBaseCline.md +++ b/KnowledgeBaseCline.md @@ -26,7 +26,7 @@ Tutto il frontend deve essere in italiano Credenziali admin Ruolo Email Password -Super Admin superadmin@pecflow.it SuperAdmin@PecFlow2026! -Admin (tenant demo) admin@demo.pecflow.it Demo@PecFlow2026! -Operator (tenant demo) operator@demo.pecflow.it Oper@PecFlow2026! +Super Admin superadmin@pechub.it SuperAdmin@PEChub2026! +Admin (tenant demo) admin@demo.pechub.it Demo@PEChub2026! +Operator (tenant demo) operator@demo.pechub.it Oper@PEChub2026! Per accedere all'applicazione usa le credenziali Admin del tenant demo. \ No newline at end of file diff --git a/Makefile b/Makefile index 3059131..f6a830c 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -## PecFlow – Developer Commands +## PEChub – Developer Commands .PHONY: dev down build test migrate seed lint format clean logs ps help @@ -79,7 +79,7 @@ makemigration: ## Genera una nuova migrazione (usa: make makemigration MSG="des $(BACKEND) alembic revision --autogenerate -m "$(MSG)" seed: ## Esegui seed dati di sviluppo (tenant demo + admin) - $(COMPOSE) exec db psql -U pecflow -d pecflow -f /docker-entrypoint-initdb.d/seeds/dev_tenant.sql + $(COMPOSE) exec db psql -U pechub -d pechub -f /docker-entrypoint-initdb.d/seeds/dev_tenant.sql @echo " ✅ Seed completato" reset-db: ## Reset completo DB (down-v + dev + migrate + seed) @@ -151,7 +151,7 @@ shell-backend: ## Shell nel container backend $(BACKEND) bash shell-db: ## psql nel container database - $(COMPOSE) exec db psql -U pecflow -d pecflow + $(COMPOSE) exec db psql -U pechub -d pechub clean: ## Rimuovi file temporanei Python find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true diff --git a/backend/app/api/v1/messages.py b/backend/app/api/v1/messages.py index 8b157a6..1661341 100644 --- a/backend/app/api/v1/messages.py +++ b/backend/app/api/v1/messages.py @@ -362,8 +362,16 @@ async def bulk_update_messages( message.archived_at = None await db.commit() - for message in messages: - await db.refresh(message) + + # Ricarica i messaggi aggiornati con selectinload per evitare MissingGreenlet sui labels + if messages: + updated_ids = [m.id for m in messages] + refreshed_result = await db.execute( + select(Message) + .where(Message.id.in_(updated_ids)) + .options(selectinload(Message.labels)) + ) + messages = list(refreshed_result.scalars().all()) return MessageBulkUpdateResponse( updated=len(messages), @@ -407,7 +415,13 @@ async def update_message( message.archived_at = None await db.commit() - await db.refresh(message) + # Re-query con selectinload per evitare MissingGreenlet sui labels + refreshed = await db.execute( + select(Message) + .where(Message.id == message_id) + .options(selectinload(Message.labels)) + ) + message = refreshed.scalar_one() return MessageResponse.model_validate(message) @@ -508,6 +522,7 @@ async def list_receipts( result = await db.execute( select(Message) .where(Message.parent_message_id == message_id) + .options(selectinload(Message.labels)) .order_by(Message.received_at.asc().nullslast(), Message.created_at.asc()) ) receipts = list(result.scalars().all()) diff --git a/frontend/index.html b/frontend/index.html index d615424..ee6a0fb 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -4,8 +4,8 @@ - PecFlow – Gestore PEC - + PEChub – Gestore PEC +
diff --git a/frontend/package.json b/frontend/package.json index ceb1d26..6f4ef33 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,5 +1,5 @@ { - "name": "pecflow-frontend", + "name": "pechub-frontend", "version": "1.0.0", "private": true, "type": "module", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 26d5800..755a8ae 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -12,7 +12,7 @@ import { VirtualBoxesPage } from '@/pages/VirtualBoxes/VirtualBoxesPage' import { NotificationsPage } from '@/pages/Notifications/NotificationsPage' /** - * Routing principale dell'applicazione PecFlow. + * Routing principale dell'applicazione PEChub. * * Struttura: * - /login → LoginPage (pubblica) diff --git a/frontend/src/components/Layout/Sidebar.tsx b/frontend/src/components/Layout/Sidebar.tsx index d3e7ead..d02a624 100644 --- a/frontend/src/components/Layout/Sidebar.tsx +++ b/frontend/src/components/Layout/Sidebar.tsx @@ -1,9 +1,9 @@ /** - * Sidebar – navigazione principale di PecFlow. + * Sidebar – navigazione principale di PEChub. * * Struttura visiva (sidebar espansa): * ┌────────────────────────────────┐ - * │ [PF] PecFlow [◀] │ + * │ [PF] PEChub [◀] │ * ├────────────────────────────────┤ * │ TUTTE LE CASELLE │ * │ 📥 Posta in Arrivo [badge] │ @@ -140,7 +140,7 @@ export function Sidebar() {
PF
- PecFlow + PEChub )} {collapsed && ( diff --git a/frontend/src/hooks/useWebSocket.ts b/frontend/src/hooks/useWebSocket.ts index 4bc71eb..bf41a8d 100644 --- a/frontend/src/hooks/useWebSocket.ts +++ b/frontend/src/hooks/useWebSocket.ts @@ -1,5 +1,5 @@ /** - * Hook useWebSocket – connessione WebSocket al backend PecFlow. + * Hook useWebSocket – connessione WebSocket al backend PEChub. * * Il backend usa FastAPI WebSocket nativo (non Socket.io). * Endpoint: /api/v1/ws/{tenant_id}?token= diff --git a/frontend/src/pages/Login/LoginPage.tsx b/frontend/src/pages/Login/LoginPage.tsx index 6280c62..7ebcba5 100644 --- a/frontend/src/pages/Login/LoginPage.tsx +++ b/frontend/src/pages/Login/LoginPage.tsx @@ -66,7 +66,7 @@ export function LoginPage() {
PF
-

PecFlow

+

PEChub

Gestore PEC SaaS

@@ -188,7 +188,7 @@ export function LoginPage() {

- PecFlow v1.0 – Piattaforma gestione PEC certificata + PEChub v1.0 – Piattaforma gestione PEC certificata

diff --git a/frontend/src/pages/Notifications/NotificationsPage.tsx b/frontend/src/pages/Notifications/NotificationsPage.tsx index 6711ebb..7f5f127 100644 --- a/frontend/src/pages/Notifications/NotificationsPage.tsx +++ b/frontend/src/pages/Notifications/NotificationsPage.tsx @@ -447,7 +447,7 @@ function RulesTab() {

Nessuna regola

- Le regole collegano gli eventi PecFlow ai canali di notifica. + Le regole collegano gli eventi PEChub ai canali di notifica.

) diff --git a/frontend/src/store/auth.store.ts b/frontend/src/store/auth.store.ts index 1a387ff..bb6e5e9 100644 --- a/frontend/src/store/auth.store.ts +++ b/frontend/src/store/auth.store.ts @@ -99,7 +99,7 @@ export const useAuthStore = create()( }) }, }), - { name: 'PecFlow/Auth' }, + { name: 'PEChub/Auth' }, ), ) diff --git a/infra/redis/redis.conf b/infra/redis/redis.conf index e7b805f..d23d4ba 100644 --- a/infra/redis/redis.conf +++ b/infra/redis/redis.conf @@ -1,4 +1,4 @@ -# Redis configuration per PecFlow +# Redis configuration per PEChub # ── Bind e rete ─────────────────────────────────────────────────────────────── bind 0.0.0.0 diff --git a/worker/pyproject.toml b/worker/pyproject.toml index 1851f85..c31231c 100644 --- a/worker/pyproject.toml +++ b/worker/pyproject.toml @@ -3,9 +3,9 @@ requires = ["setuptools>=68", "wheel"] build-backend = "setuptools.build_meta" [project] -name = "pecflow-worker" +name = "pechub-worker" version = "1.0.0" -description = "PecFlow – Worker IMAP sync + background jobs" +description = "PEChub – Worker IMAP sync + background jobs" requires-python = ">=3.12" dependencies = [