Servid Inventory — Analisi Tecnica dei Flussi

Documento tecnico per developer review · Aggiornato Aprile 2026

Architettura del Modulo Inventario

14

Componenti UI

Stack tecnologico

ORM:Prisma 6 — schema-first, db push (no migrations)
Framework:Next.js 15 App Router, TypeScript strict
Auth / RBAC:NextAuth v5 — 6 ruoli: SUPER_ADMIN, BRAND_ADMIN, WORKSHOP_MANAGER, WAREHOUSE_OPERATOR, TECHNICIAN, HEAD_AFTERSALES
UI:TailwindCSS 4, shadcn/ui, Recharts
i18n:next-intl — it, en, de, fr
DB:PostgreSQL 16 — 13 modelli inventory, 11 enum
Validazione API:Zod su tutti gli input, try/catch, HTTP status codes semantici
State mgmt:Zustand (toasts/notifiche), useState locale per form

Modelli Dati Chiave

ModelloCampi chiaveRelazioni principali
name, workshopId, locationInventoryItem[], FiscalYear[]
partNumber, description, expectedQty, unitPrice, abcClass, xyzClass, rotationClass, location, barcode, lastCountedAt, countFrequencyWarehouse, DiscrepancyCorrection[]
name, startDate, endDate, workingDaysPerWeek, holidays (JSON), dailyTarget, status, tranchePeriodWarehouse, FiscalTranche[], DailyCountPlan[]
type (QUARTERLY/SEMI_ANNUAL/CUSTOM), startDate, endDate, status, targetCoverageFiscalYear, InventorySession[]
planDate, targetCount, algorithm, status, generatedItems (JSON), algorithmConfig (JSON)FiscalYear, Warehouse, InventorySession?
name, type, status, countingMode (BLIND/GUIDED), fiscalYearIdWarehouse, InventoryCheck[], InventoryReport?
status, assignedToIdInventorySession, InventoryCheckItem[]
expectedQty, actualQty, discrepancy, checkedAt, barcode, photoInventoryCheck, InventoryItem
expectedQty, actualQty, discrepancy, valueDifference, status, correctedById, confirmedByIdInventoryItem, InventorySession
type, severity, message, warehouseId, isDismissed
snapshotDate, totalPositions, totalQty, totalValue, itemCountWarehouse
totalItems, checkedItems, discrepancies, accuracy, reportData (JSON), pdfUrlInventorySession

Flussi Operativi

3

Generazione Piano Giornaliero — «La Regia»

1
POST /api/inventory/daily-plans/generate

Richiede warehouseId, date, algorithm, targetCount. Delega all'algorithm-registry.

2
algorithm-registry.ts → runAlgorithm()6 algoritmi disponibili

Factory pattern: seleziona l'algoritmo e chiama il selettore corrispondente.

3
SMART_COMPOSITE (La Regia)

Score composito: ABC class 25% + scaduto/mai contato 25% + storia discrepanze 20% + rotazione 20% + clustering zona 10%.

4
ABC_PRIORITY

Prioritizza articoli A→B→C in base al valore di magazzino.

5
ZONE_BASED

Seleziona articoli per zona fisica, ottimizzando il percorso dell'operatore (location-clustering.ts).

6
RANDOM_SAMPLING

Campionamento stratificato casuale con Fisher-Yates shuffle, configurable %.

7
HIGH_ROTATION

Solo articoli ad alta rotazione (classe HIGH).

8
EXCEPTION_BASED

Solo articoli con stock negativo, discrepanze ripetute, o ad alto valore mai contato.

9
DailyCountPlan.generatedItems (JSON)

Salva array di item ID ordinati per score. Algorithm config salvata per audit.

10
POST /api/inventory/daily-plans/[id]/approve

Approva il piano: crea InventorySession + InventoryCheck assegnati. Opzione autoStart.

Copertura API — 42 Route

EndpointMetodiPermesso
/api/inventory/alertsGETINVENTORY_REPORT
/api/inventory/alerts/[id]/dismissPOSTINVENTORY_REPORT
/api/inventory/algorithmsGETINVENTORY_MANAGE
/api/inventory/checksGETINVENTORY_CHECK
/api/inventory/checks/[id]GET, PUTINVENTORY_CHECK
/api/inventory/checks/[id]/itemsPATCHINVENTORY_CHECK
/api/inventory/correctionsGETINVENTORY_MANAGE
/api/inventory/corrections/[id]GET, PUTINVENTORY_MANAGE
/api/inventory/corrections/batchPATCHINVENTORY_MANAGE
/api/inventory/corrections/summaryGETINVENTORY_MANAGE
/api/inventory/daily-plansGETINVENTORY_MANAGE
/api/inventory/daily-plans/generatePOSTINVENTORY_MANAGE
/api/inventory/daily-plans/generate-bulkPOSTINVENTORY_MANAGE
/api/inventory/daily-plans/todayGETINVENTORY_MANAGE
/api/inventory/daily-plans/[id]GET, PUT, DELETEINVENTORY_MANAGE
/api/inventory/daily-plans/[id]/approvePOSTINVENTORY_MANAGE
/api/inventory/daily-plans/[id]/skipPOSTINVENTORY_MANAGE
/api/inventory/dashboardGETINVENTORY_REPORT
/api/inventory/fiscal-yearsGET, POSTINVENTORY_MANAGE
/api/inventory/fiscal-years/[id]GET, PUT, DELETEINVENTORY_MANAGE
/api/inventory/importPOSTINVENTORY_MANAGE
/api/inventory/my-progressGETINVENTORY_CHECK
/api/inventory/my-tasksGETINVENTORY_CHECK
/api/inventory/reportsGETINVENTORY_REPORT
/api/inventory/reports/[id]GETINVENTORY_REPORT
/api/inventory/reports/[id]/excelGETINVENTORY_REPORT
/api/inventory/scheduleGET, POST, PUT, DELETEINVENTORY_MANAGE
/api/inventory/sessionsGET, POSTINVENTORY_MANAGE
/api/inventory/sessions/[id]GET, PUT, DELETEINVENTORY_MANAGE
/api/inventory/sessions/[id]/startPOSTINVENTORY_MANAGE
/api/inventory/sessions/[id]/completePOSTINVENTORY_MANAGE
/api/inventory/stock-snapshotsGET, POSTINVENTORY_MANAGE
/api/inventory/stock-snapshots/latestGETINVENTORY_MANAGE
/api/inventory/tranchesGETINVENTORY_MANAGE
/api/inventory/tranches/[id]GET, PUT, DELETEINVENTORY_MANAGE
/api/inventory/tranches/[id]/startPOSTINVENTORY_MANAGE
/api/inventory/tranches/[id]/completePOSTINVENTORY_MANAGE
/api/inventory/tranches/[id]/generatePOSTINVENTORY_MANAGE
/api/inventory/tranches/[id]/mandatory-itemsGET, PATCHINVENTORY_MANAGE
/api/inventory/year-end/generatePOSTINVENTORY_MANAGE
/api/inventory/year-end/startPOSTINVENTORY_MANAGE

