# ArchiTools — Project Context for AI Assistants ## Quick Start ```bash npm install npm run dev # http://localhost:3000 npx next build # verify zero errors before pushing git push origin main # manual redeploy via Portainer UI ``` --- ## Project Overview **ArchiTools** is a modular internal web dashboard for 3 architecture/engineering companies: **Beletage** (architecture), **Urban Switch** (urbanism), **Studii de Teren** (geotechnics). Production: `tools.beletage.ro` — Docker on-premise, Portainer CE, Traefik v3 proxy. ### Stack | Layer | Technology | | ---------- | ------------------------------------------------------- | | Framework | Next.js 16.x, App Router, TypeScript (strict) | | Styling | Tailwind CSS v4, shadcn/ui | | Database | PostgreSQL + PostGIS via Prisma v6 ORM | | Storage | `DatabaseStorageAdapter` (Prisma), localStorage fallback | | Files | MinIO (S3-compatible object storage) | | Auth | NextAuth v4 + Authentik OIDC (auth.beletage.ro) | | Deploy | Docker multi-stage → Portainer CE → Traefik v3 + SSL | | Repo | Gitea at `git.beletage.ro/gitadmin/ArchiTools` | | Language | Code: **English**, UI: **Romanian** | ### Architecture Principles - **Module platform** — each module isolated: own types/services/hooks/components - **Feature flags** gate loading (disabled = zero bundle cost) - **Storage abstraction** via `StorageService` interface + adapters - **Auth via Authentik SSO** — group → role/company mapping - **All entities** include `visibility` / `createdBy` from day one --- ## Repository Structure ``` src/ ├── app/(modules)/ # Route pages (thin wrappers) ├── core/ # Platform: auth, storage, flags, tagging, i18n, theme ├── modules// # Module business logic (see MODULE-MAP.md) │ ├── components/ # UI components │ ├── hooks/ # Module hooks │ ├── services/ # Business logic │ ├── types.ts # Interfaces │ ├── config.ts # Module metadata │ └── index.ts # Public exports ├── shared/components/ # ui/ (shadcn), layout/ (sidebar/header), common/ ├── config/ # modules.ts, flags.ts, navigation.ts, companies.ts docs/ # Architecture, guides, module deep-dives ``` --- ## Modules (17 total) | Module | Route | Key Features | | ------------------ | ------------------- | --------------------------------------------------- | | Dashboard | `/` | KPI cards, activity feed, module grid | | Email Signature | `/email-signature` | Multi-company, live preview, copy/download | | Word XML | `/word-xml` | Category-based XML, simple/advanced, ZIP export | | Registratura | `/registratura` | Registry CRUD, legal deadlines, notifications, NAS | | Tag Manager | `/tag-manager` | Tags CRUD, ManicTime sync | | IT Inventory | `/it-inventory` | Equipment, rack visualization, filters | | Address Book | `/address-book` | Contacts, vCard, Registratura integration | | Password Vault | `/password-vault` | AES-256-GCM encrypted, WiFi QR, multi-user | | Mini Utilities | `/mini-utilities` | 12+ tools: PDF compress, OCR, converters, calc | | Prompt Generator | `/prompt-generator` | 18 templates, text + image targets | | Digital Signatures | `/digital-signatures` | Assets CRUD, file upload, tags | | Word Templates | `/word-templates` | Template library, .docx placeholder detection | | AI Chat | `/ai-chat` | Multi-provider (OpenAI/Claude/Ollama) | | Hot Desk | `/hot-desk` | 4 desks, week calendar, room layout | | ParcelSync | `/parcel-sync` | eTerra ANCPI, PostGIS, enrichment, ePay ordering | | Geoportal | `/geoportal` | MapLibre viewer, parcel search, UAT layers | | Visual CoPilot | `/visual-copilot` | Placeholder — separate repo | See `docs/MODULE-MAP.md` for entry points, API routes, and cross-module deps. --- ## Development Rules ### TypeScript Strict Mode Gotchas - `arr[0]` is `T | undefined` even after length check — assign to const first - `Record[key]` returns `T | undefined` — always null-check - Spread of possibly-undefined: `{ ...obj[key] }` — check existence first - lucide-react Icons: cast through `unknown` → `React.ComponentType<{ className?: string }>` - Prisma `$queryRaw` returns `unknown[]` — cast with `as Array<{ field: type }>` - `?? ""` on `{}` field produces `{}` not `string` — use `typeof` check ### Conventions - **Code**: English | **UI text**: Romanian | **IDs**: uuid v4 - **Dates**: ISO strings (`YYYY-MM-DD` display, full ISO timestamps) - **Components**: functional, `'use client'` where needed - **No emojis** in code or UI ### Storage Performance (CRITICAL) - **NEVER** `storage.list()` + `storage.get()` in loop — N+1 bug - **ALWAYS** use `storage.exportAll()` or `storage.export(namespace)` for batch-load - **NEVER** store base64 files in entity JSON — use `lightweight: true` for listing - After mutations: optimistic update OR single `refresh()` — never both ### Middleware & Large Uploads - Middleware buffers entire body — exclude large-upload routes from matcher - Excluded routes: `api/auth|api/notifications/digest|api/compress-pdf|api/address-book|api/projects` - Excluded routes use `requireAuth()` from `auth-check.ts` instead - To add new upload route: (1) exclude from middleware, (2) add `requireAuth()` ### eTerra / ANCPI Rules - ArcGIS: paginate with `resultOffset`/`resultRecordCount` (max 1000) - Sessions expire ~10min — cache TTL 9min, auto-relogin on 401 - Health check detects maintenance — block login when down - `WORKSPACE_TO_COUNTY` (42 entries in `county-refresh.ts`) is authoritative - `GisUat.geometry` is huge — always `select` to exclude in list queries - Feature counts cached 5-min TTL - ePay: form-urlencoded body, OpenAM auth, MinIO metadata must be ASCII ### Before Pushing 1. `npx next build` — zero errors 2. Test on `localhost:3000` 3. Commit with descriptive message 4. `git push origin main` → manual Portainer redeploy --- ## Common Pitfalls (Top 10) 1. **Middleware body buffering** — upload routes >10MB must be excluded from matcher 2. **N+1 storage queries** — use `exportAll()`, never `list()` + `get()` loop 3. **GisUat geometry in queries** — exclude with `select`, or 50ms → 5+ seconds 4. **Enrichment data loss on re-sync** — upsert must preserve enrichment field 5. **Ghostscript corrupts fonts** — use qpdf for PDF compression, never GS 6. **eTerra timeout too low** — geometry pages need 60-90s; default 120s 7. **Traefik 60s readTimeout** — must set 600s in static config for uploads 8. **Portainer CE can't inject env vars** — all env in docker-compose.yml 9. **`@prisma/client` in dependencies** (not devDeps) — runtime requirement 10. **`output: 'standalone'`** in next.config.ts — required for Docker --- ## Infrastructure Quick Reference | Service | Address | Purpose | | ----------- | ------------------------ | -------------------------- | | App | 10.10.10.166:3000 | ArchiTools (tools.beletage.ro) | | PostgreSQL | 10.10.10.166:5432 | Database (Prisma) | | MinIO | 10.10.10.166:9002/9003 | Object storage | | Authentik | 10.10.10.166:9100 | SSO (auth.beletage.ro) | | Portainer | 10.10.10.166:9000 | Docker management | | Gitea | 10.10.10.166:3002 | Git (git.beletage.ro) | | Traefik | 10.10.10.199 | Reverse proxy + SSL | | N8N | 10.10.10.166:5678 | Workflow automation | | Stirling PDF | 10.10.10.166:8087 | PDF tools (needs env vars!) | ## Company IDs | ID | Name | Prefix | | ----------------- | --------------- | ------ | | `beletage` | Beletage | B | | `urban-switch` | Urban Switch | US | | `studii-de-teren` | Studii de Teren | SDT | | `group` | Grup | G | --- ## Documentation | Doc | Path | | ------------------- | ------------------------------------------ | | Module Map | `docs/MODULE-MAP.md` | | Architecture Quick | `docs/ARCHITECTURE-QUICK.md` | | System Architecture | `docs/architecture/SYSTEM-ARCHITECTURE.md` | | Module System | `docs/architecture/MODULE-SYSTEM.md` | | Feature Flags | `docs/architecture/FEATURE-FLAGS.md` | | Storage Layer | `docs/architecture/STORAGE-LAYER.md` | | Security & Roles | `docs/architecture/SECURITY-AND-ROLES.md` | | Module Dev Guide | `docs/guides/MODULE-DEVELOPMENT.md` | | Docker Deployment | `docs/guides/DOCKER-DEPLOYMENT.md` | | Coding Standards | `docs/guides/CODING-STANDARDS.md` | | Data Model | `docs/DATA-MODEL.md` | For module-specific deep dives, see `docs/modules/`.