Files
ArchiTools/docs/guides/CONFIGURATION.md
Marius Tarau 4c46e8bcdd Initial commit: ArchiTools modular dashboard platform
Complete Next.js 16 application with 13 fully implemented modules:
Email Signature, Word XML Generator, Registratura, Dashboard,
Tag Manager, IT Inventory, Address Book, Password Vault,
Mini Utilities, Prompt Generator, Digital Signatures,
Word Templates, and AI Chat.

Includes core platform systems (module registry, feature flags,
storage abstraction, i18n, theming, auth stub, tagging),
16 technical documentation files, Docker deployment config,
and legacy HTML tool reference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 12:50:25 +02:00

623 lines
22 KiB
Markdown

# Configuration Guide
> How ArchiTools is configured at build time, runtime, and per-module.
---
## Environment Variables
All environment variables are defined in `.env.local` for development and injected via Docker for production. The `.env.example` file in the repository root documents every variable:
```bash
# =============================================================================
# ArchiTools Environment Configuration
# =============================================================================
# Copy this file to .env.local for development.
# For Docker, pass variables via docker-compose.yml or Portainer.
# =============================================================================
# -----------------------------------------------------------------------------
# Application
# -----------------------------------------------------------------------------
NEXT_PUBLIC_APP_NAME=ArchiTools
NEXT_PUBLIC_APP_URL=http://localhost:3000
# Version displayed in footer/about. Set by CI or manually.
NEXT_PUBLIC_APP_VERSION=0.1.0
# -----------------------------------------------------------------------------
# Storage
# -----------------------------------------------------------------------------
# Active storage adapter: 'localStorage' | 'api'
NEXT_PUBLIC_STORAGE_ADAPTER=localStorage
# REST API storage backend (required when STORAGE_ADAPTER=api)
# STORAGE_API_URL=http://api.internal/storage
# MinIO object storage (server-side only, for file/binary storage)
# MINIO_ENDPOINT=minio.internal:9000
# MINIO_ACCESS_KEY=
# MINIO_SECRET_KEY=
# MINIO_BUCKET=architools
# MINIO_USE_SSL=false
# -----------------------------------------------------------------------------
# Authentication (future — Authentik SSO)
# -----------------------------------------------------------------------------
# AUTHENTIK_URL=https://auth.internal
# AUTHENTIK_CLIENT_ID=
# AUTHENTIK_CLIENT_SECRET=
# NEXTAUTH_URL=http://localhost:3000
# NEXTAUTH_SECRET=
# -----------------------------------------------------------------------------
# Feature Flags
# -----------------------------------------------------------------------------
# Comma-separated list of flag overrides. Format: flag_name=true/false
# Example: NEXT_PUBLIC_FLAGS_OVERRIDE=module_ai_chat=true,module_password_vault=false
NEXT_PUBLIC_FLAGS_OVERRIDE=
# -----------------------------------------------------------------------------
# External Services
# -----------------------------------------------------------------------------
# N8N webhook endpoint for automation triggers
# N8N_WEBHOOK_URL=https://n8n.internal/webhook
# Gitea API (for potential repo integration)
# GITEA_URL=https://git.internal
# GITEA_TOKEN=
# -----------------------------------------------------------------------------
# External Tool Links (displayed on dashboard)
# -----------------------------------------------------------------------------
# NEXT_PUBLIC_PORTAINER_URL=https://portainer.internal
# NEXT_PUBLIC_DOZZLE_URL=https://dozzle.internal
# NEXT_PUBLIC_NETDATA_URL=https://netdata.internal
# NEXT_PUBLIC_UPTIME_KUMA_URL=https://uptime.internal
# NEXT_PUBLIC_IT_TOOLS_URL=https://it-tools.internal
# NEXT_PUBLIC_STIRLING_PDF_URL=https://pdf.internal
# NEXT_PUBLIC_FILEBROWSER_URL=https://files.internal
# NEXT_PUBLIC_N8N_URL=https://n8n.internal
# NEXT_PUBLIC_GITEA_URL=https://git.internal
# NEXT_PUBLIC_MINIO_CONSOLE_URL=https://minio-console.internal
```
### Naming Rules
| Prefix | Scope | Access |
|---|---|---|
| `NEXT_PUBLIC_` | Client + Server | Bundled into client JS. Never put secrets here. |
| No prefix | Server only | Available in API routes, server components, middleware. |
**Never put credentials, API keys, or secrets in `NEXT_PUBLIC_` variables.** They are embedded in the JavaScript bundle and visible to anyone with browser DevTools.
---
## Module Configuration
**File:** `src/config/modules.ts`
Defines the module registry. Every module in the system is declared here. Modules not in this registry do not exist to the platform.
```typescript
// src/config/modules.ts
import type { LucideIcon } from 'lucide-react';
interface ModuleDefinition {
/** Unique module identifier. Matches the directory name under src/modules/. */
id: string;
/** Romanian display name shown in navigation and headers. */
label: string;
/** Short Romanian description for tooltips and dashboard cards. */
description: string;
/** Lucide icon component reference. */
icon: LucideIcon;
/** URL path segment. Module is accessible at /modules/{path}. */
path: string;
/** Storage namespace. Must match STORAGE-LAYER.md namespace table. */
namespace: string;
/** Feature flag that controls activation. References flags.ts. */
featureFlag: string;
/** Default enabled state when no flag override exists. */
defaultEnabled: boolean;
/** Minimum role required to see this module. */
minRole: Role;
/** Sort order in navigation sidebar. Lower = higher. */
order: number;
/** If true, module is loaded only when navigated to. */
lazy: boolean;
/** Which companies this module is relevant to. Empty = all. */
companies: CompanyId[];
}
export const MODULE_REGISTRY: ModuleDefinition[] = [
{
id: 'dashboard',
label: 'Panou Principal',
description: 'Tablou de bord cu widget-uri și acces rapid',
icon: LayoutDashboard,
path: 'dashboard',
namespace: 'dashboard',
featureFlag: 'module_dashboard',
defaultEnabled: true,
minRole: 'viewer',
order: 0,
lazy: false,
companies: [],
},
{
id: 'registratura',
label: 'Registratură',
description: 'Registru de intrări și ieșiri documente',
icon: BookOpen,
path: 'registratura',
namespace: 'registratura',
featureFlag: 'module_registratura',
defaultEnabled: true,
minRole: 'user',
order: 10,
lazy: true,
companies: [],
},
// ... remaining modules follow same pattern
];
```
### Adding a New Module
1. Create the module directory: `src/modules/{module-id}/`.
2. Add an entry to `MODULE_REGISTRY` in `src/config/modules.ts`.
3. Add a feature flag in `src/config/flags.ts`.
4. Add the namespace to the namespace table in the storage layer docs.
5. Create the App Router page: `src/app/modules/{path}/page.tsx`.
6. The navigation system and feature flag engine pick it up automatically.
---
## Feature Flag Configuration
**File:** `src/config/flags.ts`
```typescript
// src/config/flags.ts
interface FeatureFlag {
/** Flag identifier. Convention: module_{id} for module toggles, feature_{name} for features. */
id: string;
/** Romanian description. */
description: string;
/** Default value when no override exists. */
defaultValue: boolean;
/** If true, flag is only visible in admin settings. */
adminOnly: boolean;
/** If true, flag is experimental and shown with a warning badge. */
experimental: boolean;
}
export const FEATURE_FLAGS: FeatureFlag[] = [
// Module flags
{ id: 'module_dashboard', description: 'Panou principal', defaultValue: true, adminOnly: false, experimental: false },
{ id: 'module_registratura', description: 'Registratură', defaultValue: true, adminOnly: false, experimental: false },
{ id: 'module_email_signature', description: 'Generator semnătură email', defaultValue: true, adminOnly: false, experimental: false },
{ id: 'module_word_xml', description: 'Generatoare Word XML', defaultValue: true, adminOnly: false, experimental: false },
{ id: 'module_digital_signatures', description: 'Semnături și ștampile digitale', defaultValue: true, adminOnly: false, experimental: false },
{ id: 'module_password_vault', description: 'Seif parole partajat', defaultValue: true, adminOnly: true, experimental: false },
{ id: 'module_it_inventory', description: 'Inventar IT', defaultValue: true, adminOnly: false, experimental: false },
{ id: 'module_address_book', description: 'Agendă de contacte', defaultValue: true, adminOnly: false, experimental: false },
{ id: 'module_prompt_generator', description: 'Generator de prompturi AI', defaultValue: true, adminOnly: false, experimental: false },
{ id: 'module_word_templates', description: 'Șabloane Word', defaultValue: true, adminOnly: false, experimental: false },
{ id: 'module_tag_manager', description: 'Manager etichete', defaultValue: true, adminOnly: false, experimental: false },
{ id: 'module_mini_utilities', description: 'Mini utilitare', defaultValue: true, adminOnly: false, experimental: false },
{ id: 'module_ai_chat', description: 'Chat AI', defaultValue: false, adminOnly: false, experimental: true },
// Feature flags (non-module)
{ id: 'feature_dark_mode', description: 'Mod întunecat', defaultValue: true, adminOnly: false, experimental: false },
{ id: 'feature_export_import', description: 'Export/import date', defaultValue: true, adminOnly: true, experimental: false },
{ id: 'feature_cross_tab_sync', description: 'Sincronizare între tab-uri', defaultValue: true, adminOnly: false, experimental: false },
{ id: 'feature_infra_links', description: 'Linkuri infrastructură pe panou',defaultValue: true, adminOnly: false, experimental: false },
];
```
### Flag Resolution Order
1. **Environment override** (`NEXT_PUBLIC_FLAGS_OVERRIDE`): Highest priority. Parsed as comma-separated `key=value` pairs.
2. **Runtime override** (stored in `system` namespace under key `flag-overrides`): Set through admin UI. Persists across sessions.
3. **Default value** (`defaultValue` in `flags.ts`): Lowest priority. Used when no override exists.
```typescript
// src/lib/flags/resolve.ts
function resolveFlag(flagId: string): boolean {
// 1. Environment override
const envOverrides = parseEnvOverrides(process.env.NEXT_PUBLIC_FLAGS_OVERRIDE);
if (flagId in envOverrides) return envOverrides[flagId];
// 2. Runtime override (from storage)
const runtimeOverrides = getRuntimeOverrides(); // from system namespace
if (flagId in runtimeOverrides) return runtimeOverrides[flagId];
// 3. Default
const flag = FEATURE_FLAGS.find(f => f.id === flagId);
return flag?.defaultValue ?? false;
}
```
### Usage in Components
```typescript
import { useFeatureFlag } from '@/lib/flags/hooks';
function SomeComponent() {
const aiChatEnabled = useFeatureFlag('module_ai_chat');
if (!aiChatEnabled) return null;
return <AIChatModule />;
}
```
---
## Navigation Configuration
**File:** `src/config/navigation.ts`
Navigation is derived from the module registry. No separate navigation config is maintained. The navigation system reads `MODULE_REGISTRY`, filters by feature flags and role, sorts by `order`, and renders the sidebar.
```typescript
// src/config/navigation.ts
import { MODULE_REGISTRY } from './modules';
interface NavGroup {
label: string;
modules: string[]; // Module IDs belonging to this group
}
/**
* Groups organize modules in the sidebar.
* Modules not listed in any group appear under "Altele" (Others).
*/
export const NAV_GROUPS: NavGroup[] = [
{
label: 'Principal',
modules: ['dashboard'],
},
{
label: 'Documente',
modules: ['registratura', 'word-templates', 'word-xml', 'email-signature'],
},
{
label: 'Resurse',
modules: ['address-book', 'digital-signatures', 'password-vault', 'it-inventory'],
},
{
label: 'Instrumente',
modules: ['prompt-generator', 'ai-chat', 'mini-utilities'],
},
{
label: 'Administrare',
modules: ['tag-manager'],
},
];
```
### External Links
Infrastructure tool links are configured via environment variables and displayed in a separate sidebar section or dashboard widget:
```typescript
// src/config/navigation.ts
interface ExternalLink {
label: string;
envVar: string; // Environment variable holding the URL
icon: LucideIcon;
category: 'infra' | 'dev' | 'tools';
}
export const EXTERNAL_LINKS: ExternalLink[] = [
{ label: 'Portainer', envVar: 'NEXT_PUBLIC_PORTAINER_URL', icon: Container, category: 'infra' },
{ label: 'Dozzle', envVar: 'NEXT_PUBLIC_DOZZLE_URL', icon: ScrollText, category: 'infra' },
{ label: 'Netdata', envVar: 'NEXT_PUBLIC_NETDATA_URL', icon: Activity, category: 'infra' },
{ label: 'Uptime Kuma', envVar: 'NEXT_PUBLIC_UPTIME_KUMA_URL', icon: HeartPulse, category: 'infra' },
{ label: 'Gitea', envVar: 'NEXT_PUBLIC_GITEA_URL', icon: GitBranch, category: 'dev' },
{ label: 'MinIO', envVar: 'NEXT_PUBLIC_MINIO_CONSOLE_URL', icon: Database, category: 'dev' },
{ label: 'IT-Tools', envVar: 'NEXT_PUBLIC_IT_TOOLS_URL', icon: Wrench, category: 'tools' },
{ label: 'Stirling PDF', envVar: 'NEXT_PUBLIC_STIRLING_PDF_URL', icon: FileText, category: 'tools' },
{ label: 'N8N', envVar: 'NEXT_PUBLIC_N8N_URL', icon: Workflow, category: 'tools' },
{ label: 'Filebrowser', envVar: 'NEXT_PUBLIC_FILEBROWSER_URL', icon: FolderOpen, category: 'tools' },
];
```
Links with no URL configured (empty env var) are hidden automatically.
---
## Company Configuration
**File:** `src/config/companies.ts`
Static company data. Updated rarely and only by developers.
```typescript
// src/config/companies.ts
import type { CompanyId, Company } from '@/types/company';
export const COMPANIES: Record<CompanyId, Company> = {
beletage: {
id: 'beletage',
name: 'Beletage SRL',
shortName: 'Beletage',
cui: 'RO12345678', // replace with real CUI
address: '...',
email: 'office@beletage.ro',
phone: '...',
},
'urban-switch': {
id: 'urban-switch',
name: 'Urban Switch SRL',
shortName: 'Urban Switch',
cui: 'RO23456789',
address: '...',
email: 'office@urbanswitch.ro',
phone: '...',
},
'studii-de-teren': {
id: 'studii-de-teren',
name: 'Studii de Teren SRL',
shortName: 'Studii de Teren',
cui: 'RO34567890',
address: '...',
email: 'office@studiideteren.ro',
phone: '...',
},
group: {
id: 'group',
name: 'Grup Beletage',
shortName: 'Grup',
cui: '',
},
};
export const COMPANY_IDS: CompanyId[] = ['beletage', 'urban-switch', 'studii-de-teren'];
export const ALL_COMPANY_IDS: CompanyId[] = [...COMPANY_IDS, 'group'];
```
`COMPANY_IDS` excludes `'group'` for UI dropdowns where a real company selection is required. `ALL_COMPANY_IDS` includes it for contexts where "all companies" is valid.
---
## Theme Configuration
**File:** `src/config/theme.ts`
Theme tokens extend the shadcn/ui and Tailwind defaults.
```typescript
// src/config/theme.ts
export const THEME_CONFIG = {
/** Default theme on first visit. User preference is stored in system namespace. */
defaultTheme: 'light' as 'light' | 'dark' | 'system',
/** Company brand colors for badges, indicators, and charts. */
companyColors: {
beletage: { primary: '#1E3A5F', accent: '#4A90D9' },
'urban-switch': { primary: '#2D5F3E', accent: '#6BBF8A' },
'studii-de-teren': { primary: '#5F4B1E', accent: '#D9A44A' },
group: { primary: '#374151', accent: '#6B7280' },
},
/** Tag category default colors. */
tagCategoryColors: {
project: '#3B82F6',
client: '#8B5CF6',
phase: '#F59E0B',
type: '#10B981',
priority: '#EF4444',
domain: '#6366F1',
custom: '#6B7280',
},
} as const;
```
Theme switching is handled by `next-themes` (shadcn/ui standard). The user's preference is stored in the `system` storage namespace under the key `theme-preference`.
### Tailwind Integration
Company colors and tag colors are registered in `tailwind.config.ts` as extended colors:
```typescript
// tailwind.config.ts (relevant excerpt)
theme: {
extend: {
colors: {
beletage: { DEFAULT: '#1E3A5F', accent: '#4A90D9' },
urbanswitch: { DEFAULT: '#2D5F3E', accent: '#6BBF8A' },
studiideteren: { DEFAULT: '#5F4B1E', accent: '#D9A44A' },
},
},
},
```
---
## Build-Time vs Runtime Configuration
| Configuration Type | When Resolved | How Set | Changeable Without Rebuild |
|---|---|---|---|
| `NEXT_PUBLIC_*` env vars | Build time (bundled into JS) | `.env.local`, Docker build args | No (requires rebuild) |
| Server-only env vars | Runtime (read on each request) | Docker env vars, `.env.local` | Yes |
| Feature flag defaults | Build time (in `flags.ts`) | Source code | No |
| Feature flag overrides (env) | Build time (via `NEXT_PUBLIC_FLAGS_OVERRIDE`) | Env var | No |
| Feature flag overrides (runtime) | Runtime (from storage) | Admin UI | Yes |
| Module registry | Build time (in `modules.ts`) | Source code | No |
| Company data | Build time (in `companies.ts`) | Source code | No |
| Theme preference | Runtime (from storage) | User toggle | Yes |
| External tool URLs | Build time (via `NEXT_PUBLIC_*`) | Env vars | No |
### Making `NEXT_PUBLIC_` Variables Runtime-Configurable in Docker
Next.js inlines `NEXT_PUBLIC_` variables at build time, which is problematic for Docker images that should be configurable at deploy time. Solution:
**1. Build with placeholder values:**
```dockerfile
# Dockerfile
ARG NEXT_PUBLIC_APP_URL=__NEXT_PUBLIC_APP_URL__
ARG NEXT_PUBLIC_STORAGE_ADAPTER=__NEXT_PUBLIC_STORAGE_ADAPTER__
```
**2. Replace at container start:**
```bash
#!/bin/sh
# docker/entrypoint.sh
# Replace build-time placeholders with runtime environment values
find /app/.next -type f -name '*.js' | while read file; do
sed -i "s|__NEXT_PUBLIC_APP_URL__|${NEXT_PUBLIC_APP_URL:-http://localhost:3000}|g" "$file"
sed -i "s|__NEXT_PUBLIC_STORAGE_ADAPTER__|${NEXT_PUBLIC_STORAGE_ADAPTER:-localStorage}|g" "$file"
# ... repeat for each NEXT_PUBLIC_ variable
done
exec node server.js
```
**3. Use in docker-compose:**
```yaml
# docker-compose.yml
services:
architools:
image: architools:latest
environment:
- NEXT_PUBLIC_APP_URL=https://tools.internal
- NEXT_PUBLIC_STORAGE_ADAPTER=api
- STORAGE_API_URL=http://api:8080/storage
- MINIO_ENDPOINT=minio:9000
- MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
ports:
- "3000:3000"
```
---
## Docker Environment Injection
### Development
```bash
# .env.local (gitignored)
NEXT_PUBLIC_APP_NAME=ArchiTools
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_STORAGE_ADAPTER=localStorage
```
### Production (Docker Compose)
```yaml
# docker-compose.yml
version: '3.8'
services:
architools:
build:
context: .
dockerfile: Dockerfile
container_name: architools
restart: unless-stopped
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- NEXT_PUBLIC_APP_NAME=ArchiTools
- NEXT_PUBLIC_APP_URL=https://tools.internal
- NEXT_PUBLIC_STORAGE_ADAPTER=api
- STORAGE_API_URL=http://api:8080/storage
- MINIO_ENDPOINT=minio:9000
- MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
- MINIO_BUCKET=architools
# External links
- NEXT_PUBLIC_PORTAINER_URL=https://portainer.internal
- NEXT_PUBLIC_GITEA_URL=https://git.internal
- NEXT_PUBLIC_N8N_URL=https://n8n.internal
networks:
- internal
networks:
internal:
external: true
```
### Production (Portainer)
When deploying via Portainer, set environment variables in the container's Environment section. Sensitive values (MinIO keys, auth secrets) should use Portainer's secrets management rather than plain environment variables.
---
## Configuration Precedence
Resolution order from lowest to highest priority:
```
1. Source code defaults (flags.ts, modules.ts, companies.ts, theme.ts)
↑ overridden by
2. Environment variables (.env.local / Docker env)
↑ overridden by
3. Runtime overrides (admin UI → stored in system namespace)
```
If a conflict exists, the higher-priority source wins. Runtime overrides are only available for feature flags and user preferences (theme, sidebar state). Structural configuration (module registry, company data, navigation groups) is not runtime-overridable; it requires a code change and rebuild.
---
## Configuration File Index
| File | Purpose | Changeable at Runtime |
|---|---|---|
| `src/config/modules.ts` | Module registry and metadata | No |
| `src/config/flags.ts` | Feature flag definitions and defaults | Overridable via env/storage |
| `src/config/navigation.ts` | Sidebar groups and external links | No |
| `src/config/companies.ts` | Company master data | No |
| `src/config/theme.ts` | Theme tokens and brand colors | Theme preference only |
| `.env.local` | Development environment variables | N/A (dev only) |
| `.env.example` | Documented variable template (committed) | N/A (reference) |
| `docker-compose.yml` | Production environment variables | At deploy time |
| `docker/entrypoint.sh` | Runtime placeholder replacement | At container start |
---
## Validation
On application startup, the config system validates:
1. All required `NEXT_PUBLIC_` variables are set (not empty or placeholder).
2. `NEXT_PUBLIC_STORAGE_ADAPTER` is a known adapter type.
3. If adapter is `api`, `STORAGE_API_URL` is set.
4. If MinIO is configured, all three of `MINIO_ENDPOINT`, `MINIO_ACCESS_KEY`, and `MINIO_SECRET_KEY` are present.
5. Feature flag overrides parse correctly (no malformed entries).
6. Module IDs in `NAV_GROUPS` reference existing modules in `MODULE_REGISTRY`.
Validation errors are logged to the console with `[ArchiTools Config]` prefix and do not crash the application. Missing optional config results in graceful degradation (e.g., external links not shown, MinIO features unavailable).