# ArchiTools — System Architecture
## 1. Platform Overview
ArchiTools is a modular internal web dashboard platform built for a group of architecture, urban design, and engineering companies based in Cluj-Napoca, Romania:
- **Beletage SRL** — architecture office
- **Urban Switch SRL** — architecture and urban projects
- **Studii de Teren SRL** — engineering, surveying, GIS, technical studies
The platform centralizes daily operational tools: document registries, generators, templates, inventories, AI-assisted workflows, and technical utilities. It replaces scattered standalone HTML tools and manual processes with a unified, themeable, module-driven dashboard.
**Key constraints:**
- Internal-first deployment (external/guest access planned for later phases)
- Romanian UI labels; English code and comments
- On-premise Docker deployment behind reverse proxy
- localStorage as initial persistence layer, abstracted for future database/object store migration
- Must function as a **module platform**, not a monolithic application
---
## 2. High-Level Architecture
```
┌─────────────────────────────────────────────────────────────────────┐
│ NGINX PROXY MANAGER │
│ (TLS termination, routing) │
└──────────────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ DOCKER CONTAINER (Next.js) │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ PRESENTATION LAYER │ │
│ │ App Shell │ Sidebar │ Theme │ i18n │ Module Routes │ │
│ └──────────────────────────┬────────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────┴────────────────────────────────────┐ │
│ │ MODULE LAYER │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │Registra- │ │ Email │ │ Word XML │ │ Prompt │ ... │ │
│ │ │ tura │ │Signature │ │Generator │ │Generator │ │ │
│ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │
│ │ │ │ │ │ │ │
│ └───────┼─────────────┼────────────┼─────────────┼──────────────┘ │
│ │ │ │ │ │
│ ┌───────┴─────────────┴────────────┴─────────────┴──────────────┐ │
│ │ CORE SERVICES LAYER │ │
│ │ │ │
│ │ Module Registry │ Feature Flags │ Storage Abstraction │ │
│ │ Tagging System │ i18n Engine │ Theme Provider │ │
│ │ Auth Stub │ Navigation │ Config │ │
│ └──────────────────────────┬────────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────┴────────────────────────────────────┐ │
│ │ STORAGE LAYER │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ localStorage │ │ MinIO │ │ Database │ │ │
│ │ │ (current) │ │ (planned) │ │ (planned) │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
│
┌──────────────────┼──────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌──────────────┐ ┌──────────────┐
│ Authentik │ │ MinIO │ │ N8N │
│ (SSO) │ │ (obj store) │ │ (automation) │
└─────────────┘ └──────────────┘ └──────────────┘
```
---
## 3. Core Architecture Principles
### 3.1 Module Platform, Not Monolith
The application is a **platform that hosts modules**. The shell (layout, sidebar, theme, navigation) exists to load and present modules. No module is assumed to exist at build time — the system must function with zero modules enabled.
### 3.2 Module Isolation
Each module owns its:
- Route subtree (`/app/(modules)/[module-name]/`)
- Business logic (`/modules/[module-name]/`)
- Types, services, hooks, and components
- Storage namespace (scoped key prefix)
- Configuration entry in the module registry
Modules must never import from another module's internal directories. Cross-module communication happens exclusively through core services (tagging system, storage abstraction, shared hooks).
### 3.3 Removability
Disabling a module via feature flag must not produce build errors, runtime errors, or broken navigation. This is enforced by:
- Config-driven navigation (only enabled modules appear)
- Dynamic imports for module routes
- No direct cross-module imports
- Feature flag guards at route and component boundaries
### 3.4 Storage Independence
No module or component may call `localStorage`, `sessionStorage`, or any browser storage API directly. All persistence flows through the storage abstraction layer, which resolves to the active adapter at runtime.
### 3.5 Presentation/Logic Separation
UI components receive data via props and hooks. Business logic lives in `services/` (pure functions) and `hooks/` (stateful logic). Components do not contain data transformation, validation, or persistence logic.
---
## 4. Layer Architecture
```
┌─────────────────────────────────────────────────────┐
│ PRESENTATION LAYER │
│ Next.js App Router pages, layouts, UI components │
│ shadcn/ui primitives, Tailwind styling │
│ Theme provider, i18n labels │
├─────────────────────────────────────────────────────┤
│ MODULE LAYER │
│ Module-specific components, hooks, services │
│ Module config, types, route pages │
│ Isolated per module, lazy-loadable │
├─────────────────────────────────────────────────────┤
│ CORE SERVICES LAYER │
│ Module registry, feature flags, navigation │
│ Storage abstraction, tagging, auth stub │
│ i18n engine, theme system, config │
├─────────────────────────────────────────────────────┤
│ STORAGE / INTEGRATION LAYER │
│ Storage adapters (localStorage, MinIO, DB, API) │
│ External service clients │
│ Environment configuration │
└─────────────────────────────────────────────────────┘
```
### Layer Rules
| Layer | May Import From | Must Not Import From |
|-------|----------------|---------------------|
| Presentation | Module Layer, Core Services, Shared | — |
| Module Layer | Core Services, Shared | Other modules |
| Core Services | Shared, Config | Module Layer, Presentation |
| Storage/Integration | Config only | Everything else |
---
## 5. Runtime Architecture
### 5.1 Next.js App Router
The application uses Next.js 15 with the App Router. The routing structure:
```
app/
├── layout.tsx → Root layout: providers, shell wrapper
├── page.tsx → Dashboard home (widget grid)
├── globals.css → Tailwind base + custom tokens
└── (modules)/ → Route group (no URL segment)
├── registratura/
│ ├── page.tsx → Module entry page
│ └── [id]/
│ └── page.tsx → Detail view
├── email-signature/
│ └── page.tsx
└── ...
```
### 5.2 Client-Side Primary, SSR Where Needed
The platform is primarily a client-side interactive application. Most module pages use `"use client"` directives because they:
- Manage complex form state
- Interact with browser storage
- Require immediate user feedback
- Handle drag-and-drop, clipboard, and other browser APIs
Server-side rendering is used for:
- The shell layout (static structure, fast first paint)
- Metadata generation
- Any future API routes serving data to external consumers
### 5.3 Provider Stack
The root layout wraps the application in a provider stack:
```
{children}
```
Each provider is independent and can be replaced or extended without affecting others.
---
## 6. Module Isolation Model
### 6.1 Module Structure
Every module follows a standard directory structure:
```
src/modules/[module-name]/
├── components/ # Module-specific React components
├── hooks/ # Module-specific React hooks
├── services/ # Pure business logic functions
├── types.ts # TypeScript interfaces and types
├── config.ts # Module metadata for the registry
└── index.ts # Public API barrel export
```
### 6.2 Module Registration
Each module exports a `ModuleConfig` object:
```typescript
interface ModuleConfig {
id: string; // Unique identifier (kebab-case)
name: string; // Romanian display name
description: string; // Romanian description
icon: string; // Lucide icon name
route: string; // Base route path
category: ModuleCategory; // Grouping for navigation
enabled: boolean; // Default enabled state
featureFlag: string; // Flag key in feature flag system
requiredRole?: UserRole; // Minimum role (future use)
visibility?: Visibility; // internal | admin | public
version: string; // Semver
storageNamespace: string; // Storage key prefix
}
```
The central module registry (`src/config/modules.ts`) imports all module configs and provides them to the navigation system and feature flag guards.
### 6.3 Module Lifecycle
```
1. Module config registered in modules.ts
2. Feature flag checked at runtime
3. If enabled: route is accessible, nav item visible
4. Module page loads (dynamic import possible)
5. Module initializes its hooks/services
6. Module reads/writes through storage abstraction
7. If disabled: route returns redirect/404, nav item hidden
```
---
## 7. Core Systems Overview
### 7.1 Module Registry
**Location:** `src/core/module-registry/`
Central catalog of all available modules. Provides:
- List of all registered modules with metadata
- Lookup by ID, route, or category
- Filtering by enabled state, visibility, role
- Module category grouping for navigation
The registry is the single source of truth for what modules exist. Navigation, routing guards, and the dashboard widget grid all read from it.
### 7.2 Feature Flags
**Location:** `src/core/feature-flags/`
Controls module activation and experimental feature visibility.
```typescript
interface FeatureFlag {
key: string;
enabled: boolean;
scope: 'module' | 'feature' | 'experiment';
requiredRole?: UserRole;
description: string;
}
```
Flag resolution order:
1. Environment variable override (`NEXT_PUBLIC_FLAG_*`)
2. Runtime config (`src/config/flags.ts`)
3. Default from module config
Flags are checked via the `useFeatureFlag(key)` hook and the `` component wrapper.
### 7.3 Storage Abstraction
**Location:** `src/core/storage/`
All data persistence flows through a `StorageService` interface:
```typescript
interface StorageService {
get(namespace: string, key: string): Promise;
set(namespace: string, key: string, value: T): Promise;
delete(namespace: string, key: string): Promise;
list(namespace: string): Promise;
clear(namespace: string): Promise;
}
```
**Adapters:**
| Adapter | Status | Use Case |
|---------|--------|----------|
| `LocalStorageAdapter` | Current | Browser-local persistence, demo/dev mode |
| `MinIOAdapter` | Planned | File and object storage (signatures, templates) |
| `DatabaseAdapter` | Planned | Structured data (registry entries, inventory) |
| `APIAdapter` | Planned | External service delegation |
The active adapter is resolved at startup from environment configuration. Modules never know which adapter is active.
**Namespace isolation:** Each module operates within its own namespace (e.g., `registratura:entries`, `password-vault:credentials`). Modules cannot read or write to another module's namespace without explicit cross-module service mediation.
### 7.4 Tagging System
**Location:** `src/core/tagging/`
A cross-module tagging service used by multiple modules to categorize and link entities.
Tags are structured objects:
```typescript
interface Tag {
id: string;
label: string; // Romanian display label
category: TagCategory; // project | client | domain | custom
color?: string;
metadata?: Record;
createdAt: string;
}
```
The tagging system provides:
- Tag CRUD operations (stored via storage abstraction)
- Tag selector component (shared UI)
- Tag filtering and search
- Tag usage tracking across modules
Modules that use tags: Registratura, Prompt Generator, Word Templates, Digital Signatures, IT Inventory, Address Book.
### 7.5 Internationalization (i18n)
**Location:** `src/core/i18n/`
Current implementation: Romanian-only with structured label access for future multi-language support.
Labels are organized by module namespace:
```typescript
const labels = {
common: {
save: 'Salvează',
cancel: 'Anulează',
delete: 'Șterge',
search: 'Caută',
// ...
},
registratura: {
title: 'Registratură',
newEntry: 'Înregistrare nouă',
// ...
},
};
```
Access pattern: `useLabel('registratura.newEntry')` or ``.
The system is designed so that adding a second language requires only adding translation files, not changing component code.
### 7.6 Theme System
**Location:** `src/core/theme/`
Dark/light theme support using CSS custom properties and Tailwind's `dark:` variant.
Design tokens:
- Background and surface colors
- Text hierarchy (primary, secondary, muted)
- Border and divider colors
- Accent colors per company (Beletage, Urban Switch, Studii de Teren)
- Semantic colors (success, warning, error, info)
Theme preference is persisted in storage and respects system preference as default. The theme provider exposes `useTheme()` with `theme`, `setTheme`, and `toggleTheme`.
Visual style: professional, technical, card-based dashboard. No playful or consumer-oriented aesthetics.
### 7.7 Auth Stub
**Location:** `src/core/auth/`
Current state: no authentication enforced (internal network only).
The auth module provides a stub interface that modules can code against:
```typescript
interface AuthContext {
user: User | null;
role: UserRole; // 'admin' | 'user' | 'guest'
isAuthenticated: boolean;
company: CompanyId | null;
permissions: string[];
}
```
In the current phase, `AuthContext` returns a default internal user with admin role. When Authentik SSO integration is implemented, the auth module will resolve real user identity from SSO tokens without any module code changes.
Data model fields (`visibility`, `requiredRole`, `createdBy`) are included from day one so that enabling auth does not require data migration.
---
## 8. External Integration Points
### 8.1 Current Infrastructure
ArchiTools runs alongside existing services on the internal network:
| Service | Integration Type | Purpose |
|---------|-----------------|---------|
| **Authentik** | Future SSO provider | User authentication and role assignment |
| **MinIO** | Future storage adapter | Object/file storage for documents, signatures, templates |
| **N8N** | Future webhook/API | Workflow automation (document processing, notifications) |
| **Gitea** | Development | Source code hosting |
| **Stirling PDF** | Dashboard link | PDF manipulation (external tool link) |
| **IT-Tools** | Dashboard link | Technical utilities (external tool link) |
| **Filebrowser** | Dashboard link | File management (external tool link) |
| **Uptime Kuma** | Dashboard widget | Service health status |
| **Netdata** | Dashboard widget | Server performance metrics |
### 8.2 Integration Patterns
**Dashboard links:** External tools appear as navigation entries or dashboard widgets with `target="_blank"` links. No embedding or API integration needed.
**Dashboard widgets:** Services like Uptime Kuma and Netdata can expose status endpoints or embed iframes for health/monitoring widgets on the dashboard home.
**Storage integration (MinIO):** When the MinIO adapter is implemented, modules that manage files (Digital Signatures, Word Templates) will store binary assets in MinIO buckets while keeping metadata in the primary storage.
**Automation integration (N8N):** Modules can trigger N8N webhooks for automated workflows. Example: Registratura creates a new entry, triggering an N8N workflow that sends a notification or generates a document.
**SSO integration (Authentik):** The auth stub will be replaced with an Authentik OIDC client. The middleware layer will validate tokens and populate `AuthContext`. No module code changes required.
---
## 9. Data Flow Patterns
### 9.1 Module Data Read
```
User action
→ Component calls hook (e.g., useRegistryEntries())
→ Hook calls service function (e.g., getEntries())
→ Service calls StorageService.get(namespace, key)
→ StorageService resolves active adapter
→ Adapter reads from storage backend
→ Data returns up the chain
→ Hook updates state
→ Component re-renders
```
### 9.2 Module Data Write
```
User submits form
→ Component calls hook mutation (e.g., createEntry(data))
→ Hook validates via service (e.g., validateEntry(data))
→ Service calls StorageService.set(namespace, key, data)
→ Adapter writes to storage backend
→ Hook updates local state / invalidates cache
→ Component re-renders with new data
```
### 9.3 Cross-Module Data (via Tagging)
```
User tags an entity in Module A
→ Module A calls TaggingService.addTag(entityId, tagId)
→ Tag association stored in tagging namespace
User filters by tag in Module B
→ Module B calls TaggingService.getEntitiesByTag(tagId)
→ Returns entity IDs across modules
→ Module B fetches its own entities matching those IDs
```
### 9.4 Feature Flag Check
```
Route or component renders
→
→ useFeatureFlag('module.registratura')
→ Checks env override → config → default
→ Returns boolean
→ Children render or fallback shown
```
---
## 10. Deployment Architecture
### 10.1 Container Structure
```
┌──────────────────────────────────────────────────┐
│ Ubuntu Server (on-premise) │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ Docker (via Portainer) │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────────────┐ │ │
│ │ │ ArchiTools │ │ Other containers │ │ │
│ │ │ (Next.js) │ │ (Authentik, MinIO, │ │ │
│ │ │ Port: 3000 │ │ N8N, Gitea, etc.) │ │ │
│ │ └──────┬───────┘ └──────────────────────┘ │ │
│ │ │ │ │
│ └─────────┼────────────────────────────────────┘ │
│ │ │
│ ┌─────────┴─────────────────────────────────────┐ │
│ │ Nginx Proxy Manager │ │
│ │ tools.internal.domain → localhost:3000 │ │
│ └────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
```
### 10.2 Docker Configuration
**Dockerfile:** Multi-stage build.
1. **deps stage** — installs Node.js dependencies
2. **build stage** — runs `next build`, produces standalone output
3. **runtime stage** — minimal Node.js image, copies standalone build, exposes port 3000
**docker-compose.yml:** Single service definition for ArchiTools. Environment variables passed from `.env` file. Optional volume mounts for persistent data if needed beyond localStorage.
### 10.3 Environment Variables
```
# Application
NEXT_PUBLIC_APP_URL=https://tools.internal.domain
NEXT_PUBLIC_APP_ENV=production
# Feature flags (override defaults)
NEXT_PUBLIC_FLAG_MODULE_REGISTRATURA=true
NEXT_PUBLIC_FLAG_MODULE_AI_CHAT=false
# Future: Storage backend
STORAGE_BACKEND=localStorage
MINIO_ENDPOINT=minio.internal.domain
MINIO_ACCESS_KEY=...
MINIO_SECRET_KEY=...
# Future: Auth
AUTHENTIK_ISSUER=https://auth.internal.domain
AUTHENTIK_CLIENT_ID=...
AUTHENTIK_CLIENT_SECRET=...
```
### 10.4 Build and Deploy Flow
```
Developer pushes to Gitea
→ (future: CI pipeline builds image)
→ Docker image built (manual or Watchtower auto-update)
→ Portainer deploys/restarts container
→ Nginx Proxy Manager routes traffic
→ Users access via internal domain
```
---
## 11. Scalability Considerations
### 11.1 Current Scale
- **Users:** ~5–20 internal staff across three companies
- **Data volume:** Low (hundreds to low thousands of records per module)
- **Concurrency:** Minimal (localStorage is per-browser, no shared state conflicts)
### 11.2 Growth Path
| Concern | Current | Growth Path |
|---------|---------|-------------|
| Data persistence | localStorage (per-browser) | Database + MinIO (shared, centralized) |
| Authentication | None (network trust) | Authentik SSO with RBAC |
| Multi-user data | Isolated per browser | Centralized with user ownership |
| File storage | Not supported | MinIO buckets per module |
| Search | Client-side filter | Server-side indexed search |
| API access | None | Next.js API routes for external consumers |
| Automation | Manual | N8N webhooks triggered by module events |
### 11.3 Module Scaling
New modules are added by:
1. Creating the module directory structure
2. Registering the module config
3. Adding the feature flag
4. Creating the route pages
No changes to the shell, navigation, or other modules are required. The navigation rebuilds itself from the registry.
---
## 12. Security Boundaries
### 12.1 Current Phase: Internal Network Trust
```
┌─────────────────────────────────────────────┐
│ Internal Network │
│ │
│ ┌──────────┐ ┌──────────────────────┐ │
│ │ Users │────▶│ ArchiTools │ │
│ │ (trusted) │ │ (no auth required) │ │
│ └──────────┘ └──────────────────────┘ │
│ │
│ Security: network-level only │
│ Data: browser-local, no shared secrets │
│ Risk: low (internal, trusted users) │
└─────────────────────────────────────────────┘
```
**Current security model:**
- Network perimeter security via Crowdsec and firewall rules
- No application-level authentication
- No sensitive data in localStorage (password vault uses demo-grade encryption)
- No external API endpoints exposed
- All data stays in the user's browser
### 12.2 Future Phase: SSO + Role-Based Access
```
┌──────────────────────────────────────────────────────────┐
│ │
│ ┌──────────┐ ┌────────────┐ ┌──────────────────┐│
│ │ Users │───▶│ Authentik │───▶│ ArchiTools ││
│ │(internal/ │ │ (SSO) │ │ (auth enforced) ││
│ │ external) │ └────────────┘ └──────────────────┘│
│ └──────────┘ │
│ │
│ Security: SSO + RBAC + module permissions │
│ Data: centralized DB + MinIO with access control │
│ Roles: admin, user, guest │
│ Visibility: per-field, per-module, per-company │
└──────────────────────────────────────────────────────────┘
```
**Planned security layers:**
- Authentik OIDC authentication (SSO)
- Role-based module access (admin, user, guest)
- Company-scoped data visibility
- Per-field visibility metadata (internal, admin, public)
- API route protection via middleware token validation
- Audit logging for sensitive operations
**Design-for-security decisions made now:**
- All data models include `visibility` and `createdBy` fields
- Module configs include `requiredRole` field
- Feature flags support role-based activation
- Auth context interface defined (stubbed with defaults)
- Storage namespace isolation prevents cross-module data leaks
---
## Appendix A: Technology Decisions
| Decision | Choice | Rationale |
|----------|--------|-----------|
| Framework | Next.js 15 (App Router) | Modern React with file-based routing, SSR capability, API routes |
| Language | TypeScript | Type safety across modules, better refactorability |
| Styling | Tailwind CSS | Utility-first, consistent with shadcn/ui, theme support |
| Component library | shadcn/ui | Copy-paste components, full control, professional aesthetic |
| Deployment | Docker | Consistent with existing infrastructure (Portainer) |
| Initial storage | localStorage | Zero infrastructure, immediate development start |
| Storage pattern | Adapter abstraction | Allows migration without module changes |
| Auth pattern | Stub with interface | Enables SSO integration without refactoring |
## Appendix B: Module Catalog
| Module | ID | Category | Status |
|--------|----|----------|--------|
| Dashboard | `dashboard` | Core | Planned |
| Registratura | `registratura` | Registry | Planned |
| Email Signature Generator | `email-signature` | Generators | Planned (legacy exists) |
| Word XML Generators | `word-xml` | Generators | Planned (legacy exists) |
| Digital Signatures & Stamps | `digital-signatures` | Assets | Planned |
| Password Vault | `password-vault` | Security | Planned |
| IT Inventory | `it-inventory` | Infrastructure | Planned |
| Address Book | `address-book` | Contacts | Planned |
| Prompt Generator | `prompt-generator` | AI Tools | Planned |
| Word Template Library | `word-templates` | Templates | Planned |
| Tag Manager | `tag-manager` | Administration | Planned |
| Mini Utilities | `mini-utilities` | Tools | Planned |
| AI Chat | `ai-chat` | AI Tools | Planned |