Skip to content

Architecture

Ed Mozley edited this page Jul 21, 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
β”œβ”€β”€ logout.php / analyst_logout.php   # Logout handlers
β”œβ”€β”€ force_password_change.php         # Forced password change (expired passwords)
β”œβ”€β”€ forgot-password.php               # Password reset request page
β”œβ”€β”€ reset-password.php                # Password reset (with token from email)
β”œβ”€β”€ oauth_callback.php                # Microsoft OAuth 2.0 callback
β”œβ”€β”€ google_oauth_callback.php         # Google OAuth 2.0 callback
β”œβ”€β”€ csat.php                          # Public CSAT survey page (token link from email)
β”‚
β”œβ”€β”€ api/                              # ~140 REST endpoints, one folder per module
β”‚   └── v1/                           # Public REST API v1 (API-key auth) β€” see the REST API pages
β”‚
β”œβ”€β”€ assets/
β”‚   β”œβ”€β”€ css/                          # Shared stylesheets β€” inbox.css (core layout), theme.css (palette tokens), per-module css
β”‚   β”œβ”€β”€ js/                           # Shared scripts β€” inbox.js, i18n.js, tz.js, toast.js, safe-html.js, qrcode.min.js (MFA QR codes), … + TinyMCE library
β”‚   └── images/                       # CompanyLogo.png (replace with your own)
β”‚
β”œβ”€β”€ 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)
β”‚   β”œβ”€β”€ i18n.php                      # Translation helper β€” see the Internationalisation page
β”‚   β”œβ”€β”€ timezone.php                  # Per-analyst display timezone β€” see Timezones & Time Handling
β”‚   β”œβ”€β”€ theme.php                     # Palette registry β€” see Theming & Dark Mode
β”‚   β”œβ”€β”€ rbac.php                      # Capability guards β€” see Roles & Permissions
β”‚   β”œβ”€β”€ tenancy.php                   # Company scoping β€” see Multi-Tenancy
β”‚   β”œβ”€β”€ gmail.php / mailbox_graph.php / mailbox_imap.php   # Mailbox providers (Gmail API / MS Graph / basic IMAP-SMTP)
β”‚   β”œβ”€β”€ template_email.php            # Automated email templates for ticket events
β”‚   β”œβ”€β”€ module-colors.php             # Module colour definitions
β”‚   └── services/                     # Shared service layer β€” see Service Layer Architecture
β”‚
β”œβ”€β”€ lang/                             # Translations, one folder per locale
β”‚
β”œβ”€β”€ tickets/                          # Ticket Management module
β”‚   β”œβ”€β”€ index.php                     # Three-panel inbox interface
β”‚   β”œβ”€β”€ users.php                     # User directory & their tickets
β”‚   β”œβ”€β”€ calendar.php                  # Ticket scheduling calendar
β”‚   β”œβ”€β”€ rota.php                      # Staff rota weekly grid
β”‚   β”œβ”€β”€ settings/                     # Departments, types, origins, statuses, priorities, SLA, mailboxes, rota shifts
β”‚   └── attachments/                  # Email attachment storage (gitignored)
β”‚
β”œβ”€β”€ asset-management/                 # Asset Management module
β”‚   β”œβ”€β”€ dashboard/                    # Per-analyst widget dashboard (Chart.js)
β”‚   β”œβ”€β”€ servers/                      # vCenter VM inventory with detail modal
β”‚   └── settings/                     # vCenter connection settings
β”‚
β”œβ”€β”€ knowledge/                        # Knowledge Base β€” index.php (article list & editor), review/ (review workflow), settings/
β”œβ”€β”€ change-management/                # Changes β€” index.php, calendar.php (scheduled changes), approvals.php, settings/
β”œβ”€β”€ calendar/                         # Calendar β€” index.php (full calendar view), settings/ (event categories)
β”œβ”€β”€ morning-checks/                   # Morning Checks β€” daily check interface with PDF export
β”œβ”€β”€ reporting/                        # Reporting β€” logs/ (logins, email imports), tickets/ (ticket dashboards)
β”œβ”€β”€ software/                         # Software β€” inventory, dashboard/ (widgets + library.php), licences/, settings/ (API keys)
β”œβ”€β”€ forms/                            # Forms β€” edit/ (form editor), fill.php (A4-style filler), submissions.php, settings/
β”œβ”€β”€ lms/                              # LMS β€” index.php (dashboard), player.php (SCORM player), content/ (uploaded packages)
β”œβ”€β”€ process-mapper/                   # Process Mapper β€” visual flowchart editor
β”œβ”€β”€ network-mapper/                   # Network Mapper β€” index.php (diagrams landing), diagram.php (per-diagram editor)
β”œβ”€β”€ tasks/ Β· contracts/ Β· cmdb/ Β· problem-management/ Β· workflow/     # Further modules, same shape
β”œβ”€β”€ service-status/ Β· system-wiki/ Β· watchtower/ Β· self-service/     # (index.php + settings/ + includes/)
β”‚
β”œβ”€β”€ system/                           # System module (administrators only)
β”‚   β”œβ”€β”€ analysts/                     # Analyst accounts (passwords, SSO, teams, per-company access, admin role)
β”‚   β”œβ”€β”€ teams/                        # Team management (used across tickets, tasks, contracts, workflows)
β”‚   β”œβ”€β”€ modules/                      # Analyst module access control
β”‚   └── encryption/                   # Encryption key management
β”‚
β”œβ”€β”€ browser-extension/                # Chrome/Edge Watchtower extension (Manifest V3) β€” see Browser Extension
β”œβ”€β”€ cron/                             # Scheduled jobs (SLA breach checks, webhook deliveries, scheduled workflows)
β”œβ”€β”€ database/
β”‚   └── freeitsm.sql                  # Schema bootstrap
β”œβ”€β”€ docs/                             # Design docs (e.g. cmdb.md)
└── setup/                            # Setup verification / diagnostic page (delete after going live)

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, plus imap_username, imap_password and smtp_server for basic IMAP/SMTP mailboxes
  • analysts.totp_secret

