# 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 two on-premise servers, containerized with Docker, managed via Portainer CE.

### 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)                              |
| Proxy        | Traefik v3 on `10.10.10.199` (proxy server), SSL via Let's Encrypt           |
| Deploy       | Docker multi-stage, Portainer CE on `10.10.10.166` (satra)                   |
| 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
│   ├── <module-name>/
│   │   ├── 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.5.0   | CRUD registry, dynamic doc types, bidirectional Address Book, threads, backdating, **legal deadline tracking** (6 categories, 18 types), 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), **email notifications** (Brevo SMTP daily digest, per-user preferences), **compact registry numbers** (single-letter company badge + direction arrow + plain number) |
| 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.2.0   | CRUD contacts (person OR institution), card grid, vCard export, Registratura reverse lookup, **dynamic types (creatable)**, **name OR company required** (flexible validation), **ContactPerson with department field**, **quick contact from Registratura** (persons + institutions) |
| 8   | **Password Vault**     | `/password-vault`     | 0.4.0   | CRUD credentials, 9 categorii cu iconițe, **WiFi QR code real**, context-aware form, strength meter, company scope, **AES-256-GCM encryption**, **utilizatori multipli per intrare** (VaultUser[]: username/password/email/notes, colapsibil în form, badge în list)                                                                                                                           |
| 9   | **Mini Utilities**     | `/mini-utilities`     | 0.4.0   | Text case, char counter, percentage, **TVA calculator (cotă configurabilă: 5/9/19/21% + custom)**, area converter, U→R, num→text, artifact cleaner, MDLPA, **PDF compression** (qpdf local lossless + iLovePDF API cloud lossy, streaming upload for large files), PDF unlock, **DWG→DXF**, OCR, color palette, **paste on all drop zones**, **thermal drag-drop reorder**, **Calculator scară desen** (real cm↔desen mm, 7 preseturi 1:20..1:5000 + custom) |
| 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:

- **18 deadline types** across 6 categories (Certificat, Avize, Completari, Urbanism, Autorizare, Litigii)
- **Working days vs calendar days** with Romanian public holiday support (including Orthodox Easter via Meeus algorithm)
- **Chain deadlines** (resolving one prompts adding the next — e.g., CU analiza → emitere, PUZ/PUD analiza → post-CTATU → emitere)
- **Tacit approval** (auto-detected when overdue + applicable type)
- **Tabbed UI**: "Registru" tab (existing registry) + "Termene legale" tab (deadline dashboard)
- **Email notifications**: daily digest via Brevo SMTP, per-user opt-in/opt-out preferences, N8N cron trigger

Key files:

- `services/working-days.ts` — Romanian holidays, `addWorkingDays()`, `isWorkingDay()`
- `services/deadline-catalog.ts` — 18 `DeadlineTypeDef` entries across 6 categories
- `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)
- `components/notification-preferences.tsx` — Bell button + dialog with per-type toggles
- `components/registry-table.tsx` — `CompactNumber` component: single-letter company badge (B/U/S/G), direction arrow (↓ intrat / ↑ iesit), plain number

### Address Book — Flexible Contact Model

The Address Book supports both persons and institutions:

- **Flexible validation**: either `name` OR `company` required (not both mandatory)
- **Auto-type detection**: when only company is set via quick-create, type defaults to "institution"
- **ContactPerson sub-entities**: each has `name`, `department`, `role`, `email`, `phone`
- **Quick contact creation from Registratura**: inline dialog with name + company + phone + email
- **Display logic**: if no name, company shows as primary; if both, shows "Name (Company)"
- **Creatable types**: dropdown with defaults (client/supplier/institution/collaborator/internal) + user-created custom types

Key files:

- `modules/address-book/types.ts` — `AddressContact`, `ContactPerson` interfaces
- `modules/address-book/components/address-book-module.tsx` — Full UI (cards, detail dialog, form)
- `modules/address-book/hooks/use-contacts.ts` — Storage hook with search/filter
- `modules/address-book/services/vcard-export.ts` — vCard 3.0 export
- `modules/registratura/components/quick-contact-dialog.tsx` — Quick create from registry

### PDF Compression — Dual Mode (Local + Cloud)

Two compression routes, both with streaming upload support for large files (tested up to 287MB):

- **Local (qpdf)**: lossless structural optimization — stream compression, object dedup, linearization. Safe, no font corruption. Typical reduction: 3-15%.
- **Cloud (iLovePDF API)**: lossy image re-compression via iLovePDF REST API. Levels: extreme/recommended/low. Typical reduction: 50-91%. Requires `ILOVEPDF_PUBLIC_KEY` env var.

**Architecture** (zero-memory for any file size):
1. `parseMultipartUpload()` streams request body to disk (constant 64KB memory)
2. Scans raw file for multipart boundaries using `findInFile()` with 64KB sliding window
3. Stream-copies PDF bytes to separate file
4. Route handler processes (qpdf exec or iLovePDF API) and streams response back

**Critical gotchas**:
- Middleware body buffering: `api/compress-pdf` routes are **excluded from middleware matcher** (middleware buffers entire body at 10MB default)
- Auth: route-level `requireAuth()` instead of middleware (in `auth-check.ts`)
- Unicode filenames: `Content-Disposition` header uses `encodeURIComponent()` to avoid ByteString errors with Romanian chars (Ș, Ț, etc.)
- Ghostscript `-sDEVICE=pdfwrite` destroys font encodings — **never use GS for compression**, only qpdf

Key files:

- `app/api/compress-pdf/parse-upload.ts` — Streaming multipart parser (zero memory)
- `app/api/compress-pdf/extreme/route.ts` — qpdf local compression
- `app/api/compress-pdf/cloud/route.ts` — iLovePDF API integration
- `app/api/compress-pdf/auth-check.ts` — Shared auth for routes excluded from middleware

### Email Notifications (Brevo SMTP)

Platform-level notification service for daily email digests:

- **Brevo SMTP relay** via nodemailer (port 587, STARTTLS)
- **N8N cron**: weekdays 8:00 → POST `/api/notifications/digest` with Bearer token
- **Per-user preferences**: stored in KeyValueStore (`notifications` namespace), toggle global opt-out + 3 notification types
- **Digest content**: urgent deadlines (<=5 days), overdue deadlines, expiring documents (CU/AC)
- **HTML email**: inline-styled table layout, color-coded rows (red/yellow/blue), per-company grouping
- **Sender**: "Alerte Termene" &lt;noreply@beletage.ro&gt;, test mode via `?test=true` query param

Key files:

- `src/core/notifications/types.ts` — `NotificationType`, `NotificationPreference`, `DigestSection`, `DigestItem`
- `src/core/notifications/email-service.ts` — Nodemailer transport singleton (Brevo SMTP)
- `src/core/notifications/notification-service.ts` — `runDigest()`, `buildCompanyDigest()`, `renderDigestHtml()`, preference CRUD
- `src/app/api/notifications/digest/route.ts` — POST endpoint (N8N cron, Bearer auth)
- `src/app/api/notifications/preferences/route.ts` — GET/PUT (user session auth)

### 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: `satra` — 10.10.10.166 (Ubuntu, app server)

| Service                 | Port                   | Purpose                             |
| ----------------------- | ---------------------- | ----------------------------------- |
| **ArchiTools**          | 3000                   | This app (tools.beletage.ro)        |
| **Gitea**               | 3002                   | Git hosting (git.beletage.ro)       |
| **PostgreSQL**          | 5432                   | App database (Prisma ORM)           |
| **Portainer CE**        | 9000                   | Docker management + deploy          |
| **Uptime Kuma**         | 3001                   | Service monitoring                  |
| **MinIO**               | 9002 (API) / 9003 (UI) | Object storage                      |
| **Authentik**           | 9100                   | SSO (auth.beletage.ro) — **active** |
| **N8N**                 | 5678                   | Workflow automation (daily digest)  |
| **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                            |

### Server: `proxy` — 10.10.10.199 (Traefik reverse proxy)

| Config                  | Path / Value                             |
| ----------------------- | ---------------------------------------- |
| **Static config**       | `/opt/traefik/traefik.yml`               |
| **Dynamic configs**     | `/opt/traefik/dynamic/` (file provider, `watch: true`) |
| **ArchiTools route**    | `/opt/traefik/dynamic/tools.yml`         |
| **SSL**                 | Let's Encrypt ACME, HTTP challenge       |
| **Timeouts**            | `readTimeout: 600s`, `writeTimeout: 600s`, `idleTimeout: 600s` on `websecure` entrypoint |
| **Response forwarding** | `flushInterval: 100ms` (streaming support) |

**IMPORTANT**: Default Traefik v2.11+ has 60s `readTimeout` — breaks large file uploads. Must set explicitly in static config.

### Deployment Pipeline

```
git push origin main
  → Gitea webhook fires
    → Portainer CE: Stacks → architools → "Pull and redeploy"
      → Toggle "Re-pull image and redeploy" ON → click "Update"
        → Portainer re-clones git repo + Docker multi-stage build (~2 min)
          → Container starts on :3000
            → Traefik routes tools.beletage.ro → http://10.10.10.166:3000
```

**Portainer CE deploy**: NOT automatic. Must manually click "Pull and redeploy" in Portainer UI after each push. The stack is configured from git repo `http://10.10.10.166:3002/gitadmin/ArchiTools`.

### Docker

- `Dockerfile`: 3-stage build (deps → builder → runner), `node:22-alpine`, non-root user
- Runner stage installs: `gdal gdal-tools ghostscript qpdf` (for PDF compression, GIS)
- `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<string, T>[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/<name>/
├── components/     # React components
├── hooks/          # Custom hooks (use-<name>.ts)
├── services/       # Business logic (pure functions)
├── types.ts        # TypeScript interfaces
├── config.ts       # ModuleConfig metadata
└── index.ts        # Public exports
```

### Middleware & Large Upload Routes

- Next.js middleware buffers the **entire request body** even if it only reads cookies/headers
- Default middleware body limit is 10MB — any upload route handling large files MUST be excluded
- Excluded routes pattern in `src/middleware.ts` matcher: `api/auth|api/notifications/digest|api/compress-pdf`
- Excluded routes handle auth via `requireAuth()` helper (`src/app/api/compress-pdf/auth-check.ts`)
- To add a new large-upload route: (1) add to middleware matcher exclusion, (2) add `requireAuth()` call in route handler
- `next.config.ts` has `experimental: { middlewareClientMaxBodySize: '500mb' }` but this is unreliable with `output: 'standalone'`

### 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                  |
| **Email Notifications** | ✅ Implemented      | Brevo SMTP daily digest, `/api/notifications/digest` + `/preferences`, N8N cron trigger    |
| **N8N automations**  | ✅ Active (digest cron) | Daily digest cron `0 8 * * 1-5`, Bearer token auth, future: backups, workflows             |
| **iLovePDF API**     | ✅ Active              | Cloud PDF compression, `ILOVEPDF_PUBLIC_KEY` env, free tier 250 files/month                |
| **qpdf**             | ✅ Active              | Local lossless PDF optimization, installed in Docker image (`apk add qpdf`)                |

---

## 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/<name>/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                      |