Correzioni Applicate (Aprile 2026)

Categoria: Frontend / Dati

inventory/page.tsx

8 field mismatch tra frontend e API dashboard: positionPercent, valuePercent, workingDaysRemaining, stockValueTrend, problematicItems → oggetti annidati (positionProgress.percentage, workingDays.remaining, stockTrend, topProblematicItems). Progress ring sempre a 0%, grafici vuoti.

inventory/corrections/page.tsx

Colonna 'Quantità Contata' leggeva item.countedQty inesistente nel modello DiscrepancyCorrection.

api/inventory/my-progress/route.ts

valuePercent hardcodato a 0 — stub non implementato. Barra progresso operatori mobile sempre a 0%.

Categoria: Sicurezza — IDOR e Scope

api/inventory/corrections/route.ts + summary/route.ts

Scope overwrite: buildRoleScope() costruisce where.inventoryItem per RBAC, poi warehouseId sovrascriveva la stessa chiave azzerando il filtro di ruolo. Un BRAND_ADMIN poteva vedere correzioni di altri brand.

api/inventory/corrections/batch/route.ts

PATCH batch eseguiva updateMany({ where: { id: { in: ids } } }) senza verificare che le correzioni appartengano al warehouse dell'utente. IDOR: un operatore poteva modificare correzioni di altri warehouse.

api/inventory/alerts/[id]/dismiss/route.ts

findUnique({ where: { id } }) senza join al warehouse. Qualsiasi utente autenticato poteva dismissare alert di altri warehouse.

api/inventory/reports/[id]/route.ts + excel/route.ts

findUnique non verificava ownership. Un utente poteva leggere o esportare in Excel report di warehouse non accessibili.

api/inventory/sessions/[id]/route.ts (GET, PUT, DELETE)

Tutte le operazioni su sessione per ID usavano findUnique senza verifica warehouse. Possibile accesso cross-tenant.

api/inventory/fiscal-years/[id]/route.ts + tranches/[id]/*.ts

Stessa vulnerabilità IDOR su fiscal years, tranches (GET, PUT, start, complete, generate, mandatory-items).

Categoria: Performance
OTTIMIZZAZIONE

api/inventory/dashboard/route.ts

generateAlerts() era chiamato con await bloccando la risposta dashboard di 200-500ms anche quando non necessario.

OTTIMIZZAZIONE

lib/inventory/alert-engine.ts

N+1 query: per ogni alert generato si eseguiva findFirst + create separati (fino a 30+ query sequenziali per warehouse attivi).

OTTIMIZZAZIONE

lib/inventory/dashboard-stats.ts

Sequenziale: count totale poi count contati poi findMany di tutti gli item per sommare unitPrice×expectedQty in JS (O(n) in memoria).

OTTIMIZZAZIONE

lib/inventory/rotation-calculator.ts

O(n×m) inner loop: per ogni item di tutti i warehouse veniva chiamato checkCounts.find() — scansione lineare dell'array ad ogni iterazione.

OTTIMIZZAZIONE

prisma/schema.prisma — InventoryCheckItem

La query più frequente (discrepancy trend, alert engine, rotation calculator) filtra su inventoryItemId + checkedAt ma non esisteva un indice composito.

Categoria: UX

inventory/corrections/page.tsx

handleStatusChange non mostrava alcun feedback visivo: successo e errore erano silenziosi. L'utente non sapeva se l'operazione era andata a buon fine.

Codice Rimosso (Dead Code)

  • src/components/inventory/ProgressRing.tsx — componente SVG definito ma mai importato da nessuna pagina. La dashboard usa già un'implementazione inline equivalente.
  • src/components/inventory/AnnualProgressBar.tsx — barra progresso annuale definita ma mai importata. Nessuna pagina la referenzia.

Limitazioni Note Residue

Servid v1.0 — Modulo Inventario — Analisi tecnica generata Aprile 2026 · servid.condoe.it