metallkart-erp/CDC.md
louis 27c36375b1 feat: SPEC-37A settings multi-tabs + notification preferences + fix budget byCategory
- Fix budget byCategory: use PurchaseOrderLine (qty×price) instead of PR.budgetAmount (null)
- UserNotificationPreference model (7 categories, role defaults, @@unique userId+category)
- GET/PUT /notification-preferences routes (upsert transactional)
- NotificationHelper: shouldNotifyInApp() filters by category before creating
- PaymentRemindersService: category PAYMENT_DUE on notifyRole calls
- Frontend: SettingsPage 3 tabs (Profile/Notifications/Categories)
- ProfileTab, NotificationsTab (Switch inApp, Email/Telegram disabled)
- CDC updated session 37

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 17:32:40 +03:00

330 lines
20 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 27
## Date: 22 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
---
## 6. BUGS CONNUS NON RÉSOLUS
### Session 30 — Revision Impact Report + Budget Fix (24/03/2026)
#### 30A — Backend Revision Impact API
- Nouveau fichier: `src/modules/purchases/revision-impact.service.ts` `RevisionImpactService`
- Route: `GET /orders/:id/revision-impact` (RBAC: ADMIN, DIRECTION_FIN, DIRECTION_OPS, ACHETEUR, ADM_PRODUCTION)
- Agrège PRs impactés par révisions: types SURPLUS/RACHAT/MODIFIED, totals, ack status
- Données via sourceType='SMETA_REVISION' + revisionAlert=true
#### 30B — Frontend Onglet "Изменения Закупок"
- Nouveau fichier: `frontend/src/api/revisionImpact.ts`
- Nouveau fichier: `frontend/src/pages/orders/tabs/RevisionImpactTab.tsx` (~200 lignes)
- 6ème onglet dans OrderDetailPage avec Badge pending count
- 3 cartes stats (SURPLUS rouge, RACHAT vert, MODIFIED jaune)
- Tableau 9 colonnes + ack individuel/bulk + row coloring + Tooltip revisionNote
- Visible uniquement pour commandes post-AWAITING_ESTIMATE
#### 30C — Fix Budget Computation
- `budget.service.ts`: `computeTotals()` et `getDashboard()` totalEstimated multiplié par order.quantity
- `schema.prisma`: variancePercent élargi Decimal(5,2) Decimal(10,2)
- Résultat: order 50 totalEstimated=2 512 171 (×170), variancePercent=57.15% (plus d'overflow)
#### 30D — Cancel Pending Revision + Visible History
- Backend: route `DELETE /estimates/revisions/:revId` annule REV_PENDING (transaction: delete decisions, costs, revision, new smeta)
- Frontend: bouton "Отменить ревизию" avec Popconfirm dans SmetaRevisionTab
- Historique: Collapse remplacé par Card toujours visible
- API: `cancelRevision()` ajoutée dans smetaRevisions.ts
#### État technique post-session 30
- ~205+ routes API, 1000+ tests (18 e2e + 6 Playwright), tous verts
- Nouveaux fichiers: revision-impact.service.ts, revisionImpact.ts, RevisionImpactTab.tsx
- Onglet OrderDetailPage: 6 tabs (Информация, Ревизии, Фото, Ревизия сметы, Паспорт заказа, Изменения Закупок)
- 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 31 — PurchaseLots, Factures, Conditions paiement (24/03/2026)
#### TLT-C1a — Backend PurchaseLots + Factures + Conditions paiement
- POInvoice, POPaymentSchedule, POInstallment models
- createLotsForPO helper, 15+ routes, confirm guards, PaymentRequest auto-creation PAY-
#### TLT-C1b-1 — Frontend Drawer PO enrichi
- 3 sections: Лоты, Счёт-фактура, Условия оплаты
- 11 API functions, 6 types, RBAC actions
### Session 32 — PO Workflow SENT, Onglet Счета, Steel Conversion, Cashflow PO, Доп затраты auto (25/03/2026)
#### 32A — PO Workflow SENT + Lots Overflow Fix
- PurchaseOrderStatus +SENT, PurchaseLot.quantity Decimal(15,2), sendPOEmailSENT transition
#### TLT-C1b-2 — Onglet Счета (ex-Оплаты)
- Code couleur lignes par statut, date paiement vert/rouge, bouton Файл facture, drawer enrichi
#### 32B — Offer Analyzer Refonte + Steel References
- 51 profils acier seed, SteelConversionService тм, offer analyzer refonte raw+deterministic post-processing
#### 32C — Cashflow Prévisionnel PO
- Forecast PO installments, KPI poCommitments, 5ème carte KPI frontend
#### 32D — Calcul auto Сумма ДЗ
- Bannière orange temps réel ADDITIONAL_COST dans SmetaRevisionTab
### Session 34 (07-08/04/2026)
Dev local PC validé. 22 items livrés (18 fixes + 4 features). Fixes: PDF blob, cashflow, P0 quantités PR, tender async, PR doublons, close() libère PR, updateSuppliers, Zod Predoplata/Postoplata, ADMIN bypass, tags alignés, Gantt barres, montants transhi, PR résiduelle award partiel, lots min 1, doublon priorité. Features: lien tender dans statut PR, Podtverdit vse groupe, filtre commande Tendery, arkhivirovat zakrytye. Pipeline WIN_TERMINAL testé.
### Session 35 (08-09/04/2026)
15 specs livrées, workflow paiement refondu. Fixes (8): git push 403 PAT, CashflowTab off-by-one, award global supprimécompare, revertToSent COMPARINGSENT, 4 fixes UI drawer PO, navigation tab PO depuis Счета, PR ORDERED après award, fournisseurs tender filtrés par dispatches, TLT renommé ООО "ТЛТ". Features (5): recherche textuelle tenders serveur-side, archivage PO (CANCELLED auto + RECEIVED manuel + bulk), installments liés aux paiements (purchaseOrderId, paymentRequestId, cascade markPaid), refonte workflow paiement PENDINGAPPROVEDPAID avec toggle Инициировать/Отозвать, bouton "Заказ ТЛТ" sur LASER_FLAT/LASER_TUBE/PIPE_CUT. Améliorations: dates installments éditables (DatePicker inline, dueDate propagé sur PaymentRequest), purge données ERP local.
### Session 36 (09-10/04/2026) — complète
SPEC-36A: Comparaison révision smeta descend dans specData (compareSpecItems, SPEC_DETAIL_CATEGORIES +LASER_TUBE/+TUBE_BENDING, endpoint recalculate). Fix lots TLT/laser: requirementId nullable, splitLots corrigé, items enrichis requirementIds. SPEC-36B: Ближайшие платежи avec vraies données (POInstallment+PaymentRequest), 7 colonnes, tags statut. Fix fournisseur: Decimalstring coercé Number(). SPEC-36C: Revert PO CONFIRMEDDRAFT (unconfirm), rejette PR, bloque si paidAt. SPEC-36D: PaymentRemindersService cron J-3/J-1/J-0/overdue, notifyRole ACHETEUR+DIRECTION_FIN, idempotent, POST /check-reminders ADMIN. SPEC-36E: Refonte lotissement PO par ligne (PurchaseLotLine model, validation 100%, deliveryDays TenderOffer). SPEC-36E-FIX: Backfill items JSONPurchaseOrderLine (12 POs migrés), fix createFromTender/createTlt. SPEC-36F: LotSplitModal plein écran (matrice ligne×lot, InputNumber/DatePicker, auto-calcul deliveryDate, validation Tag 100%). SPEC-36G: Fix révision smeta compare v2 pas v1 (suppression filtre statut currentSmeta). SPEC-36H: Fix navigation cashflow (liens Заказ/description/ЗП, highlight blink-red 10s), filtres statut Radio.Group, tri Просроченные↑, colonne Просрочка (N дн. rouge). Fix lot split: deliveryDate sauvegardée dans payload, auto-remplissage depuis supplier.deliveryDelayDays. Backfill PurchaseOrderLine.material: 48 lignes fixées (28 via requirementId, 20 TLTLASER_FLAT).
### Session 37 (10/04/2026)
Fix budget byCategory: remplacé PR.budgetAmount (null) par PurchaseOrderLine groupées par material (quantity×finalPrice). SPEC-37A: Refonte Настройки multi-onglets (Профиль/Уведомления/Категории). Modèle UserNotificationPreference (7 catégories: PAYMENT_DUE, PR_APPROVE, PR_CONFIRM, TENDER_OFFER, SMETA_REVISION, PO_DELIVERY, LOT_ORDER_DUE). Defaults par rôle (ROLE_DEFAULT_CATEGORIES). Routes GET/PUT /notification-preferences (upsert transactionnel). NotificationHelper: shouldNotifyInApp() filtre par catégorie avant création. PaymentRemindersService: category PAYMENT_DUE ajouté. Frontend: ProfileTab (GET /auth/me), NotificationsTab (Switch inApp actif, Email/Telegram disabled futur), SettingsPage 3 onglets.
---
## 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)