Files
ArchiTools/CLAUDE.md
T
AI Assistant 974d06fff8 feat: add email notification system (Brevo SMTP + N8N daily digest)
- Add core notification service: types, email-service (nodemailer/Brevo SMTP), notification-service (digest builder, preference CRUD, HTML renderer)
- Add API routes: POST /api/notifications/digest (N8N cron, Bearer auth), GET/PUT /api/notifications/preferences (session auth)
- Add NotificationPreferences UI component (Bell button + dialog with per-type toggles) in Registratura toolbar
- Add 7 Brevo SMTP env vars to docker-compose.yml
- Update CLAUDE.md, ROADMAP.md, DATA-MODEL.md, SYSTEM-ARCHITECTURE.md, CONFIGURATION.md, DOCKER-DEPLOYMENT.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 01:12:36 +02:00

29 KiB

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

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
│   ├── <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)
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

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.tscreateTrackedDeadline(), 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

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

Key files:

  • src/core/notifications/types.tsNotificationType, NotificationPreference, DigestSection, DigestItem
  • src/core/notifications/email-service.ts — Nodemailer transport singleton (Brevo SMTP)
  • src/core/notifications/notification-service.tsrunDigest(), 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: 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 (daily digest cron)
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<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 unknownReact.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

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

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