# 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=

# -----------------------------------------------------------------------------
# Email Notifications (Brevo SMTP)
# -----------------------------------------------------------------------------
# SMTP relay for daily digest emails (deadline alerts, document expiry)
BREVO_SMTP_HOST=smtp-relay.brevo.com
BREVO_SMTP_PORT=587
BREVO_SMTP_USER=              # Brevo SMTP login (from Brevo dashboard)
BREVO_SMTP_PASS=              # Brevo SMTP key (from Brevo dashboard)
NOTIFICATION_FROM_EMAIL=noreply@beletage.ro
NOTIFICATION_FROM_NAME=Alerte Termene
NOTIFICATION_CRON_SECRET=     # Random Bearer token for N8N → digest API auth

# -----------------------------------------------------------------------------
# eTerra ANCPI (ParcelSync module — GIS data)
# -----------------------------------------------------------------------------
ETERRA_USERNAME=                # eTerra login email
ETERRA_PASSWORD=                # eTerra login password

# -----------------------------------------------------------------------------
# ANCPI ePay (CF extract ordering)
# -----------------------------------------------------------------------------
ANCPI_USERNAME=                 # ePay login email (separate from eTerra)
ANCPI_PASSWORD=                 # ePay login password
ANCPI_BASE_URL=https://epay.ancpi.ro/epay
ANCPI_LOGIN_URL=https://oassl.ancpi.ro/openam/UI/Login
ANCPI_DEFAULT_SOLICITANT_ID=14452   # Beletage persoana juridica
MINIO_BUCKET_ANCPI=ancpi-documente  # MinIO bucket for CF extract PDFs

# -----------------------------------------------------------------------------
# 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).