The canonical lists live in the ENCRYPTED_SETTING_KEYS and ENCRYPTED_MAILBOX_COLUMNS constants in includes/encryption.php β€” a system_settings key or mailbox column is only encrypted/decrypted if it appears there.

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

Module Page Pattern

Every module page follows the same skeleton β€” set $current_page and $path_prefix before the markup, pull in the shared stylesheet and the module header, and define an API_BASE constant for the page's JavaScript:

<?php
session_start();
require_once '../config.php';
$current_page = 'module_name';
$path_prefix = '../';
?>
<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="../assets/css/inbox.css">
    <!-- Module-specific styles in a <style> block -->
</head>
<body>
    <?php include 'includes/header.php'; ?>
    <div class="main-container module-container">
        <!-- Module content -->
    </div>
    <script>
        const API_BASE = '../api/module_name/';
        // Module JavaScript
    </script>
</body>
</html>

Adding a New Module

  1. Create the module folder with index.php and includes/header.php
  2. Create an API folder under api/
  3. Register it in includes/waffle-menu.php (add to the $modules array + CSS colours)
  4. Add a card to the index.php landing page (icon, colour, link)
  5. Add any new tables to database/freeitsm.sql and the Database Verification schema

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) β€” but delete endpoints also remove children explicitly rather than trusting cascades, because installs grown via Database Verification may lack backfilled FKs. Full story, delete-rule conventions, orphan-hunting SQL and the schema-change checklist: Database Integrity
  • 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.

Business logic belongs in a shared service, not in the endpoint. These UI endpoints and their REST API v1 counterparts are thin adapters over a per-module service class, so a rule is written once and can't drift between the UI and the API. If you add a feature with both a UI action and an API endpoint, read Service Layer β€” one implementation, two interfaces first (rollout status: progress tracker).

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.

File Locations Quick Reference

Need to... Look in...
Add a new module Module folder + api/ + includes/waffle-menu.php + index.php
Change the database connection db_config.php (outside the web root, referenced from config.php), includes/functions.php
Add an encrypted setting includes/encryption.php β†’ ENCRYPTED_SETTING_KEYS or ENCRYPTED_MAILBOX_COLUMNS
Modify cross-module navigation includes/waffle-menu.php
Change the landing page index.php
Modify the ticket inbox tickets/index.php, assets/js/inbox.js
Configure vCenter asset-management/settings/, api/assets/get_vcenter.php
Manage knowledge AI knowledge/settings/, api/knowledge/ai_chat.php
Design forms forms/index.php, api/forms/save_form.php
View form submissions forms/submissions.php, api/forms/get_submissions.php
Manage the encryption key system/encryption/, api/system/check_encryption.php
Configure module access system/modules/, api/system/save_analyst_modules.php
Account menu (avatar / password / MFA) includes/waffle-menu.php β†’ renderHeaderRight(), api/myaccount/
MFA login challenge login.php, api/myaccount/verify_login_otp.php
TOTP implementation includes/totp.php

FreeITSM

Getting Started

Modules

Multi-tenancy (planned)

Blue sky thinking

Bugs resolved

Links

Clone this wiki locally