Skip to content

Architecture

Ed Mozley edited this page Jun 4, 2026 · 10 revisions

Architecture

FreeITSM is a classic LAMP-style web application: PHP server-side with vanilla JS/HTML/CSS on the client. No frameworks, no build step. All 18 modules share a common chrome (waffle menu, header, user account dropdown) but each module is self-contained under its own folder.

Technology Stack

Component Technology
Backend PHP 7.4–8.4
Database MySQL 8.0+ via PDO MySQL
Frontend Vanilla JavaScript, HTML5, CSS3
Rich text editing TinyMCE 6+
Email integration Microsoft Graph API + Gmail API (OAuth 2.0)
Encryption at rest AES-256-GCM for sensitive values
AI features Pluggable providers β€” Anthropic Claude / OpenAI / OpenRouter, per-feature keys (AI Providers) + OpenAI embeddings (Knowledge)
Web server Apache (WAMP/XAMPP/LAMP) or any PHP server

Directory Layout

freeitsm/
β”œβ”€β”€ config.php                  # References external db_config.php
β”œβ”€β”€ index.php                   # Module selection grid (landing page)
β”œβ”€β”€ login.php                   # Analyst login
β”œβ”€β”€ api/                        # ~140 REST endpoints, one folder per module
β”œβ”€β”€ assets/
β”‚   β”œβ”€β”€ css/                    # Shared stylesheets
β”‚   β”œβ”€β”€ js/                     # Shared scripts + TinyMCE library
β”‚   └── images/
β”œβ”€β”€ includes/                   # Shared PHP components
β”‚   β”œβ”€β”€ functions.php           # connectToDatabase() + analyst module helpers
β”‚   β”œβ”€β”€ waffle-menu.php         # Cross-module nav + user account menu
β”‚   β”œβ”€β”€ encryption.php          # AES-256-GCM helpers
β”‚   β”œβ”€β”€ totp.php                # Pure-PHP TOTP / HOTP (RFC 6238 / 4226)
β”‚   └── module-colors.php       # Module colour definitions
β”œβ”€β”€ database/
β”‚   └── freeitsm.sql            # Schema bootstrap
β”œβ”€β”€ docs/                       # Design docs (e.g. cmdb.md)
└── <module-folders>/           # tickets/, contracts/, cmdb/, ...

Each module folder typically contains:

  • index.php β€” landing page
  • settings/index.php β€” module config
  • help.php β€” in-app guided help page (scroll-spy sidebar, sectioned content)
  • includes/header.php β€” module's header bar with its colour gradient and nav tabs

Shared Components

Waffle Menu (includes/waffle-menu.php)

A Microsoft 365-style app launcher in the header of every module page. Each module is registered with a name, path, icon SVG, and colour gradient. Respects $_SESSION['allowed_modules'] to filter visible modules per analyst.

Also contains the user account menu β€” an initials avatar circle in the top-right of every page. Clicking opens a dropdown with:

  • Change Password (validates current, min 8 chars)
  • Multi-Factor Authentication (TOTP setup/disable with QR code)
  • Logout (with confirmation)

To add a new module, add an entry to the $modules array and matching CSS.

TOTP (includes/totp.php)

Pure-PHP implementation of RFC 6238 (TOTP) and RFC 4226 (HOTP). No external dependencies β€” uses PHP's built-in hash_hmac() and random_bytes().

  • Secret generation: 20 random bytes β†’ Base32 (32-char string)
  • Code generation: HMAC-SHA1, 30-second time step, dynamic truncation β†’ 6-digit code
  • Verification: Β±1 time window (90-second tolerance), hash_equals() for timing-safe compare
  • URI format: otpauth://totp/FreeITSM:{username}?secret={base32}&issuer=FreeITSM

Secrets are encrypted at rest with AES-256-GCM before being stored in analysts.totp_secret.

Encryption (includes/encryption.php)

AES-256-GCM authenticated encryption for sensitive database values.

  • Key file: C:\wamp64\encryption_keys\sdtickets.key (outside web root)
  • Format: ENC: + base64(IV + auth tag + ciphertext)
  • Migration-safe: Values without ENC: prefix pass through unchanged
$encrypted = encryptValue($plaintext);
$plaintext = decryptValue($encrypted);
$mailbox = decryptMailboxRow($mailbox);

Encrypted columns include:

  • system_settings: vcenter_*, knowledge_ai_api_key, knowledge_openai_api_key, intune_*
  • target_mailboxes: azure_tenant_id, azure_client_id, azure_client_secret, oauth_redirect_uri, imap_server, target_mailbox
  • analysts.totp_secret

A subset of "true secrets" listed in MASKED_SETTING_KEYS are also masked to ****<last4> in API responses, with a save-time convention that blank or asterisk-prefixed submissions mean "leave unchanged" so the user can save the form without re-typing.

