audit: production safety fixes, cleanup, and documentation overhaul
CRITICAL fixes: - Fix SQL injection in geoportal search (template literal in $queryRaw) - Preserve enrichment data during GIS re-sync (upsert update explicit fields only) - Fix ePay version race condition (advisory lock in transaction) - Add requireAuth() to compress-pdf and unlock routes (were unauthenticated) - Remove hardcoded Stirling PDF API key (env vars now required) IMPORTANT fixes: - Add admin role check on registratura debug-sequences endpoint - Fix reserved slot race condition with advisory lock in transaction - Use SSO identity in close-guard-dialog instead of hardcoded "Utilizator" - Storage DELETE catches only P2025 (not found), re-throws real errors - Add onDelete: SetNull for GisFeature → GisSyncRun relation - Move portal-only users to PORTAL_ONLY_USERS env var - Add security headers (X-Frame-Options, X-Content-Type-Options, Referrer-Policy) - Add periodic cleanup for eTerra/ePay session caches and progress store - Log warning when ePay dataDocument is missing (expiry fallback) Cleanup: - Delete orphaned rgi-test page (1086 lines, unregistered, inaccessible) - Delete legacy/ folder (5 files, unreferenced from src/) - Remove unused ensureBucketExists() from minio-client.ts Documentation: - Optimize CLAUDE.md: 464 → 197 lines (moved per-module details to docs/) - Create docs/ARCHITECTURE-QUICK.md (80 lines: data flow, deps, env vars) - Create docs/MODULE-MAP.md (140 lines: entry points, API routes, cross-deps) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
# ArchiTools — Architecture Quick Reference
|
||||
|
||||
## Data Flow
|
||||
|
||||
```
|
||||
Browser → Traefik (tools.beletage.ro) → Next.js :3000
|
||||
├── App Router (pages)
|
||||
├── API Routes (/api/*)
|
||||
│ ├── Prisma → PostgreSQL + PostGIS
|
||||
│ ├── MinIO (file storage)
|
||||
│ ├── eTerra ANCPI (external GIS API)
|
||||
│ └── Brevo SMTP (email notifications)
|
||||
└── Auth: NextAuth → Authentik OIDC
|
||||
```
|
||||
|
||||
## Module Dependencies
|
||||
|
||||
```
|
||||
registratura ←→ address-book (bidirectional: contacts + reverse lookup)
|
||||
parcel-sync → geoportal (map components reuse)
|
||||
geoportal → PostGIS (spatial queries, vector tiles)
|
||||
parcel-sync → eTerra API (external: ANCPI cadastral data)
|
||||
parcel-sync → ePay API (external: ANCPI CF extract ordering)
|
||||
parcel-sync → MinIO (CF extract PDF storage)
|
||||
notifications → registratura (deadline digest data)
|
||||
all modules → core/storage (KeyValueStore via Prisma)
|
||||
all modules → core/auth (Authentik SSO session)
|
||||
```
|
||||
|
||||
## Critical API Routes (Write Operations)
|
||||
|
||||
| Route | Method | What it does | Auth |
|
||||
| ---------------------------------- | ------ | ----------------------------------- | --------- |
|
||||
| `/api/storage` | PUT/DELETE | KeyValueStore CRUD | Middleware |
|
||||
| `/api/registratura` | POST/PUT/DELETE | Registry entries + audit | Middleware + Bearer |
|
||||
| `/api/registratura/reserved` | POST | Reserve future registry slots | Middleware |
|
||||
| `/api/registratura/debug-sequences`| POST/PATCH | Reset sequence counters | Admin only |
|
||||
| `/api/vault` | PUT/DELETE | Encrypted vault entries | Middleware |
|
||||
| `/api/address-book` | PUT/DELETE | Contact CRUD | Middleware + Bearer |
|
||||
| `/api/eterra/sync-background` | POST | Start GIS sync job | Middleware |
|
||||
| `/api/eterra/uats` | POST/PATCH | UAT management + county refresh | Middleware |
|
||||
| `/api/ancpi/order` | POST | ePay CF extract order | Middleware |
|
||||
| `/api/notifications/digest` | POST | Trigger email digest | Bearer |
|
||||
| `/api/notifications/preferences` | PUT | User notification prefs | Middleware |
|
||||
| `/api/compress-pdf/*` | POST | PDF compression/unlock | requireAuth |
|
||||
|
||||
## Storage Architecture
|
||||
|
||||
```
|
||||
KeyValueStore (Prisma) GisFeature (PostGIS) MinIO
|
||||
├── namespace: module-id ├── layerId + objectId ├── bucket: tools
|
||||
├── key: entity UUID ├── geometry (GeoJSON) ├── bucket: ancpi-cf
|
||||
└── value: JSON blob ├── enrichment (JSONB) └── PDF files
|
||||
└── geom (native PostGIS)
|
||||
```
|
||||
|
||||
## Auth Flow
|
||||
|
||||
```
|
||||
User → /auth/signin → Authentik OIDC → callback → NextAuth session
|
||||
├── Middleware: checks JWT token, redirects if unauthenticated
|
||||
├── Portal-only users: env PORTAL_ONLY_USERS → redirected to /portal
|
||||
└── API routes excluded from middleware: use requireAuth() or Bearer token
|
||||
```
|
||||
|
||||
## Environment Variables (Critical)
|
||||
|
||||
| Var | Required | Used by |
|
||||
| ---------------------- | -------- | -------------------------- |
|
||||
| `DATABASE_URL` | Yes | Prisma |
|
||||
| `NEXTAUTH_SECRET` | Yes | NextAuth JWT |
|
||||
| `NEXTAUTH_URL` | Yes | Auth redirects |
|
||||
| `ENCRYPTION_SECRET` | Yes | Password Vault AES-256 |
|
||||
| `STIRLING_PDF_URL` | Yes | PDF compression/unlock |
|
||||
| `STIRLING_PDF_API_KEY` | Yes | Stirling PDF auth |
|
||||
| `NOTIFICATION_CRON_SECRET` | Yes | Digest endpoint Bearer |
|
||||
| `MINIO_*` | Yes | MinIO connection |
|
||||
| `ANCPI_*` | For ePay | ePay CF ordering |
|
||||
| `ILOVEPDF_PUBLIC_KEY` | Optional | Cloud PDF compression |
|
||||
| `PORTAL_ONLY_USERS` | Optional | Comma-separated usernames |
|
||||
@@ -0,0 +1,140 @@
|
||||
# ArchiTools — Module Map
|
||||
|
||||
Quick reference: entry points, key files, API routes, and cross-module dependencies.
|
||||
|
||||
## Module Index
|
||||
|
||||
| Module | Entry Point | Config | Types |
|
||||
| ------ | ----------- | ------ | ----- |
|
||||
| [Dashboard](#dashboard) | `modules/dashboard/index.ts` | — | `types.ts` |
|
||||
| [Email Signature](#email-signature) | `modules/email-signature/index.ts` | `config.ts` | `types.ts` |
|
||||
| [Word XML](#word-xml) | `modules/word-xml/index.ts` | `config.ts` | `types.ts` |
|
||||
| [Registratura](#registratura) | `modules/registratura/index.ts` | `config.ts` | `types.ts` |
|
||||
| [Tag Manager](#tag-manager) | `modules/tag-manager/index.ts` | `config.ts` | `types.ts` |
|
||||
| [IT Inventory](#it-inventory) | `modules/it-inventory/index.ts` | `config.ts` | `types.ts` |
|
||||
| [Address Book](#address-book) | `modules/address-book/index.ts` | `config.ts` | `types.ts` |
|
||||
| [Password Vault](#password-vault) | `modules/password-vault/index.ts` | `config.ts` | `types.ts` |
|
||||
| [Mini Utilities](#mini-utilities) | `modules/mini-utilities/index.ts` | `config.ts` | `types.ts` |
|
||||
| [Prompt Generator](#prompt-generator) | `modules/prompt-generator/index.ts` | `config.ts` | `types.ts` |
|
||||
| [Digital Signatures](#digital-signatures) | `modules/digital-signatures/index.ts` | `config.ts` | `types.ts` |
|
||||
| [Word Templates](#word-templates) | `modules/word-templates/index.ts` | `config.ts` | `types.ts` |
|
||||
| [AI Chat](#ai-chat) | `modules/ai-chat/index.ts` | `config.ts` | `types.ts` |
|
||||
| [Hot Desk](#hot-desk) | `modules/hot-desk/index.ts` | `config.ts` | `types.ts` |
|
||||
| [ParcelSync](#parcel-sync) | `modules/parcel-sync/index.ts` | `config.ts` | `types.ts` |
|
||||
| [Geoportal](#geoportal) | `modules/geoportal/index.ts` | `config.ts` | `types.ts` |
|
||||
| [Visual CoPilot](#visual-copilot) | `modules/visual-copilot/index.ts` | `config.ts` | — |
|
||||
|
||||
---
|
||||
|
||||
## Module Details
|
||||
|
||||
### Dashboard
|
||||
- **Route**: `/`
|
||||
- **Main component**: `app/(modules)/page.tsx` (home page, not a registered module)
|
||||
- **API routes**: none (reads via storage API)
|
||||
- **Cross-deps**: none
|
||||
|
||||
### Email Signature
|
||||
- **Route**: `/email-signature`
|
||||
- **Main component**: `components/email-signature-module.tsx`
|
||||
- **API routes**: none (client-only)
|
||||
- **Cross-deps**: none
|
||||
|
||||
### Word XML
|
||||
- **Route**: `/word-xml`
|
||||
- **Main component**: `components/word-xml-module.tsx`
|
||||
- **Services**: `services/xml-builder.ts`, `services/zip-export.ts`
|
||||
- **API routes**: none (client-only)
|
||||
- **Cross-deps**: none
|
||||
|
||||
### Registratura
|
||||
- **Route**: `/registratura`
|
||||
- **Main component**: `components/registratura-module.tsx`
|
||||
- **Key services**: `services/registry-service.ts` (numbering, advisory locks), `services/working-days.ts` (Romanian holidays), `services/deadline-catalog.ts` (18 legal deadline types), `services/deadline-service.ts`
|
||||
- **API routes**: `/api/registratura` (CRUD + audit), `/api/registratura/reserved`, `/api/registratura/debug-sequences`, `/api/registratura/audit`, `/api/registratura/status-check`
|
||||
- **Cross-deps**: **address-book** (quick contact, reverse lookup), **notifications** (deadline digest)
|
||||
|
||||
### Tag Manager
|
||||
- **Route**: `/tag-manager`
|
||||
- **Main component**: `components/tag-manager-module.tsx`
|
||||
- **Services**: `services/manictime-sync.ts`
|
||||
- **API routes**: `/api/manictime`
|
||||
- **Cross-deps**: core/tagging
|
||||
|
||||
### IT Inventory
|
||||
- **Route**: `/it-inventory`
|
||||
- **Main component**: `components/it-inventory-module.tsx`
|
||||
- **API routes**: none (via storage API)
|
||||
- **Cross-deps**: none
|
||||
|
||||
### Address Book
|
||||
- **Route**: `/address-book`
|
||||
- **Main component**: `components/address-book-module.tsx`
|
||||
- **Services**: `services/vcard-export.ts`
|
||||
- **API routes**: `/api/address-book` (CRUD, Bearer token support)
|
||||
- **Cross-deps**: **registratura** (reverse lookup via `useRegistry`)
|
||||
|
||||
### Password Vault
|
||||
- **Route**: `/password-vault`
|
||||
- **Main component**: `components/password-vault-module.tsx`
|
||||
- **API routes**: `/api/vault` (AES-256-GCM encrypt/decrypt)
|
||||
- **Cross-deps**: none
|
||||
|
||||
### Mini Utilities
|
||||
- **Route**: `/mini-utilities`
|
||||
- **Main component**: `components/mini-utilities-module.tsx` (monolithic, tab-based)
|
||||
- **API routes**: `/api/compress-pdf/*` (local qpdf + cloud iLovePDF), `/api/compress-pdf/unlock`
|
||||
- **Cross-deps**: none
|
||||
|
||||
### Prompt Generator
|
||||
- **Route**: `/prompt-generator`
|
||||
- **Main component**: `components/prompt-generator-module.tsx`
|
||||
- **Services**: `services/prompt-templates.ts` (18 templates)
|
||||
- **API routes**: none (client-only)
|
||||
- **Cross-deps**: none
|
||||
|
||||
### Digital Signatures
|
||||
- **Route**: `/digital-signatures`
|
||||
- **Main component**: `components/digital-signatures-module.tsx`
|
||||
- **API routes**: none (via storage API)
|
||||
- **Cross-deps**: none
|
||||
|
||||
### Word Templates
|
||||
- **Route**: `/word-templates`
|
||||
- **Main component**: `components/word-templates-module.tsx`
|
||||
- **Services**: `services/docx-analyzer.ts`
|
||||
- **API routes**: none (via storage API)
|
||||
- **Cross-deps**: none
|
||||
|
||||
### AI Chat
|
||||
- **Route**: `/ai-chat`
|
||||
- **Main component**: `components/ai-chat-module.tsx`
|
||||
- **API routes**: `/api/ai-chat` (multi-provider proxy)
|
||||
- **Cross-deps**: tag-manager (project linking)
|
||||
|
||||
### Hot Desk
|
||||
- **Route**: `/hot-desk`
|
||||
- **Main component**: `components/hot-desk-module.tsx`
|
||||
- **Services**: `services/desk-layout.ts`
|
||||
- **API routes**: none (via storage API)
|
||||
- **Cross-deps**: none
|
||||
|
||||
### ParcelSync
|
||||
- **Route**: `/parcel-sync`
|
||||
- **Main component**: `components/parcel-sync-module.tsx` (~4100 lines, 5 tabs)
|
||||
- **Key services**: `services/eterra-client.ts` (~1000 lines, eTerra API), `services/sync-service.ts`, `services/enrich-service.ts`, `services/eterra-health.ts`, `services/epay-client.ts`, `services/epay-queue.ts`, `services/epay-storage.ts`, `services/no-geom-sync.ts`
|
||||
- **API routes**: `/api/eterra/*` (login, sync, search, features, UATs, health), `/api/ancpi/*` (order, test), `/api/geoportal/*` (search, boundaries, setup)
|
||||
- **Cross-deps**: **geoportal** (map components via map-tab.tsx), **MinIO** (CF extract PDFs), **PostGIS** (GisFeature, GisUat)
|
||||
|
||||
### Geoportal
|
||||
- **Route**: `/geoportal`
|
||||
- **Main component**: `components/geoportal-module.tsx`
|
||||
- **Key components**: `components/map-viewer.tsx` (MapLibre), `components/basemap-switcher.tsx`, `components/selection-toolbar.tsx`, `components/feature-info-panel.tsx`
|
||||
- **API routes**: `/api/geoportal/*` (search, boundary-check, uat-bounds, setup-views)
|
||||
- **Cross-deps**: **parcel-sync** (declared dependency — uses PostGIS data)
|
||||
|
||||
### Visual CoPilot
|
||||
- **Route**: `/visual-copilot`
|
||||
- **Status**: Placeholder (iframe to separate repo `git.beletage.ro/gitadmin/vim`)
|
||||
- **API routes**: none
|
||||
- **Cross-deps**: none
|
||||
Reference in New Issue
Block a user