# ArchiTools — Project Context for AI Assistants > This file provides all context needed for Claude Code, Sonnet, or any AI model to work on this project from scratch. --- ## Quick Start ```bash npm install npm run dev # http://localhost:3000 npx next build # verify zero errors before pushing git push origin main # auto-deploys via Portainer webhook ``` --- ## Project Overview **ArchiTools** is a modular internal web dashboard for an architecture/engineering office group of 3 companies: - **Beletage** (architecture) - **Urban Switch** (urbanism) - **Studii de Teren** (geotechnics) It runs on an on-premise Ubuntu server at `10.10.10.166`, containerized with Docker, managed via Portainer, served by Nginx Proxy Manager. ### Stack | Layer | Technology | | ------------ | ---------------------------------------------------------------------------- | | Framework | Next.js 16.x, App Router, TypeScript (strict) | | Styling | Tailwind CSS v4, shadcn/ui | | Database | PostgreSQL (10.10.10.166:5432) via Prisma v6 ORM | | Storage | `DatabaseStorageAdapter` (PostgreSQL) — localStorage fallback available | | File Storage | MinIO (10.10.10.166:9002 API / 9003 UI) — client configured, adapter pending | | Auth | NextAuth v4 + Authentik OIDC (auth.beletage.ro) | | Deploy | Docker multi-stage, Portainer CE, Nginx Proxy Manager | | Repo | Gitea at `https://git.beletage.ro/gitadmin/ArchiTools` | | Language | Code in **English**, UI in **Romanian** | ### Architecture Principles - **Module platform, not monolith** — each module isolated with own types/services/hooks/components - **Feature flags** gate module loading (disabled = zero bundle cost) - **Storage abstraction**: `StorageService` interface with adapters (database default via Prisma, localStorage fallback) - **Cross-module tagging system** as shared service - **Auth via Authentik SSO** — NextAuth v4 + OIDC, group→role/company mapping - **All entities** include `visibility` / `createdBy` fields from day one - **Company logos** — theme-aware (light/dark variants), dual-rendered for SSR safety --- ## Repository Structure ``` src/ ├── app/ # Routing only (thin wrappers) │ ├── (modules)/ # Module route pages │ └── layout.tsx # App shell ├── core/ # Platform services │ ├── module-registry/ # Module registration + types │ ├── feature-flags/ # Flag evaluation + env override │ ├── storage/ # StorageService + adapters │ │ └── adapters/ # localStorage adapter (+ future DB/MinIO) │ ├── tagging/ # Cross-module tag service │ ├── i18n/ # Romanian translations │ ├── theme/ # Light/dark theme │ └── auth/ # Auth types + stub (future Authentik) ├── modules/ # Module business logic │ ├── / │ │ ├── components/ # Module UI components │ │ ├── hooks/ # Module-specific hooks │ │ ├── services/ # Module business logic │ │ ├── types.ts # Module types │ │ ├── config.ts # Module metadata │ │ └── index.ts # Public exports │ └── ... ├── shared/ # Shared UI │ ├── components/ │ │ ├── ui/ # shadcn/ui primitives │ │ ├── layout/ # Sidebar, Header │ │ └── common/ # Reusable app components │ ├── hooks/ # Shared hooks │ └── lib/ # Utils (cn, etc.) ├── config/ # Global config │ ├── modules.ts # Module registry entries │ ├── flags.ts # Default feature flags │ ├── navigation.ts # Sidebar nav structure │ └── companies.ts # Company definitions docs/ # 16 internal technical docs legacy/ # Original HTML tools for reference ``` --- ## Implemented Modules (16 total — 14 original + 2 new) | # | Module | Route | Version | Key Features | | --- | ---------------------- | --------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 1 | **Dashboard** | `/` | 0.1.0 | KPI cards (6), activity feed (last 20), module grid, external tools | | 2 | **Email Signature** | `/email-signature` | 0.1.0 | Multi-company branding, address toggle (BTG/US/SDT), live preview, zoom/copy/download | | 3 | **Word XML Generator** | `/word-xml` | 0.1.0 | Category-based XML gen, simple/advanced mode, ZIP export | | 4 | **Registratura** | `/registratura` | 0.4.0 | CRUD registry, dynamic doc types, bidirectional Address Book, threads, backdating, **legal deadline tracking**, recipient registration, document expiry, **NAS network path attachments** (A/O/P/T drives, copy-to-clipboard), **detail sheet side panel**, **configurable column visibility**, **QuickLook attachment preview** (images: zoom/pan, PDFs: native viewer, multi-file navigation) | | 5 | **Tag Manager** | `/tag-manager` | 0.2.0 | CRUD tags, category/scope/color, US/SDT seeds, mandatory categories, **ManicTime bidirectional sync** | | 6 | **IT Inventory** | `/it-inventory` | 0.2.0 | Dynamic equipment types, rented status (purple pulse), **42U rack visualization**, type/status/company filters | | 7 | **Address Book** | `/address-book` | 0.1.1 | CRUD contacts, card grid, vCard export, Registratura reverse lookup, **dynamic types (creatable)**, **alphabetically sorted type dropdown** | | 8 | **Password Vault** | `/password-vault` | 0.3.0 | CRUD credentials, 9 categorii cu iconițe, **WiFi QR code real**, context-aware form, strength meter, company scope, **AES-256-GCM encryption** | | 9 | **Mini Utilities** | `/mini-utilities` | 0.2.0 | Text case, char counter, percentage, **TVA calculator (19%)**, area converter, U→R, num→text, artifact cleaner, MDLPA, **extreme PDF compression (GS+qpdf)**, PDF unlock, **DWG→DXF**, OCR, color palette, **paste on all drop zones**, **thermal drag-drop reorder** | | 10 | **Prompt Generator** | `/prompt-generator` | 0.2.0 | Template-driven prompt builder, **18 templates** (14 text + 4 image), search bar, target type filter | | 11 | **Digital Signatures** | `/digital-signatures` | 0.1.0 | CRUD assets, drag-and-drop file upload, tag chips | | 12 | **Word Templates** | `/word-templates` | 0.1.0 | Template library, 8 categories, version tracking, .docx placeholder auto-detection | | 13 | **AI Chat** | `/ai-chat` | 0.2.0 | Multi-provider (OpenAI/Claude/Ollama/demo), **project linking via Tag Manager**, provider status badge | | 14 | **Hot Desk** | `/hot-desk` | 0.1.1 | 4 desks, week-ahead calendar, room layout (window+door proportioned), reserve/cancel | | 15 | **ParcelSync** | `/parcel-sync` | 0.5.0 | eTerra ANCPI integration, **PostGIS database**, background sync, 23-layer catalog, enrichment pipeline, owner search, **per-UAT analytics dashboard**, **health check + maintenance detection** | | 16 | **Visual Copilot** | `/visual-copilot` | 0.1.0 | AI-powered image analysis — **developed in separate repo** (`https://git.beletage.ro/gitadmin/vim`), placeholder in ArchiTools, will be merged as module later | ### Registratura — Legal Deadline Tracking (Termene Legale) The Registratura module includes a full legal deadline tracking engine for Romanian construction permitting: - **16 deadline types** across 5 categories (Avize, Completări, Analiză, Autorizare, Publicitate) - **Working days vs calendar days** with Romanian public holiday support (including Orthodox Easter via Meeus algorithm) - **Backward deadlines** (e.g., AC extension: 45 working days BEFORE expiry) - **Chain deadlines** (resolving one prompts adding the next) - **Tacit approval** (auto-detected when overdue + applicable type) - **Tabbed UI**: "Registru" tab (existing registry) + "Termene legale" tab (deadline dashboard) Key files: - `services/working-days.ts` — Romanian holidays, `addWorkingDays()`, `isWorkingDay()` - `services/deadline-catalog.ts` — 16 `DeadlineTypeDef` entries - `services/deadline-service.ts` — `createTrackedDeadline()`, `resolveDeadline()`, `aggregateDeadlines()` - `components/attachment-preview.tsx` — QuickLook-style fullscreen preview (images: zoom/pan, PDFs: blob URL iframe, multi-file nav) - `components/deadline-dashboard.tsx` — Stats + filters + table - `components/deadline-add-dialog.tsx` — 3-step wizard (category → type → date preview) ### ParcelSync — eTerra ANCPI GIS Integration The ParcelSync module connects to Romania's national eTerra/ANCPI cadastral system: - **eTerra API client** (`eterra-client.ts`): form-post auth, JSESSIONID cookie jar, session caching (9min TTL), auto-relogin, paginated fetching with `maxRecordCount=1000` + fallback page sizes (500, 200) - **23-layer catalog** (`eterra-layers.ts`): TERENURI_ACTIVE, CLADIRI_ACTIVE, LIMITE_UAT, etc. organized in 6 categories - **PostGIS storage**: `GisFeature` model with geometry column, SIRUTA-based partitioning, `enrichment` JSONB field - **Background sync**: long-running jobs via server singleton, progress polling (2s), phase tracking (fetch → save → enrich) - **Enrichment pipeline** (`enrich-service.ts`): hits eTerra `/api/immovable/list` per parcel to extract NR_CAD, NR_CF, PROPRIETARI, SUPRAFATA, INTRAVILAN, CATEGORIE_FOLOSINTA, HAS_BUILDING, etc. - **Owner search**: DB-first (ILIKE on enrichment JSON) with eTerra API fallback - **Per-UAT dashboard**: SQL aggregates (area stats, intravilan/extravilan, land use, top owners), CSS-only visualizations (donut ring, bar charts) - **Health check** (`eterra-health.ts`): pings `eterra.ancpi.ro` every 3min, detects maintenance by keywords in HTML response, blocks login when down, UI shows amber "Mentenanță" state - **Test UAT**: Feleacu (SIRUTA 57582, ~30k immovables, ~8k GIS features) Key files: - `services/eterra-client.ts` — API client (~1000 lines), session cache, pagination, retry - `services/eterra-layers.ts` — 23-layer catalog with categories - `services/sync-service.ts` — Layer sync engine with progress tracking - `services/enrich-service.ts` — Enrichment pipeline (FeatureEnrichment type) - `services/eterra-health.ts` — Health check singleton, maintenance detection - `services/session-store.ts` — Server-side session management - `components/parcel-sync-module.tsx` — Main UI (~4100 lines), 4 tabs (Export/Layers/Search/DB) - `components/uat-dashboard.tsx` — Per-UAT analytics dashboard (CSS-only charts) --- ## Infrastructure ### Server: `10.10.10.166` (Ubuntu) | Service | Port | Purpose | | ----------------------- | ---------------------- | ----------------------------------- | | **ArchiTools** | 3000 | This app (tools.beletage.ro) | | **Gitea** | 3002 | Git hosting (git.beletage.ro) | | **PostgreSQL** | 5432 | App database (Prisma ORM) | | **Portainer** | 9000 | Docker management | | **Nginx Proxy Manager** | 81 (admin) | Reverse proxy + SSL termination | | **Uptime Kuma** | 3001 | Service monitoring | | **MinIO** | 9002 (API) / 9003 (UI) | Object storage | | **Authentik** | 9100 | SSO (auth.beletage.ro) — **active** | | **N8N** | 5678 | Workflow automation (future) | | **Stirling PDF** | 8087 | PDF tools | | **IT-Tools** | 8085 | Developer utilities | | **FileBrowser** | 8086 | File management | | **Netdata** | 19999 | System monitoring | | **Dozzle** | 9999 | Docker log viewer | | **CrowdSec** | 8088 | Security | ### Deployment Pipeline ``` git push origin main → Gitea webhook fires → Portainer CE detects new commit → Manual "Pull and redeploy" in Portainer (CE doesn't auto-rebuild) → Docker multi-stage build (~1-2 min) → Container starts on :3000 → Nginx Proxy Manager routes to tools.beletage.ro ``` ### Docker - `Dockerfile`: 3-stage build (deps → builder → runner), `node:20-alpine`, non-root user - `Dockerfile` includes `npx prisma generate` before build step - `docker-compose.yml`: single service, port 3000, **all env vars hardcoded** (Portainer CE can't inject env vars) - `output: 'standalone'` in `next.config.ts` is **required** - `@prisma/client` must be in `dependencies` (not devDependencies) for runtime --- ## Development Rules ### TypeScript Strict Mode Gotchas - `array.split()[0]` returns `string | undefined` — use `.slice(0, 10)` instead - `Record[key]` returns `T | undefined` — always guard with null check - Spread of possibly-undefined objects: `{ ...obj[key], field }` — check existence first - lucide-react Icons: cast through `unknown` → `React.ComponentType<{ className?: string }>` - `arr[0]` is `T | undefined` even after `arr.length > 0` check — assign to const first: `const first = arr[0]; if (first) { ... }` - Prisma `$queryRaw` returns `unknown[]` — always cast with `as Array<{ field: type }>` and guard access - `?? ""` on an object field typed `{}` produces `{}` not `string` — use explicit `typeof x === 'string'` or `'number'` check ### Conventions - **Code**: English - **UI text**: Romanian - **Components**: functional, `'use client'` directive where needed - **State**: localStorage via `useStorage('module-name')` hook - **IDs**: `uuid v4` - **Dates**: ISO strings (`YYYY-MM-DD` for display, full ISO for timestamps) - **No emojis** in code or UI unless explicitly requested ### Storage Performance Rules - **NEVER** use `storage.list()` followed by `storage.get()` in a loop — this is an N+1 query bug - `list()` fetches ALL items (keys+values) from DB but discards values, then each `get()` re-fetches individually - **ALWAYS** use `storage.exportAll()` (namespaced) or `storage.export(namespace)` (service-level) to batch-load - Filter items client-side after a single fetch: `for (const [key, value] of Object.entries(all)) { ... }` - After mutations (add/update), either do optimistic local state update or a single `refresh()` — never both - **NEVER store large binary data (base64 files) inside entity JSON** — this makes list loading transfer tens of MB - For modules with attachments: use `exportAll({ lightweight: true })` for listing, `storage.get()` for single-entry full load - The API `?lightweight=true` parameter strips `data`/`fileData` strings >1KB from JSON values server-side - Future: move file data to MinIO; only store metadata (name, size, type, url) in the entity JSON ### Module Development Pattern Every module follows: ``` src/modules// ├── components/ # React components ├── hooks/ # Custom hooks (use-.ts) ├── services/ # Business logic (pure functions) ├── types.ts # TypeScript interfaces ├── config.ts # ModuleConfig metadata └── index.ts # Public exports ``` ### eTerra / External API Rules - **ArcGIS REST API** has `maxRecordCount=1000` — always paginate with `resultOffset`/`resultRecordCount` - **eTerra sessions expire after ~10min** — session cache TTL is 9min, auto-relogin on 401/redirect - **eTerra goes into maintenance regularly** — health check must detect and block login attempts - **Never hardcode timeouts too low** — eTerra 1000-feature geometry pages can take 60-90s; default is 120s - **CookieJar + axios-cookiejar-support** required for eTerra auth (JSESSIONID tracking) - **Page size fallbacks**: if 1000 fails, retry with 500, then 200 ### Before Pushing 1. `npx next build` — must pass with zero errors 2. Test the feature manually on `localhost:3000` 3. Commit with descriptive message 4. `git push origin main` — Portainer auto-deploys --- ## Company IDs | ID | Name | Prefix | | ----------------- | --------------- | ------ | | `beletage` | Beletage | B | | `urban-switch` | Urban Switch | US | | `studii-de-teren` | Studii de Teren | SDT | | `group` | Grup | G | --- ## Current Integrations | Feature | Status | Notes | | -------------------- | ---------------------- | ------------------------------------------------------------------------------------------ | | **Authentik SSO** | ✅ Active | NextAuth v4 + OIDC, group→role/company mapping | | **PostgreSQL** | ✅ Active | Prisma ORM, `KeyValueStore` model, `/api/storage` route | | **MinIO** | Client configured | 10.10.10.166:9002, bucket `tools`, adapter pending | | **AI Chat API** | ✅ Multi-provider | `/api/ai-chat` — OpenAI/Claude/Ollama/demo; needs API key env | | **Vault Encryption** | ✅ Active | AES-256-GCM server-side, `/api/vault`, ENCRYPTION_SECRET env | | **ManicTime Sync** | ✅ Implemented | `/api/manictime` — bidirectional Tags.txt sync, needs SMB mount | | **NAS Paths** | ✅ Active | `\\newamun` (10.10.10.10), drives A/O/P/T, hostname+IP fallback, `src/config/nas-paths.ts` | | **eTerra ANCPI** | ✅ Active | ParcelSync module, `eterra-client.ts`, health check + maintenance detection | | **PostGIS** | ✅ Active | `GisFeature` model, geometry storage, spatial queries, used by ParcelSync | | **N8N automations** | Webhook URL configured | For notifications, backups, workflows | --- ## Model Recommendations | Task Type | Claude | OpenAI | Google | Notes | | ----------------------------- | -------------- | ------------- | ---------------- | ----------------------------------------------- | | **Bug fixes, config** | Haiku 4.5 | GPT-4o-mini | Gemini 2.5 Flash | Fast, cheap | | **Features, tests, UI** | **Sonnet 4.6** | GPT-5.2 | Gemini 3 Flash | Best value — Opus-class quality at Sonnet price | | **New modules, architecture** | Opus 4.6 | GPT-5.3-Codex | Gemini 3 Pro | Complex multi-file, business logic | **Default: Sonnet 4.6** for most work. See `ROADMAP.md` for per-task recommendations. ### Session Handoff Tips - Read this `CLAUDE.md` first — it has all context - Read `ROADMAP.md` for the complete task list with dependencies - Check `docs/` for deep dives on specific systems - Check `src/modules//types.ts` before modifying any module - Always run `npx next build` before committing - Push to `main` → Portainer auto-deploys via Gitea webhook - The 16 docs in `docs/` total ~10,600 lines — search them for architecture questions --- ## Documentation Index | Doc | Path | Content | | ------------------- | ------------------------------------------ | -------------------------------------------- | | System Architecture | `docs/architecture/SYSTEM-ARCHITECTURE.md` | Overall architecture, module platform design | | Module System | `docs/architecture/MODULE-SYSTEM.md` | Module registry, lifecycle, config format | | Feature Flags | `docs/architecture/FEATURE-FLAGS.md` | Flag system, env overrides | | Storage Layer | `docs/architecture/STORAGE-LAYER.md` | StorageService interface, adapters | | Tagging System | `docs/architecture/TAGGING-SYSTEM.md` | Cross-module tags | | Security & Roles | `docs/architecture/SECURITY-AND-ROLES.md` | Visibility, auth, roles | | Module Dev Guide | `docs/guides/MODULE-DEVELOPMENT.md` | How to create a new module | | HTML Integration | `docs/guides/HTML-TOOL-INTEGRATION.md` | Legacy tool migration | | UI Design System | `docs/guides/UI-DESIGN-SYSTEM.md` | Design tokens, component patterns | | Docker Deployment | `docs/guides/DOCKER-DEPLOYMENT.md` | Full Docker/Portainer/Nginx guide | | Coding Standards | `docs/guides/CODING-STANDARDS.md` | TS strict, naming, patterns | | Testing Strategy | `docs/guides/TESTING-STRATEGY.md` | Testing approach | | Configuration | `docs/guides/CONFIGURATION.md` | Env vars, flags, companies | | Data Model | `docs/DATA-MODEL.md` | All entity schemas | | Repo Structure | `docs/REPO-STRUCTURE.md` | Directory layout | | Prompt Generator | `docs/modules/PROMPT-GENERATOR.md` | Prompt module deep dive |