Module Header Pattern

Each module's includes/header.php:

  1. Checks session auth (redirects to login if missing)
  2. Sets $current_module for waffle-menu highlighting
  3. Renders the header bar with the module's colour gradient
  4. Includes the waffle button, module nav tabs, and user account avatar

Toast Notifications (assets/js/toast.js)

Global notification system. Four types: success (green), error (red), warning (amber), info (blue). 9 configurable screen positions via visual grid picker in System Settings β†’ General. Position persisted per-browser in localStorage. Slide-in animations, auto-dismiss after 4s, manual close button.

i18n (includes/i18n.php, assets/js/i18n.js, lang/)

Native multi-language support with a t('namespace.path.to.key') call pattern in both PHP and JavaScript. The first dot-separated segment of the key maps to a file (lang/<locale>/<namespace>.php); everything after walks a nested PHP array inside that file.

return [
    'toolbar' => [
        'process'  => 'Prozess',
        'decision' => 'Entscheidung',
    ],
];

Fallback is per key, not per file. If lang/de/tickets.php has 80% of keys translated, you get 80% in German and the missing 20% in English. Last-resort behaviour returns the key itself so unfilled strings are visible during development.

Locale resolution chain: logged-in analyst's interface_language user preference β†’ browser Accept-Language header (with primary-subtag matching β€” pt resolves to pt-BR) β†’ 'en' default. Selectable in System β†’ Preferences; on change, persists to user_preferences and reloads the page.

JS bridge: each page declares the namespaces it needs ($translationNamespaces = ['common', 'process-mapper']) and PHP renders window.translations with English fallback already merged into the active locale per key. The JS t() helper does a flat dotted walk β€” no fallback logic on the client.

Supported locales (20 as of May 2026): en, af, fr, de, es, pt-BR, nl, it, pl, ru, id, hi, bn, ta, te, mr, kn, ml, gu, pa. BCP 47 codes match the HTML lang attribute. Spans Europe (en/fr/de/es/pt-BR/nl/it/pl/ru), South Africa (af β€” Afrikaans), South Asia (the nine Indian languages), and Indonesia (id β€” Bahasa Indonesia). Adding a new language is a 2-step code change: add to I18n::SUPPORTED_LOCALES (with native-script display name), and drop .php translation files into lang/<code>/. The System β†’ Preferences dropdown picks the new locale up automatically.

Translated modules: Process Mapper was the pilot; Tickets and Tasks are now fully translated end-to-end (PHP pages and JavaScript) across all 20 locales. Remaining modules follow in phased sweeps β€” the infrastructure is the hard part and it's done.

Database Conventions

  • MySQL 8.0+ with AUTO_INCREMENT for primary keys
  • $conn->lastInsertId() to retrieve new IDs after INSERT
  • Foreign keys with cascading where ownership is real (e.g. cmdb_objects.parent_id cascade-deletes descendants)
  • Soft delete via is_active flags rather than physical deletion for user-facing records
  • Datetime columns: created_datetime, last_modified_datetime, etc. (PHP-side defaults)

API Pattern

All endpoints live under api/<module>/ and return JSON. Every endpoint starts with:

session_start();
require_once '../../config.php';
require_once '../../includes/functions.php';

header('Content-Type: application/json');

if (!isset($_SESSION['analyst_id'])) {
    echo json_encode(['success' => false, 'error' => 'Not authenticated']);
    exit;
}

See API Reference for a per-module endpoint summary.

AI Integration Pattern

AI features share a single provider-agnostic building block β€” drop renderAiSettingsPanel('<ns>') on a settings page and call aiProviderChat() in the backend. Each feature is configured independently with its own provider (Anthropic / OpenAI / OpenRouter), model and key, kept separate for granular billing visibility:

Feature Namespace Settings location
Knowledge AI chat knowledge_ai Knowledge β†’ Settings β†’ AI
Reply Cleanup tickets_reply_cleanup Tickets β†’ Settings β†’ Reply Cleanup
Form generation forms_ai Forms β†’ Settings β†’ AI
CMDB AI summary + Suggest Properties cmdb_ai CMDB β†’ Settings β†’ AI Integration
Workflow co-author workflow_ai Workflows β†’ Settings β†’ AI
RFP Builder (deferred) Contracts β†’ Settings β†’ RFP AI

All keys are encrypted at rest. Most AI features stream output via SSE (claude.ai-style live tokens) for long-running calls. OpenRouter adds a single key reaching hundreds of models across vendors. See AI Providers for the full reference.

FreeITSM

Getting Started

Modules

Multi-tenancy (planned)

Blue sky thinking

Bugs resolved

Links

Clone this wiki locally