metallkart-erp/docs/CDC.md
louis 9524dc9516 docs: update CDC session 37 complete (37A-37E)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 18:46:44 +03:00

372 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# МеталлКарт ERP — Document de continuité Session 31
## Date: 24 mars 2026
---
## 1. RÈGLES INDISPENSABLES DE TRAVAIL
### Architecture agentique
- **claude.ai** = ARCHITECTE + PROMPTEUR uniquement. NE JAMAIS piloter le VPS commande par commande.
- Si tenté de lancer des commandes complexes → STOP → écrire une spec → send_task.sh
- VPS Hostinger Ubuntu 24.04, IP **76.13.55.81**, SSH: `ssh root@76.13.55.81`
### Pattern d'envoi des specs (VALIDÉ, NE PAS IMPROVISER)
```
1. bash_tool: encoder la spec en base64
2. CLAUDE_TERMINAL (n8n workflow Y5kkG8IIFTxSSlDs):
- Heredoc B64END pour écrire le b64 dans /tmp/sb.txt
- node -e POST vers HOST_TERMINAL (172.17.0.1:9999) pour décoder et écrire /tmp/spec_XXX.md
3. CLAUDE_TERMINAL:
- node -e POST vers HOST_TERMINAL: launch script qui lit /tmp/spec_XXX.md, encode b64, appelle send_task.sh
4. Vérifier les logs: via HOST_TERMINAL tail /opt/erp/logs/spec_XXX_*.log
```
**Secrets:**
- CLAUDE_TERMINAL: `mk_terminal_2026`
- HOST_TERMINAL: `mk_host_2026`
### Règles absolues
- Ne jamais sleep >60s dans CLAUDE_TERMINAL (timeout)
- curl absent du container n8n → toujours node http.request()
- Ne jamais mettre du b64 en argument shell ni dans JS template literals
- /tmp dans CLAUDE_TERMINAL = container n8n, PAS le host VPS
- CLAUDE_TERMINAL a un timeout task runner n8n, POST HOST_TERMINAL pour commandes longues
- prisma migrate dev IMPOSSIBLE en non-interactif → db push
- EADDRINUSE port 3001 → fuser -k 3001/tcp
- Toujours utiliser db push (pas migrate dev) après modification schema
---
## 2. ÉTAT DU PROJET — Session 27
### Stack
- Backend : Fastify + Prisma + PostgreSQL 16 + TypeScript, port 3001
- Frontend : Vite 8 + React 19 + Ant Design 6 + TypeScript, port 5173 (nginx 5180)
- Repo : /opt/erp/metallkart-erp/
- Services systemd : erp-backend.service, erp-frontend.service
- PG staging : 172.19.0.5, user metallkart, DB erp_staging
### Modules backend complets
- auth (JWT, RBAC 15 rôles, seed 15 users)
- suppliers (CRUD, INN, pagination)
- products (CRUD, SKU, relations)
- orders (state machine XState 10 statuts, ref auto, transitions RBAC)
- revisions (workflow conditionnel, double approbation)
- photos (upload multipart, storage abstraction)
- passport (agrégation complète commande JSON)
- dashboard (summary, alertes, vue financière)
- payment-requests (XState, 4 catégories, budget checks)
- estimates (workflow 2 validateurs, versioning, import Excel)
- contract-tracking (XState relances, escalade)
- supplier-database (CRUD enrichi, tags, contacts)
- purchases (PR CRUD, génération auto smeta, consolidé)
- steel-references (52 profils, import bulk)
- tenders (6 statuts, offres, compare, award multi-fournisseur)
- purchase-orders (from-tender, TLT, QR, email, PDF)
- budget (double validation FIN+OPS, blocage PO)
- financial (suivi coûts, FinancialTracking, ExpenseCode, MonthlyBudget)
- cashflow (ДДС, RecurringPayment, BankStatement, forecast, export Excel)
- profitability (marge, hook cashflow→tracking, export)
- notifications (centralisées, NotificationHelper)
- tasks (centre de tâches unifié, escalade auto)
- audit (journal, stats, export CSV)
- admin (users CRUD, config système, health check)
- email (SMTP+IMAP, cron inbox poll)
- consultation (drafts KP, envoi email groupé)
- onec (import 1С OData, sync contractors/contracts/financial)
- smeta-revision (comparison engine, validate+apply, AdditionalCost)
- clients (CRUD, stats)
- document-files (upload, versioning, checksum)
### Frontend complet
- Документооборот : 5 onglets (Оплаты, Сметы, Контракты, Поставщики, Заказчики)
- Заказы : liste + détail 5 onglets (Général, Ревизии, Фото, Паспорт, Ревизии смет)
- Закупки : 5 onglets (Потребности, Консультации, Заказы поставщикам, Бюджет, Планирование)
- Финансы : 2 onglets (Календарь ДДС, Рентабельность)
- Уведомления : 2 onglets (Уведомления, Задачи)
- Администрирование : 3 onglets (Пользователи, Журнал аудита, Настройки)
- Настройки : Category-Tag Configurator
---
## 3. NOUVEAU WORKFLOW ACHATS (référence)
Flux complet :
1. **Smeta** : créer → import Excel → versions/révisions → soumettre → valider (2 validateurs)
2. **Lancement** : commande LAUNCHED → PR auto-générées depuis specData
3. **Consultations** : matrice PR×Fournisseurs → envoi email → réponses → analyse AI
4. **Tenders** : compare matriciel → award ligne par ligne multi-fournisseur → PO DRAFT
5. **Budget** : vue consolidée → double validation Максим (FIN) + Никита (OPS)
6. **PO** : confirmation → email PDF+QR → expédition → réception QR scan
---
## 4. INFRASTRUCTURE
| Composant | Détail |
|-----------|--------|
| VPS | Hostinger Ubuntu 24.04, 76.13.55.81 |
| PostgreSQL | 16, staging 172.19.0.5 |
| n8n | container n8n-n8n-1, SQLite |
| SMTP | purchase@metdesigntver.ru, beget.com:465 |
| IMAP | purchase@metdesigntver.ru, beget.com:993 |
| GitHub | cifemvostok-png/metallkart-erp (privé) |
| Пугина | PG 9.6, 85.91.121.250:5432 |
| 1С OData | scloud.ru (désactivé session 18) |
---
## 5. HISTORIQUE DES SESSIONS
### Sessions 1-7 (mars 2026)
Infrastructure, modules backend core (auth, suppliers, products, orders, payment-requests, estimates, contract-tracking, supplier-database, purchases, tenders, purchase-orders, financial, cashflow, profitability, notifications, tasks, audit, admin).
### Session 8
Frontend scaffolding (Vite+React+AntDesign), Документооборот 4 tabs, Заказы pages.
### Sessions 10-12
Phase 1.5 (filtres, ContractAttachment→APPENDIX, clients, archive PR), EstimatesTab enrichi, ДДС dashboard v2, bugfixes documents.
### Sessions 13-16
Smeta import Excel (parser dynamique, 13 MaterialCategory), Document Files module, frontend finance+notifications+admin, Phase 1.5B/C (traductions, améliorations frontend).
### Sessions 17-18
Email service SMTP+IMAP, consultation fournisseurs, QR codes PO, Planning Gantt, configurable scoring, 2-validator estimate workflow, bugfixes critiques.
### Sessions 19-20
Consultation matrice PR×Fournisseurs, 1C OData import, tender cleanup+offer lines, compare modal matriciel, award lines multi-fournisseur, offer analyzer AI, tender responses multipart.
### Sessions 21-22
Editable drawers, batch confirm, partial award, TLT intégration (auto-PO, exclude tenders), category-tag configurator, tender dispatch fix, visual validation tool, 18+ specs corrections/améliorations.
### Sessions 23-24
TLT schema+auto-PO+frontend, data cleanup, SPEC_DETAIL_CATEGORIES, smeta revision engine (comparison+validate+apply+AdditionalCost), PR cascade cleanup, order delete/archive.
### Sessions 25-26
SmetaLot prévisionnel (créé puis supprimé — lotissement déplacé au niveau PO), refonte lotissement backend/frontend, test infrastructure (E2E+Playwright), dropdown/expand fixes.
### Session 27 (22/03/2026)
#### 27A — Infrastructure Consolidation
- CLAUDE.md : 4 nouvelles sections (tests obligatoires, validation frontend, skills, workflow achats)
- dev_task.sh : --allowedTools étendu avec 5 outils MCP Playwright
- Skills nettoyées : suppression tailwindcss, redis, mcp-server-guide (15 restantes)
- Test E2E workflow : 18/18 passés (auth→client→order→estimate→submit→approve→launch→PRs(9)→tender→dashboard)
- tests/test_workflow_e2e.sh créé
#### 27B — Purchase Orders API Routes
- Nouveaux fichiers : src/modules/purchase-orders/po-pdf.service.ts
- Routes CRUD : POST/DELETE /purchase-orders (avec auto orderCode PO-YYYYMMDD-NNN, auto totalAmount)
- Routes workflow : confirm (QR), send-email (PDF+QR attachés), mark-shipped, receive, cancel
- Route génération : POST /purchase-orders/generate-from-tender/:tenderId (groupé par supplier)
- Route PDF : GET /purchase-orders/:id/pdf (pdfkit avec header, lignes, QR, signature)
- SMTP configuré : SMTP_FROM ajouté dans .env
- Dépendances : nodemailer, pdfkit, qrcode
#### 27C — Budget Consolidé + Double Validation
- Nouveau modèle Prisma : BudgetValidation (@@unique orderId, enum PENDING/FIN_APPROVED/TECH_APPROVED/FULLY_APPROVED/REJECTED)
- Relations ajoutées : Order.budgetValidation, User.budgetFinValidations, User.budgetTechValidations
- Nouveaux fichiers : src/modules/budget/budget.service.ts, budget.routes.ts
- 6 routes /api/v1/budget : GET order/:orderId (vue consolidée), GET dashboard (KPIs), POST validate-financial, POST validate-technical, POST reject, POST reset
- BudgetService : calculs automatiques totalEstimated (smeta), totalAwarded (TenderLineAward), totalPO (PurchaseOrder non CANCELLED), variance, bySupplier, byCategory
- Guard PO confirm : vérifie FULLY_APPROVED avant DRAFT→CONFIRMED (sauf clientOrderId null)
- Rôles : DIRECTION_FIN pour financier, DIRECTION_OPS pour technique, ADMIN pour reset
#### 27D — Frontend PO + Budget Tabs
- PurchaseOrdersTab : modal création (supplier, lignes éditables, auto-total, DatePicker), génération depuis tender AWARDED, suppression DRAFT, PDF download, actions contextuelles par status
- BudgetTab (280 lignes) : 4 KPI cards (estimé, PO, variance colorée, validé count), tableau commandes, drawer détail (bySupplier, byCategory, validation RBAC)
- Nouveaux fichiers : frontend/src/api/budget.ts, frontend/src/pages/purchases/BudgetTab.tsx
- Modifiés : PurchaseOrdersTab.tsx, PurchasesPage.tsx, App.tsx, types/purchases.ts, api/purchaseOrders.ts
- Route /purchases/budget ajoutée
#### 27E — MEMORY.md Mémoire Étendue
- Créé /opt/erp/metallkart-erp/MEMORY.md : contexte complet projet (équipe, infra, credentials, bots TG, pipeline, règles métier smeta, n8n gotchas, skills, Пугина, historique sessions, DNS)
- CLAUDE.md : section "Mémoire étendue" ajoutée en référence
- Solution au problème de limite 30 mémoires claude.ai
#### Règles métier documentées (session 27)
- Smeta 3 onglets : Техданные (fabrication), Расчет (chiffrage/budget), СПЕЦИФИКАЦИЯ (plan achats)
- Пром-Лазер = placeholder historique → toujours ТЛТ pour Лазер et Труборез
- Services = chaque fournisseur différent
- Сетка : 2 modes (achat fini "комплект сетки" OU проволока + сварка сетки sous-traitée)
- Техданные exclut services de transformation (galvanisation, traitement thermique)
#### État technique post-session 27
- ~200+ routes API, 1000+ tests (18 e2e + 6 Playwright), tous verts
- Modules complets : Orders, Clients, Documents, Estimates, PurchaseRequirements, Tenders, TenderOffers, PurchaseOrders, Budget, ДДС, Profitability, Notifications, Audit
- Frontend : 6+ onglets page Achats (Сметы, Консультации, Заказы поставщикам, Бюджет)
- Mémoire : claude.ai 20/30 + MEMORY.md sur VPS
### Session 29 — Sync PRs on Smeta Revision (24/03/2026)
#### 29A — Backend syncPRsOnRevision
- Hook dans POST `/revision/:revId/apply` (estimates.routes.ts L470+)
- `SmetaRevisionService.syncPRsOnRevision(revisionId)` dans smeta-revision.service.ts
- Pour chaque decision APPLY: flag le PR via `impactedPRIds` ou description matching → revisionAlert=true + revisionNote
- Pour chaque decision ADDITIONAL_COST (position ORDERED):
- Si delta > 0: crée nouveau PR DRAFT (quantity = delta × order.quantity, estimatedPrice = unitPrice)
- Si delta < 0: flag SURPLUS sur PR existant (note avec fournisseur + PO number)
- Notification ACHETEUR via NotificationHelper.notifyRole si flagged > 0
- Champs Prisma ajoutés: revisionAlert, revisionNote, revisionAckBy, revisionAckAt sur PurchaseRequirement
- Routes: POST /purchase-requirements/:id/ack-revision, POST /purchase-requirements/ack-revision-bulk
#### 29B — Frontend tag ПОМЕНЯТЬ + ack-revision
- Types purchases.ts: revisionAlert, revisionNote, revisionAckBy, revisionAckAt
- API purchases.ts: ackRevision(id), ackRevisionBulk(orderId)
- PurchaseRequirementsTab.tsx: tag ⚠ ПОМЕНЯТЬ + Tooltip revisionNote + bouton Обработано + row highlight #f9f0ff + bulk ack button
#### 29C — Corrections
- Fix version collision: MAX(version)+1 au lieu de currentSmeta.version+1 (estimates.routes.ts L357)
- PR DRAFT pour delta ORDERED dans syncPRsOnRevision (action ADDITIONAL_COST)
- Historique révisions: déjà implémenté en 24J (bouton Просмотр diff)
#### 29D — UX Notifications + Tasks
- Modal notification: clic sur message → Modal avec texte complet (whiteSpace: pre-wrap)
- Filtre rôle dans les tâches: Select "Фильтр по роли" + cartes cliquables
#### 29E — Fix quantité delta PR
- quantity = deltaQtyPerUnit × order.quantity (quantité totale)
- estimatedPrice = unitPrice (prix unitaire inchangé)
- budgetAmount = deltaQtyTotal × unitPrice
- Arrondi toFixed(4) pour quantités, toFixed(2) pour prix
- Nettoyage 4 PR orphelins
#### 29F — Alerte surplus (diminution quantité)
- Quand delta < 0 sur position ORDERED: flag PR existant avec revisionAlert + note SURPLUS
- Note inclut: fournisseur, n° PO, surplus total, coût
- Résolu via lineAwards purchaseOrder supplier
### Session 30 — Revision impacts + budget fix + cancel revision (24/03/2026)
#### 30A — API revision-impact
- GET /orders/:id/revision-impact agrégation impacts revision achats par commande
- Types SURPLUS/RACHAT/MODIFIED, totaux par type, statut acquittement
#### 30B — Frontend onglet Изменения Закупок
- 3 cartes stats SURPLUS/RACHAT/MODIFIED, tableau impacts avec ack individuel+bulk
- Badge pendingCount sur onglet, visible post-AWAITING_ESTIMATE
#### 30C — Budget fix quantity
- totalEstimated×order.quantity dans computeTotals+getDashboard
- variancePercent Decimal(10,2) overflow fix
#### 30D — Cancel revision
- DELETE /estimates/revisions/:id annule REV_PENDING+supprime newSmeta cascade
- Bouton Отменить ревизию frontend, historique revisions sorti du Collapse en Card visible
#### 30E — Refonte SmetaRevisionTab
- Fusionné 2 sections (Доп. затраты Card + История ревизий Timeline) en 1 Table AntD 8 colonnes
- Colonnes: Версия, Статус, Дата, Автор, Изменений, Дельта бюджета, Доп. затраты, Действия
- Expandable rows pour доп. затраты par revision, orphan costs en bas
### Session 31 — PurchaseLots, Factures, Conditions paiement (24/03/2026)
#### TLT-C1a — Backend PurchaseLots + Factures + Conditions paiement
- 2 enums: PaymentType (PREPAYMENT_FULL/INSTALLMENT/POST_DELIVERY), InvoiceStatus (PENDING_VALIDATION/APPROVED_AWAITING_PAYMENT/PARTIALLY_PAID/PAID)
- 3 modèles: POInvoice, POPaymentSchedule, POInstallment
- `createLotsForPO` helper intégré dans 4 méthodes création PO (createManual, generateFromTender, createFromTender, createTlt)
- 15+ routes: lots (GET /:poId/lots, POST /:poId/lots/split), invoices (POST multipart, validate, trigger-payment, confirm-payment, GET file, DELETE), payment schedule (PUT, GET), backfill-lots
- 3 guards CONFIRM: facture obligatoire + conditions paiement + dates lots (skip TLT)
- Facture validée auto-crée PaymentRequest code PAY- statut APPROVED
- Cycle: APPROVED trigger-payment AWAITING_PAYMENT confirm-payment PAID
- Prefix PAY- (ex PR-) pour nouveaux payment requests
- PO_INCLUDE enrichi: lots, invoices, paymentSchedule
#### TLT-C1b-1 — Frontend Drawer PO enrichi
- 6 types: POLotItem, POInvoice, InvoiceStatus, PaymentType, POInstallment, POPaymentSchedule
- 11 API functions dans purchaseOrders.ts
- Drawer PO: 3 nouvelles sections + 3 modals:
- Лоты: table + modal split (qty + DatePicker)
- Счёт-фактура: table Tags colorés (jaune/bleu/rouge/violet/vert + overdue), upload Dragger, RBAC actions
- Условия оплаты: Radio 3 types, installments éditables DRAFT, read-only sinon, Alert récap
- Code couleur: PENDING_VALIDATION=jaune, APPROVED_AWAITING_PAYMENT=bleu (OVERDUE=rouge si dueDate<now), PARTIALLY_PAID=violet, PAID=vert
#### SEED-31 — Script seed données test
- `tests/seed-test-data.ts` script idempotent pour peupler la base
- 3 POs (PO-2603-010 CONFIRMED, PO-2603-011 DRAFT, PO-2603-012 DRAFT)
- Fournisseurs, PRs, tender AWARDED, lots, payment schedule
#### État technique post-session 31
- ~220+ routes API, E2E 18/18, Playwright 6/6
- Nouveaux modèles: POInvoice, POPaymentSchedule, POInstallment
- PurchaseLots auto-créés à chaque PO
- Script seed: `npx tsx tests/seed-test-data.ts`
### Session 32 — PO Workflow SENT, Onglet Счета, Steel Conversion, Cashflow PO, Доп затраты auto (25/03/2026)
#### 32A — PO Workflow SENT + Lots Overflow Fix
- Ajout statut SENT à PurchaseOrderStatus enum (DRAFTCONFIRMEDSENTSHIPPEDRECEIVED)
- PurchaseLot.quantity élargi Decimal(10,3) Decimal(15,2) pour supporter montants >10M ₽
- sendPOEmail() → transition CONFIRMED→SENT après envoi email réussi
- ship() n'accepte que SENT (plus CONFIRMED directement)
- Frontend: boutons contextuels par statut dans liste et drawer PO
- Migration SQL: UPDATE purchase_orders SET status = 'SENT' WHERE status = 'CONFIRMED' AND email_sent_at IS NOT NULL
#### TLT-C1b-2 — Onglet Счета (ex-Оплаты)
- Onglet Документооборот renommé "Оплаты" → "Счета"
- Code couleur fond lignes par statut (jaune PENDING, bleu APPROVED, rouge REJECTED, vert PAID, violet INFO_REQUESTED)
- Colonne date paiement: vert=réelle (paidAt), rouge=prévisionnelle (dueDate)
- Bouton "Файл" pour consulter facture fournisseur (POInvoice file download)
- Drawer détail enrichi: section infos facture + conditions paiement (via payment-schedule API)
- Backend: PaymentRequest list enrichi avec relation poInvoice
- Types: POInvoiceSummary, InvoiceStatus ajoutés
#### 32B — Offer Analyzer Refonte + Steel References
- Seed 51 profils acier dans steel_references (SQUARE_TUBE, RECT_TUBE, ROUND_TUBE, ANGLE, CHANNEL, SHEET, FLAT_BAR, ROUND_BAR) avec poids théoriques ГОСТ
- SteelConversionService: findWeightPerMeter (regex cyrillique), metersToTonnes, tonnesToMeters, pricePerTonneToPerMeter, removeVAT/addVAT
- Route GET /api/v1/steel-references/convert
- Offer analyzer refonte: nouveau prompt AI extraction données brutes (supplierQuantity, supplierUnit, supplierUnitPrice, vatIncluded, vatRate)
- Post-processing déterministe normalizeAnalysis(): conversion unités via SteelConversion, retrait НДС, détection offre partielle
- rawSupplierData conservé pour audit, transportCost ajouté
#### 32C — Cashflow Prévisionnel PO
- Forecast enrichi avec échéances PO (installments non payés des PO CONFIRMED/SENT/SHIPPED)
- Champ poExpenses par semaine dans le forecast
- KPI poCommitments: totalUnpaid, poCount, installmentsDue7d, overdueInstallments
- Frontend: 5ème carte KPI "Обязательства по закупкам" dans CashflowTab
- Live: 2 PO actifs, 63.6M total non payé
#### 32D — Calcul auto Сумма ДЗ
- Bannière orange temps réel dans SmetaRevisionTab quand ADDITIONAL_COST sélectionné
- Affiche: nombre positions + montant total ₽ + impact budget
- Visible uniquement pendant révision REV_PENDING active
#### État technique post-session 32
- ~225+ routes API, 1000+ tests (18 e2e + 6 Playwright), tous verts
- 5 specs livrées, 0 échec
- steel_references: 51 profils seedés
- PurchaseOrderStatus: 7 valeurs (DRAFT, CONFIRMED, SENT, SHIPPED, RECEIVED, PARTIAL, CANCELLED)
- PurchaseLot.quantity: Decimal(15,2)
---
## 6. BUGS CONNUS NON RÉSOLUS
- Validation toasts parfois apparaissent sur Закупки (à investiguer)
- Puppeteer screenshot multi-page auth loss (contournement: screenshot-api.js)
- 1С sync désactivé (routes 503) — données nettoyées session 18
### Session 33-34 (06-08/04/2026)
Audit 33A (PDF OK, workflow OK, cashflow OK, Gantt OK). Session 34: 22 items (18 fixes + 4 features). Fixes: PDF blob, cashflow, quantités PR, tender async, doublons, close() libère PR, updateSuppliers, Zod, ADMIN bypass, tags, Gantt, montants, PR résiduelle, lots min 1. Features: lien tender PR, Podtverdit vse, filtre commande Tendery, arkhivirovat.
### Session 35 (08-09/04/2026)
15 specs. Workflow paiement refondu PENDING→APPROVED→PAID. Fixes: git push PAT, CashflowTab off-by-one, award compare, revertToSent, UI drawer PO, navigation tab, PR ORDERED, fournisseurs filtrés, TLT renommé. Features: recherche tenders, archivage PO, installments liés, toggle Инициировать/Отозвать, bouton ТЛТ, dates installments éditables.
### Session 36 (09-10/04/2026)
36A: Comparaison révision smeta specData (compareSpecItems, LASER_TUBE/TUBE_BENDING). 36B: Ближайшие платежи vraies données. 36C: Revert PO CONFIRMED→DRAFT. 36D: PaymentRemindersService cron J-3/J-1/J-0/overdue, idempotent. 36E: Lotissement PO par ligne (PurchaseLotLine, validation 100%). 36E-FIX: Backfill items→PurchaseOrderLine. 36F: LotSplitModal plein écran matrice ligne×lot. 36G: Fix révision smeta compare dernière version. 36H: Navigation cashflow + highlight blink-red + filtres statut + tri Просроченные↑ + colonne Просрочка. Fix lot split deliveryDate + auto-remplissage supplier. Backfill PurchaseOrderLine.material (48 lignes fixées).
### Session 37 (10/04/2026)
Fix budget byCategory (PurchaseOrderLine au lieu de PR.budgetAmount null). 37A: Refonte Настройки multi-onglets (Профиль/Уведомления/Категории). Modèle UserNotificationPreference (7 catégories, defaults par rôle). Routes GET/PUT /notification-preferences. NotificationHelper filtrage par catégorie (shouldNotifyInApp). PaymentRemindersService category PAYMENT_DUE. Frontend ProfileTab + NotificationsTab (Switch inApp, Email/Telegram disabled). 37B: Budget drawer enrichi (totaux + 3 colonnes Бюджет/Факт/Разница). 37C: Catégories notification sur tous notifyRole existants (estimates, tenders, tasks) + lot order date reminders (checkLotOrderDates). 37D: notifyByCategory remplace notifyRole dans reminders (ADMIN recoit les notifs) + budgetAmount peuple a la creation PR. 37E: Budget par categorie depuis smeta specData (materiaux) + SmetaLine (services via SERVICE_TO_CATEGORY) — LASER_FLAT/LASER_TUBE/ROD_BENDING maintenant avec budget.
---
## 7. PROCHAINES ÉTAPES
- [ ] [P1] Cashflow prévisionnel (installments + PO confirmés + factures clients)
- [ ] [P1] Refonte Планирование/Gantt
- [ ] [P2] Erreurs TS backend (.test.ts)
- [ ] invoices (facturation client)
- [ ] reports (rapports financiers)
- [ ] Intégration Пугина (vues SQL lecture seule)