Operations · Administration · Development

DAoC CMS Complete Documentation

A code-aligned guide to installing, operating, extending and troubleshooting DAoC CMS with Dawn of Light or OpenDAoC. It covers the core website, community system, game-data editors, live bridges, Discord integration and production maintenance.

Version 1.0.0-rc2Dawn of LightOpenDAoCPHP 8.2+MySQL 8Reviewed 13 August 2026
Start here

1. What DAoC CMS is

DAoC CMS is an open-source content and administration platform made specifically for Dark Age of Camelot freeshards. It combines a conventional website and community layer with direct access to a supported game database and optional services for actions against the live game world.

A minimal installation can run as a website, account portal and forum. A fully integrated installation can additionally expose Herald and PvE data, edit game content, relay guild chat, display live events, operate an itemshop, administer online players and connect Discord.

CORE WEBSITE

Publish and organize

Pages, navigation, FAQ, team page, profiles, search, SEO, themes and translations.

COMMUNITY

Run the community

Registration, linked game accounts, Spike Forum, messages, notifications, moderation and audit tools.

GAME DATA

Manage the shard

Herald, PvE database, RvR map, items, mobs, suits, quests, abilities, characters and server properties.

LIVE INTEGRATION

Reach the game world

AldhranConsole, AldhranBridge, Discord bot, live events, guild chat and terrain support.

You do not need every component. The CMS, its own database and a connection to an existing game database are enough for the basic platform. AldhranConsole, C# scripts, Node.js, Discord and terrain services are feature-specific additions.

Documentation scope

This document describes the repository state identified as 1.0.0-rc2. Paths and setting names are written exactly as they exist in that code line. Custom forks can add or omit fields, so schema-dependent operations should still be tested against a copy of the real database before production use.

Minimal path

2. Quick start

This is the shortest safe route from a clean web directory to a usable CMS. The full setup chapters explain every choice.

  1. Create an empty MySQL database for the CMS using utf8mb4.
  2. Clone or extract DAoC CMS into the public web directory.
  3. Open /setup/ and clear all red requirement and permission checks.
  4. Connect the empty CMS database.
  5. Select Dawn of Light or OpenDAoC and connect the game database.
  6. For an existing shard choose Use my existing database. Do not import a public schema over live data.
  7. Set the site URL, timezone, sender identity and generated secrets.
  8. Skip optional bridges unless you want live game actions immediately.
  9. Create the Privilege Level 5 administrator and run all installation phases.
  10. Download the setup summary, back up includes/config.php, then delete setup/.
git clone https://github.com/Darku11/daoc_cms.git
cd daoc_cms
# Open https://your-domain.example/daoc_cms/setup/ in a browser
Existing shard: the public-schema and uploaded-backup choices are destructive import modes. Choose the existing-database option unless replacing the selected game database is intentional and backed up.
Mental model

3. Core concepts

Two logical databases

DatabaseContainsUsed by
CMS databaseCMS users, pages, themes, translations, forum, settings, bot configuration, audit logs, AI tasks and CMS-owned suit data.The PHP application and installer.
Game databaseAccounts, characters, guilds, mobs, item templates, quests, keeps, relics, zones, properties and other emulator data.CMS game modules, AldhranConsole and the game server.

In the current PHP runtime both connections are exposed through the configured PDO environment used by the application. Keep the distinction clear operationally: CMS tables are owned by DAoC CMS; emulator tables remain live game data.

Database data versus live-world state

Reading a character or editing an item template is a database operation. Kicking an online player, teleporting them, broadcasting a message or handing an item to an online inventory is a live-world operation and goes through the Console/Bridge chain.

ExamplePathExtra component
Show Herald rankingsPHP → game databaseNone
Edit an item templateACP → game databaseNone
Kick an online playerCMS → AldhranConsole → AldhranBridge.NET service + C# script
Push a keep capture to the websiteCMSLiveEvents.cs → api_events.phpC# script
Relay guild chat to DiscordGuildChatBridge.cs → CMS → Discord botC# script + bot

Core selector

The setting game_server_core is either dol or opendaoc. Existing RC1 installations without this setting default to DOL behavior. The selected value changes compatibility mappings and selects the core-specific Mob Editor implementation. It can be changed later in ACP → General Settings → Game Server, but the connected database must match the selected core.

System map

4. Architecture

Browser / DiscordVisitors, staff and bot commands
DAoC CMSPHP 8.2+, CMS database, game DB access
AldhranConsoleASP.NET Core HTTP service · :5100
Game serverAldhranBridge TCP script · :2000

Repository responsibilities

RepositoryResponsibilityKey paths
Darku11/daoc_cmsWeb application, installer, PHP modules, schema, frontend, ACP, bot process source and downloadable bridge scripts.modules/, includes/, setup/, assets/js/bot.js
Darku11/daoc_cms_utilitiesComponents that run inside or beside the game server.AldhranConsole/, AldhranBridge.cs, CMSLiveEvents.cs, GuildChatBridge.cs, TerrainService archive

Request boundaries

  • Frontend requests enter through index.php?p=<slug>.
  • ACP requests enter through acp.php?s=<section> and are checked against the section's minimum privilege.
  • Shared application bootstrap, sessions, settings, compatibility helpers and plugins are loaded through includes/db.php.
  • Theme CSS is assembled from database modules by style.php with theme inheritance and ETag versioning.
  • Live actions use the hardened client in includes/console_client.php.
  • External game scripts post events to api_events.php using the game-server shared secret.
Installation

5. Requirements and deployment models

Required for the core CMS

RequirementMinimum / expectedWhy
Web serverApache or another PHP-capable serverApache rules are supplied in .htaccess; equivalent rules are required elsewhere.
PHP8.2 or newerInstaller hard requirement.
DatabaseMySQL 8; compatible MariaDB deployments should be testedCMS schema, triggers/events and game data.
PHP extensionspdo, pdo_mysql, json, curl, zip, fileinfo, zlibConnections, JSON APIs, HTTP integrations, archives, uploads and compressed OpenDAoC import.
Recommended extensionsmbstring, opensslUnicode handling and cryptographic/TLS support.
GitCurrent stable clientRecommended installation and update workflow.

Recommended PHP limits

  • memory_limit: 128 MB or more
  • upload_max_filesize: 32 MB or more
  • post_max_size: 32 MB or more and not smaller than the upload limit
  • max_execution_time: 60 seconds or more, or unlimited during controlled installation

Optional component requirements

FeatureAdditional requirement
Live in-game administration / item delivery.NET 10 for AldhranConsole and AldhranBridge.cs in the game server scripts folder.
Discord botCurrent Node.js LTS, npm dependencies and a Discord application/bot.
Discord interaction endpointPHP Sodium extension when using Discord's Ed25519 interaction verification.
Terrain-dependent editorsTerrainService package and its supporting client library.
Scheduled AI workConfigured provider and a task scheduler invoking cron_ai_worker.php.
Automated itemshop deliveryA scheduler invoking the webshop worker and a working Console/Bridge chain.

Deployment profiles

Minimal

Web server + PHP + CMS database + existing game database. Suitable for content, accounts, forum and database-backed public modules.

Integrated

Minimal profile plus AldhranConsole and AldhranBridge for live administration and delivery.

Full

Integrated profile plus Discord bot, CMSLiveEvents, GuildChatBridge, schedulers and optional terrain service.

Ten chapters

6. Setup wizard

Open https://your-domain.example/path/setup/. The wizard stores answers in the current PHP session, so keep the tab open until installation finishes.

Step 1 — Welcome

Introduces the installation and starts the ten-step sequence. No system changes occur here.

Step 2 — Requirements

The wizard checks PHP, required and recommended extensions, runtime limits, operating system and web server. Red entries block progress; amber entries are warnings.

Step 3 — Permissions

The web server must be able to create or write uploads/, backups/, plugins/ and includes/config.php (or its parent directory before the file exists). Prefer correct ownership and narrow permissions; do not set the entire website to 777.

Step 4 — CMS database

Create the empty database before opening the wizard. The installer connects to it but does not create the database itself.

CREATE DATABASE `daoc_cms`
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_general_ci;

The test verifies connectivity and the ability to create and drop a temporary table. An existing users table triggers a warning because the final schema phase writes CMS tables.

Step 5 — Game database and server core

Select OpenDAoC or Dawn of Light, enter host, port, database, username and password, then choose one mode:

ModeUse whenRisk
Use my existing databaseThe shard already exists or its schema was imported separately.Connection/structure test only. Safest for production.
Install public databaseBuilding a brand-new shard from the bundled core-specific schema.Destructive import; can replace tables.
Import my own backupIntentionally restoring a supplied SQL file.Destructive import; large files may exceed PHP limits.

The bundled public files are setup/sql/dol_public.sql and setup/sql/opendaoc_public.sql.gz. Large backups are more reliable through the MySQL command line; after importing them externally, return and select the existing-database mode.

Step 6 — Site configuration and secrets

Configure site name, shard name, absolute base URL without a trailing slash, language, timezone, sender name/address, optional Resend key and optional Discord values. The wizard generates:

  • Password pepper — required to validate every CMS password.
  • Instance ID — installation identity and session-name component; not a secret.
  • Bot bootstrap secret — authorizes the Node bot to retrieve startup configuration.
  • Game-server integration secret — written as ASP_KEY and used as the canonical shared secret for AldhranConsole and game-server scripts.
Back up the password pepper outside the server. Losing or changing it invalidates every existing CMS password hash.

Step 7 — Optional bridges

Set AldhranConsole host (without http://), HTTP port (default 5100) and AldhranBridge TCP port (default 2000). The wizard exposes downloads for the three C# scripts. Saving this step configures only the CMS; the external services still have to be installed and started.

Step 8 — Administrator

Create the first Privilege Level 5 account. The username is restricted to 3–20 letters, numbers, underscores or hyphens; the password validator requires a strong password. The installed password is peppered and stored as a bcrypt hash.

Step 9 — Installation phases

  1. Write includes/config.php.
  2. Verify the CMS database connection.
  3. Execute setup/sql/database.sql.
  4. Normalize selected CMS table names to the cms_ scheme.
  5. Create the Super Admin.
  6. Save initial settings and the migration baseline.

The per-phase endpoint is CSRF-protected, rejects non-POST requests and refuses a second completed run in the same setup session.

Step 10 — Finish and seal

Download daoc-cms-setup-summary.txt before leaving the page. It contains the pepper, instance ID, integration key and bot bootstrap secret, but not database or administrator passwords. The wizard creates install.lock and clears setup secrets from the session.

Delete setup/ after installation. The lock blocks normal reuse, but removing the installer code is the correct production state. If the lock could not be created, deletion is urgent.
Before customization

7. First-run checklist

  • Setup summary downloaded and stored outside the web root.
  • includes/config.php backed up securely.
  • setup/ removed and install.lock present.
  • HTTPS enabled before ordinary logins; secure cookies are enforced by the CMS.
  • Super Admin login tested.
  • Two-factor authentication enabled for the Super Admin; ACP access requires it at level 5.
  • ACP opens and re-authentication succeeds.
  • Selected game-server core matches the connected database.
  • Herald or another read-only game module can query the game database.
  • Maintenance mode reviewed; the fresh schema seeds it as enabled.
  • Unused public modules disabled.
  • Default pages, privacy text and imprint reviewed for the actual operator.
  • Backup paths and a first verified backup configured.
  • Secrets excluded from Git and off-server backups protected.

Recommended order

  1. Secure access and backups.
  2. Confirm database/core compatibility.
  3. Set identity, language, modules and legal pages.
  4. Configure theme and content.
  5. Add one optional integration at a time and test its health boundary before adding the next.
Reference

8. Configuration

includes/config.php

The installer generates this PHP file. It contains credentials and must never be committed, served as text or shared in support screenshots.

ConstantPurposeNotes
SITE_URLCanonical absolute CMS URL.No trailing slash. Used for links, mail and SEO.
INSTANCE_IDUnique installation identity.Also makes the PHP session cookie name installation-specific.
ALDRAN_PEPPER / ALDHRAN_PEPPERPassword pepper aliases retained for compatibility.Back up permanently; never rotate without a password migration.
ASP_KEYInstalled game-server integration secret and compatibility fallback.Current installs also persist it in settings.game_server_shared_secret.
BOT_BOOTSTRAP_SECRETAuthorizes bot startup configuration retrieval.Separate from both the bot socket secret and Discord token.
DB_HOST, DB_USER, DB_PASS, DB_NAMECMS database connection.Restrict DB account access to the intended host/database.
RESEND_API_KEYOptional mail API credential.Leave empty when unused.
SMTP_FROM_EMAIL, SMTP_FROM_NAMEOutbound sender identity.Use a sender/domain authorized by the delivery service.
Changing SITE_URL: the installer text correctly notes that it is a file constant, not merely an ACP setting. Update the file carefully, clear caches and verify canonical URLs, mail links and callbacks.

General settings tabs

AreaImportant setting keysBehavior
Identity & presentationsite_name, default_language, active_theme, discord_linkSite name, UI language, theme and community link.
Modulesmod_forum, mod_herald, mod_rvr_map, mod_faq, mod_team, mod_register, mod_pve, itemshop_enabled, mod_imprintControls public navigation and module availability.
Accountsemail_verification_required, admin_approval_required, use_resend_apiRegistration activation and mail behavior.
Game coregame_server_coredol or opendaoc; controls compatibility logic.
Game addressgame_server_ip, game_server_portPublic/status TCP target; default game port is 10300.
Live bridgegame_server_console_host, game_server_console_port, game_server_bridge_port, game_server_shared_secretCMS-to-Console host/port and shared integration secret.
Restartgame_server_bat_pathConfigured startup path used by the generated watchdog/restart workflow.
Maintenancemaintenance_mode, maintenance_textBlocks normal visitors; access is retained for level 5 administrators.

Secret separation

SecretAuthenticatesNever substitute with
Discord Bot TokenBot process → DiscordAny CMS or bridge secret
Bot bootstrap secretBot process → api_bot_config.phpBot token or socket secret
Bot socket secretCMS ↔ Node bot HMAC/webhook/socket trafficGame-server shared secret
Game-server shared secretCMS ↔ AldhranConsole ↔ AldhranBridge and C# event scriptsDiscord credentials
Authorization

9. Roles, standing and ACP access

CMS privilege is stored in users.priv_level. It is related to, but distinct from, the game account's account.PrivLevel. The User Manager can synchronize both where the action explicitly does so.

LevelDisplay roleTypical access
0GuestUnauthenticated public pages allowed by page/module visibility.
1PlayerProfile, forum and ordinary authenticated features.
2AssociateSupport/moderation features where individual modules permit level 2.
3GMACP dashboard and selected operational/game-data modules.
4AdminContent, settings, integrations, logs and broad administration.
5Super AdminProtected system functions, PHP error log, zones, plugin installation and full privilege assignment.

Management ceiling

OperatorMay manage targets up toMay assign up to
Level 3 GMLevel 2Level 2
Level 4 AdminLevel 3Level 3
Level 5 Super AdminLevel 5Level 5

The User Manager enforces these limits in both listing/edit checks and assignment validation. An Admin cannot promote another account to level 4 or 5 and cannot manage an existing level 4/5 target. A Super Admin cannot delete or edit their own protected account through the User Manager workflow.

ACP session protection

  • ACP entry requires level 3 or higher.
  • The ACP has a separate 30-minute re-authentication window.
  • Level 5 accounts must enable TOTP before ACP access; re-authentication uses the TOTP code.
  • Other staff re-authenticate with their password.
  • AJAX actions repeat minimum-privilege and ACP-session checks.

Standing

Standing is a moderation state independent of privilege: Good (0), Warning I (1), Warning II (2), Restricted (3), Suspended (4) and Banned (5). Restricted/unverified accounts are read-only in relevant profile/community workflows. Ban and suspension actions can trigger bot events and game-account synchronization.

Public site

10. Frontend modules

ModulePurposeDependency / switch
Dynamic pagesPublished CMS content, scheduled publication, menu categories, privilege visibility and SEO metadata.Always available through the Content Manager.
Registration & verificationCreates linked CMS accounts with password policy, privacy acceptance, optional email verification/admin approval and anti-abuse checks.mod_register
User profilesAvatar, languages, biography, signature, linked characters, password, TOTP, data export and account deletion.Authenticated user; game DB for character list.
Spike ForumBoards, threads, posts, polls, attachments, reactions, mentions, tags, prefixes, unread state, subscriptions, reports and search.mod_forum
Private messagesInternal user-to-user messaging with unread counters and sender/receiver deletion state.Authenticated user.
FAQPublic categorized frequently asked questions.mod_faq
TeamStaff/team presentation based on CMS users and role data.mod_team
HeraldPopulation, character, guild, leaderboard, keep and relic views.mod_herald + game DB.
PvE databaseBestiary, bosses, items, quests, reward resolution and related game data.mod_pve + game DB.
ItemshopBrowse configured shop items, create purchases and deliver through the live bridge.itemshop_enabled + Console/Bridge for delivery.
RvR mapRealm war display with normalized keep ownership and relic data.mod_rvr_map + game DB.
SearchSite/forum search surfaces with visibility checks.Available routes; forum search can be disabled separately.
ImprintOperator legal notice page.mod_imprint
RSS / sitemapPublic forum RSS and published public-page XML sitemap.rss.php, sitemap.php

Publication visibility

Normal visitors see only pages with status='published', a reached or empty published_at value and a permitted min_priv. Administrators may see additional content in management contexts. The sitemap restricts itself to published, currently visible level-0 pages; the RSS feed excludes protected boards and shadow-banned authors.

Administration

11. ACP module reference

Every ACP section has a code-defined minimum level. Plugin sections are merged into the same registry after their hook registration.

Category / sectionMin.What it manages
Dashboard3Operational overview, counters, shortcuts, update widget and plugin dashboard hooks.
User Manager3Search, account standing, CMS/game privilege, verification, profiles, password and account lifecycle within the management ceiling.
Content Manager4Pages, publication state, navigation, templates, metadata, history and media.
General Settings4Identity, modules, game core, bridge, startup path and maintenance.
Theme Editor4Database CSS modules, themes, inheritance, live preview, variables, history, import/export and contrast checks.
Translation Editor4Search, compare, create, edit and remove language variables by context.
Forum Admin4Board structure, reports, settings, prefixes, smilies, forbidden words and maintenance tools.
FAQ Manager3FAQ categories, entries and ordering.
Mob Editor3Core-specific visual spawn, loot, template and patrol-route management.
Core Architect3Economy analysis and simulation.
Dataquest Creator3Visual DataQuest editing and simulation.
Item Creator3Search, create and edit item templates with schema-aware writes.
Suit Creator3Paperdoll gear sets, caps, presets, revisions, item generation and merchant output.
Ability Editor4Spells, spell lines, styles, abilities and NPC templates.
Character Editor3Character lookup and selected game-character fields.
Zones Editor5Zone properties.
Global Constants3Reference values and ID mappings.
Ingame Console4Online status, player actions, broadcasts, restart and restricted raw commands via AldhranConsole.
Server Properties4Game-server properties and rates.
Bot & AI Settings4 view / 5 saveDiscord process, socket, command service and provider configuration.
Bot Commands4Enable state, minimum AuthLevel and user/AuthLevel overrides.
AI Suggestions4Review, accept or reject queued proposals.
Admin Log4Administrative and security audit trail.
IP Audit4Login/device/household patterns and approvals.
PHP Error Log5Application error diagnosis.
Cache Manager3CSS versioning, OPcache reset and browser-cache status.
Backup Manager4Create, verify, annotate, pin, restore and delete archives.
Plugin Manager5 effectiveInstall, activate, deactivate and uninstall PHP plugins.
Minimum access is not a safety guarantee. Game-data editors write live tables. Test edits on a copy, keep verified backups and use staff levels narrowly.
Publishing

12. Content and navigation

Page fields

The pages table carries the slug, title, content, status, publication date, menu category and position, parent relationship, language/translation group, template key/data, minimum privilege, meta title/description and optional hero image.

Menu categories

Dynamic menu entries are grouped under stronghold, community and library. none keeps a page out of navigation. Two content prefixes create special links:

  • [EXT]:https://example.org creates an external link with safe new-tab attributes.
  • [MODULE]:herald creates a module link and respects the corresponding module switch.

Safe publishing workflow

  1. Create or edit as draft.
  2. Set language, menu placement, privilege and metadata.
  3. Preview rendered content and media.
  4. Schedule published_at or publish immediately.
  5. Verify as a logged-out visitor, because ACP visibility can be broader.

History and media tables preserve page revisions and file relationships. Canonical URLs drop tracking, secret and transient query parameters before generating the canonical link.

Presentation

13. Themes and CSS

Frontend CSS is stored as named modules in aldhran_styles. style.php selects a stack for the current frontend module, resolves the active theme's parent chain and emits active CSS with content-aware ETags.

Editor capabilities

  • Load, create and save individual CSS modules.
  • Clone a theme or create one with a parent.
  • Live preview and palette/CSS-variable editing.
  • Validate balanced CSS braces and inspect contrast.
  • Export a theme as SQL and import validated theme SQL.
  • Retain up to 30 history versions per module/theme and roll back.
  • Delete non-default themes after child relationships are resolved.

Theme inheritance

aldhran_themes.parent_slug forms an inheritance chain. Parent modules are loaded first and child modules later, so the active child can override selected CSS without duplicating the full theme.

Cache behavior

The ETag combines active theme, requested module, css_version and the latest update timestamp of loaded style rows. Saving database CSS therefore changes the response identity; the Cache Manager can additionally bump css_version to force broad revalidation.

Template overrides: filesystem templates are resolved under templates/<active-theme>/<name>.php before falling back to the default template path. Template names are restricted to letters, numbers, underscores and hyphens.
Localization

14. Translations

Translation rows use lang_code, var_key, var_value and var_context. The runtime loads active languages and resolves strings through t()/cms_t() with replacements and an explicit fallback.

Editor workflow

  • Filter by language, context and search text.
  • Edit a complete row or perform a quick inline save.
  • Create a variable for one language and optionally create the same key for another.
  • Compare missing keys between languages.
  • Delete an obsolete row deliberately; missing UI strings then use their code fallback where supplied.

Preserve stable variable keys when changing wording. A renamed key is a code change, not merely a translation edit. New modules should use a distinct context and provide an English fallback in code.

Community

15. Spike Forum

Spike is the integrated DAoC CMS forum. It shares users, roles, standing, profiles, notifications and administration with the rest of the platform instead of requiring a separate forum bridge.

Member features

  • Categories, boards, privilege-based read/post access and graphical boards.
  • Threads with slugs, prefixes, tags, sticky/locked/approval state and subscriptions.
  • Rich posts, inline images, separately tracked attachments, smilies and edit history.
  • Polls with two or more options, optional multiple choice and optional end time.
  • Reactions, mentions, notifications, unread markers and user ignore/block features.
  • Search, private messages and post/thread reports.

Forum administration

  • Create, order, move and delete categories/boards.
  • Move, lock, sticky, approve or delete threads in bulk.
  • Merge threads, move individual posts and preview content.
  • Process reports with handler notes and status.
  • Manage forbidden words, actions/replacements, prefixes and smilies.
  • Configure cooldowns, link thresholds, attachments/MIME types, edit history, subscriptions, search, unread markers, tags and other feature switches.
  • Clean old read markers and search logs.

Attachment security

The default attachment path is uploads/forum/. Uploads are checked against configured size and MIME allowlists. Inline base64 images are decoded into stored image files; ordinary archives/documents become attachment records. Keep execution disabled in the upload directory at the web-server level.

Public feed

rss.php exposes the latest 20 approved posts from public boards, optionally filtered with ?board=<id>. Protected content and shadow-banned authors are excluded.

Server cores

16. Dawn of Light and OpenDAoC compatibility

DAoC CMS supports both emulator families. Support does not mean their schemas or runtime APIs are identical; RC2 introduces explicit compatibility boundaries instead of treating OpenDAoC as a byte-for-byte DOL database.

PHP compatibility layer

includes/game_server_compat.php centralizes operations shared by public and ACP modules:

  • Core selection and safe default to DOL for older installations.
  • UUID-style game object ID generation.
  • Schema inspection and case-preserving field filtering before writes.
  • Account/character lookup and game privilege resolution.
  • Keep ownership across ClaimedGuildName versus GuildID schemas.
  • Relic identity normalization across RelicID and optional Relic_ID.
  • Herald population, public-stat privacy, character and guild queries.
  • PvE counts, mob/loot resolution, DataQuest reward parsing, item-name and region-label lookup.

Core-specific behavior

AreaDOLOpenDAoC
Mob Editoracp_mob_editor.php, including DOL fields such as MaxDistance.acp_mob_editor_opendaoc.php; removes absent MaxDistance, exposes FactionID and avoids a DOL-only default Brain class.
Item writesPhysical item-template columns are discovered and unsupported fields are removed before persistence.
Suit merchant pricingCan use a MerchantItem price column where present.Uses the referenced ItemTemplate price when MerchantItem has no Price column.
Keep claimsCommonly joins keep.GuildID to guild.Can read keep.ClaimedGuildName directly.
Script API differencesBridge scripts use reflection-based shims for logger creation, player enumeration, release enum placement, command lookup and translation overloads.

Switching a running installation

  1. Back up both databases and the CMS files.
  2. Point the installation at the intended game database.
  3. Set game_server_core to the matching value.
  4. Clear CSS/OPcache only if code or styles changed; the core selector itself is database-backed.
  5. Test read-only modules first, then editors on a staging copy.
  6. Install the matching tested bridge scripts and restart/recompile the game server.
Custom forks: column filtering helps with optional item fields, but it cannot make every arbitrary fork compatible. A custom table name, changed relationship or runtime method still requires a mapped adaptation.
ACP game content

17. Game-data editors

Mob Editor

The Mob Editor is a visual spawn and NPC management environment. It supports zone/region selection, map-based placement, mob creation/editing, templates, loot relationships and patrol routes. The dedicated 2D route editor can associate a route with a selected mob before recording points. A separate OpenDAoC implementation handles core-specific mob fields.

Automatic ground-height or terrain-assisted placement requires the terrain service. Without it, enter a valid Z coordinate or use a known source value.

Item Creator

Searches and edits itemtemplate records. It covers identity, model/slot/type, value/price, quality/condition/durability, bonuses, resists, effects and other fields exposed by the active schema. Writes are filtered against the real table columns so optional fields from another core are not blindly inserted.

Item IDs are live references. Reusing an existing Id_nb can alter every merchant, loot table or character inventory that references it. Clone to a new ID unless replacement is intentional.

Suit Creator

Builds named equipment sets around a paperdoll. It includes class presets, automatic cap calculations, per-slot item selection, saved revisions, clone/blank generation modes, game-table writes and merchant/export workflows. Saving a suit and writing generated items are separate operations: a CMS-side draft does not alter itemtemplate until the write action is used.

Dataquest Creator

Provides a visual editor and simulator for DataQuest records, including quest text, steps, goals, dialogue and rewards. OpenDAoC serialized per-step XP/money rewards and choice-item encodings are normalized by the compatibility layer when displayed.

Ability Editor

Manages spells, spell lines and their level assignments, combat styles and style spells, abilities, and NPC templates/spells. The editor exposes low-level emulator values such as spell type, target, damage type, timing, range, specialization keys, growth rate and NPC brain/class fields.

Other tools

ToolPurposeRisk profile
Core ArchitectEconomy snapshots, wealth analysis and simulation.Prefer analysis/simulation before applying balancing decisions.
Character EditorFind characters and update selected character fields.Back up before level, realm, currency or identity changes.
Zones EditorEdit zone properties.Level 5 only; wrong region/coordinate data affects world behavior.
Global ConstantsBrowse shared constants and ID references used by editors.Reference-oriented; verify the active client/core version.
Server PropertiesEdit game-server properties and rates.Some properties apply only after a server restart.

Safe editor procedure

  1. Create a database backup and note the exact table/record identity.
  2. Use search/read mode to confirm the current record.
  3. Change the smallest possible field set.
  4. Verify database persistence.
  5. Restart or reload scripts only where the game core requires it.
  6. Test in-game with a non-production object or controlled character.
Commerce workflow

18. Itemshop

The itemshop is a CMS/game integration, not an external payment processor. shop_system_items defines available game items, category, base price, stock and activation state. Public item views join those definitions with game item templates.

Purchase path

PlayerSelects a listing
CMSValidates account, balance and request
AldhranConsole/shop/purchase and DB work
AldhranBridgeDelivers to online player

AldhranConsole also exposes /shop/cm-listings for consignment merchant offers. The webshop worker retries or finalizes queued delivery work according to the CMS itemshop logic.

Operational rules

  • Keep itemshop_enabled off until Console status and a test delivery succeed.
  • Use a restricted game-database user with the rights required by enabled shop features.
  • Never expose AldhranConsole directly to customers.
  • Test insufficient balance, unavailable stock, offline player and duplicate/retry behavior.
  • Audit delivery logs before manually compensating a failed transaction.
Public game data

19. Herald, PvE database and RvR map

Herald

Displays server population, top characters, individual character records, guilds and members, keeps and relic context. OpenDAoC's public-stat privacy flag is respected by compatibility queries. Avoid bypassing these helpers with new direct queries that would reveal hidden statistics.

PvE database

Provides bestiary and boss views, item search/details, quest lists/details and resolved rewards. Mob loot follows the emulator's mob-name → loot-template → item-template relationships. Region labels and optional schema details are normalized where possible.

RvR map

Reads keep realm ownership, guild claims and relic state from the game database, then normalizes the different DOL/OpenDAoC representations. The JSON/data view should be treated as public game state; do not add staff-only fields to its response without a privilege boundary.

Freshness

These modules query the database when requested; they are not a separate analytics warehouse. “Players online” views that infer activity from LastPlayed use a recency window and are an approximation unless the live Bridge presence endpoint is used.

Live integration

20. AldhranConsole and AldhranBridge

This is the canonical chain for live administration:

DAoC CMSHTTP + X-Aldhran-Secret
AldhranConsoleASP.NET Core · :5100
AldhranBridge.csTCP secret + JSON · :2000
DOL / OpenDAoCLive players and world

AldhranConsole requirements

  • .NET 10 SDK to build.
  • .NET 10 ASP.NET Core Runtime for a framework-dependent release.
  • MySQL/MariaDB connectivity to the game database.
  • Network access to AldhranBridge's host/port for live-world actions.

appsettings.json

{
  "Console": {
    "ListenUrl": "http://127.0.0.1:5100",
    "SharedSecret": "REPLACE_WITH_THE_CMS_GAME_SERVER_SECRET",
    "DbConnection": "Server=127.0.0.1;Port=3306;Database=GAME_DB;User ID=USER;Password=PASSWORD;",
    "BridgeHost": "127.0.0.1",
    "BridgePort": 2000,
    "BridgeTimeoutSeconds": 8,
    "ScriptsPath": ""
  }
}

Production values can be supplied as environment variables using double underscores, for example Console__SharedSecret and Console__DbConnection. Legacy ApiSecret, BridgeSecret, DolHost and DolPort keys remain accepted, but current installations should use the canonical keys.

Build and publish

dotnet restore
dotnet build --configuration Release

# Windows framework-dependent publish
dotnet publish --configuration Release --runtime win-x64 --self-contained false --output publish/win-x64

# Linux framework-dependent publish
dotnet publish --configuration Release --runtime linux-x64 --self-contained false --output publish/linux-x64

Run AldhranConsole.exe on Windows or dotnet AldhranConsole.dll on Linux. Keep the published directory together and exclude configured production files, bin/ and obj/ from source releases.

Install AldhranBridge

  1. Copy the current AldhranBridge.cs to the game server's scripts/ directory.
  2. Replace CHANGE_ME_BRIDGE_SECRET with the exact CMS game-server shared secret.
  3. Keep BRIDGE_PORT synchronized with the Console configuration (default 2000).
  4. Restrict the port by firewall to the AldhranConsole host.
  5. Restart/recompile scripts and check the server log for [AldhranBridge] Started on port 2000.

Health tests

curl http://127.0.0.1:5100/health
curl -H "X-Aldhran-Secret: YOUR_SHARED_SECRET" http://127.0.0.1:5100/status

/health proves only that the HTTP process is alive and intentionally exposes no connection details. /status proves the authenticated Console → Bridge round trip.

Capabilities

The bridge handles status and presence, kick, privilege level 0–3, teleport, item delivery, stat changes, heal/revive, freeze/mute, broadcasts, guild chat, scheduled restart and restricted raw commands. shutdown and quit are blocked on both sides of the raw-command boundary.

OpenDAoC script compilation and “Bad IL format”

Use source scripts that are compiled against the target server's own assemblies. The utilities repository includes two PowerShell helpers:

# Diagnose all scripts and print the real CSxxxx source error
.\tools\Test-OpenDAoCScripts.ps1 -ReleasePath "C:\Path\To\OpenDAoC\Release"

# Build lib\GameServerScripts.dll against that exact release
.\tools\Build-OpenDAoCScriptAssembly.ps1 -ReleasePath "C:\Path\To\OpenDAoC\Release"

The diagnostic script deliberately compiles the complete script tree with the installed .NET SDK and the release's own assemblies. This separates a real source/API error from a stale or incompatible precompiled GameServerScripts.dll. Do not distribute one arbitrary precompiled script DLL as universally compatible across different OpenDAoC builds.

Game → website

21. CMSLiveEvents

CMSLiveEvents.cs subscribes to player-death and keep-capture events and posts them to api_events.php. It is optional and runs inside the game-server script environment.

  1. Edit API_URL to the public HTTPS URL of api_events.php.
  2. Set BRIDGE_SECRET to the current game-server shared secret.
  3. Place the file in scripts/ and restart/recompile.
  4. Cause a controlled PvP or keep event and poll api_events.php?last_id=0.

Authenticated POST requests store ordinary event types/messages in cms_live_events. The public GET path returns up to five newer, escaped events based on last_id. Guild-chat events follow a special relay path and are not stored as ordinary feed events.

Endpoint exposure: GET is public by design for the live feed. POST depends entirely on the shared secret, so use HTTPS, a high-entropy value and immediate rotation if it appears in logs or screenshots.
Bidirectional relay

22. GuildChatBridge

GuildChatBridge.cs preserves the original /gu behavior while forwarding each successful guild message to the CMS. Because the core suppresses duplicate command registrations, the script replaces the loaded &gu/&guild command entries after scripts load and restores them when unloaded.

Install

  1. Enable Guild Chat Sync in ACP → Bot & AI Settings. The CMS attempts to add guild.discord_channel_id if absent.
  2. Configure and start the Discord bot.
  3. Edit the bridge's API_URL and BRIDGE_SECRET.
  4. Copy it to scripts/, restart/recompile and check for script errors.
  5. Link each in-game guild to its Discord channel ID.
  6. Send /gu test in game. Confirm the message still reaches guild members and appears in the linked Discord channel.

Outbound game → CMS HTTP work runs asynchronously and intentionally cannot crash the chat command. A failed web request therefore leaves in-game chat working but must be diagnosed from logs and the Discord relay result.

Discord → game

The Node bot listens for Discord messages using GuildMessages and MessageContent, posts a signed guild_chat event to the CMS, and the dispatcher/Console/Bridge chain delivers it to the game guild where configured.

Community integration

23. Discord bot

The Aldhran DiscordBot is a Node.js process. It is independent of AldhranBridge for startup and ordinary Discord connectivity. Individual commands that perform live game actions still need the corresponding Console/Bridge path.

Required values

ValueSourceUsed by
Bot TokenDiscord Developer Portal → BotNode process login to Discord.
Public KeyDiscord application General Informationbot_interactions.php Ed25519 validation when using the interaction endpoint.
Client/Application IDDiscord applicationApplication identification/invite configuration.
Bot Channel IDDiscord channel → Copy IDDefault output channel.
Admin Role IDDiscord role → Copy IDRaises recognized bot command authority to level 4.
Bot bootstrap secretSetup summary / configRetrieves CMS bot configuration.
Socket secretGenerated separately by operatorHMAC signatures for Node bot ↔ CMS traffic.

Discord application

  1. Create an application and bot in the Discord Developer Portal.
  2. Enable Message Content Intent. The bot requests Guilds, GuildMessages and MessageContent; it does not request Presence or Server Members.
  3. Install it to the target server with application-command support.
  4. Grant View Channels and Send Messages. Add Manage Channels only for /createguildchannel.
  5. Do not grant Administrator merely to troubleshoot command registration.

CMS bot settings

Set active state, guild-chat switch, Bot Token, channel/role IDs, reboot delay, socket secret, host, port (default 15000), TLS flag and the path to bot.js. Saving bot settings is restricted to level 5. The Token and socket secret are never redisplayed; leave each input empty to retain the stored value.

Process environment

DAOC_CMS_CONFIG_URL=https://your-domain.example/api_bot_config.php
DAOC_CMS_BOOTSTRAP_SECRET=YOUR_BOT_BOOTSTRAP_SECRET
DAOC_CMS_WEBHOOK_URL=https://your-domain.example/bot_webhook.php

node assets/js/bot.js

The ACP Start Bot action uses the configured script path and supplies the required environment. Manual startup is useful for seeing the exact Node/Discord error in a console.

Registered slash commands

/status, /players, /reboot, /broadcast, /char, /guild, /leaderboard, /aisk and /createguildchannel. Command enable state, minimum AuthLevel, cooldown and per-user/per-level overrides are managed in the Bot Commands ACP section.

Why the bot is online but commands are missing

  1. Check the Node log for Slash commands registered globally and for each guild. Being online proves login only, not successful REST registration.
  2. Confirm the bot was installed with the applications.commands scope/application-command functionality.
  3. Restart the process after resetting the token or changing the installation.
  4. Verify that the bot is actually a member of the intended guild when the ready handler loops through guilds.
  5. Check Discord API errors in the Node console; permissions such as Administrator do not repair a missing installation scope or invalid token.
  6. Guild registrations should appear quickly; global commands can be cached. Test in the installed guild and restart the Discord client if necessary.

Authentication paths

  • api_bot_config.php: X-DAOC-CMS-Bootstrap header and bootstrap secret.
  • bot_webhook.php: raw-body HMAC-SHA256 in X-Webhook-Signature, rate-limited.
  • Bot socket: HMAC of action + timestamp, maximum 60-second drift, loopback binding in the Node implementation.
  • bot_interactions.php: Discord Ed25519 signature and timestamp headers.
Optional subsystem

24. AI providers, tasks and suggestions

The AI subsystem is optional. It supports provider-backed analysis and suggestion workflows; it does not replace operator responsibility. The code supports none, Gemini, LM Studio, Groq, OpenAI and Anthropic configurations.

Configuration

Each provider retains its own encrypted API key, URL and model. Shared controls set active provider, maximum tokens (100–8000) and temperature (0–2), plus module-specific system prompts. Local LM Studio can use a localhost-compatible endpoint.

Workflow

  1. A module creates a provider request or queued task.
  2. The response is logged and, for change proposals, stored as a suggestion.
  3. Staff review the original context and proposal.
  4. An authorized reviewer accepts or rejects it with an optional note.
  5. Accepted actions are handled through explicit apply handlers; terminal accepted/rejected suggestions cannot be reverted to pending by the database trigger.

cron_ai_worker.php processes queued work when called by the scheduler. The schema also tracks daily call/task counts, provider keys, logs, tasks and expiry behavior.

Review boundary: never treat a provider response as trusted SQL, PHP or game data. Inspect the exact proposed fields, verify the target record and keep a backup before applying game-balance or content changes.

/aisk is separately controllable in Bot Commands. Normal Discord features do not require an AI provider.

Optional utility

25. TerrainService and map data

The utilities repository includes a Windows x64 TerrainService package used by tools that need client-derived terrain or ground-height data. It is not part of a basic CMS installation and does not belong in the DOL/OpenDAoC scripts directory.

Use it when

  • A map editor requests automatic Z/ground height.
  • A placement tool explicitly reports that the terrain endpoint is unavailable.
  • The tool documentation mentions the TerrainService or DAoC client library.

Operational guidance

  • Run it on a trusted host reachable only by the editor/CMS component that needs it.
  • Keep client data/version aligned with the target world data.
  • Do not expose a local terrain endpoint publicly without authentication/firewall controls.
  • Validate returned coordinates in game before bulk placement.

DaocClientLib remains third-party work and retains its own authorship and licensing; it is not relicensed merely by being used with DAoC CMS.

Reference

26. Endpoints and APIs

DAoC CMS has a small set of integration endpoints rather than a general public REST API. Treat each endpoint according to its authentication model. Do not expose a secret-bearing example command in shell history, screenshots or tickets.

CMS endpoints

EndpointMethod and purposeAuthentication
api_events.phpPOST accepts type and message; guild-chat events also use guild and player. GET ?last_id=N returns up to five newer events.POST form field secret, checked against the configured game-server secret, bridge secret or legacy ASP_KEY. GET is intentionally public.
api_bot_config.phpGET supplies the Node bot with its token, loopback socket port/secret and active switches.X-DAOC-CMS-Bootstrap must equal BOT_BOOTSTRAP_SECRET.
bot_webhook.phpPOST receives JSON events from the Node bot and dispatches them inside the CMS.X-Webhook-Signature: sha256=<HMAC>, calculated over the raw body with the bot socket secret. The current handler skips verification if that secret is empty, so a production setup must never leave it empty.
bot_interactions.phpPOST handles Discord interaction pings and commands.Discord X-Signature-Ed25519 and X-Signature-Timestamp, verified with the configured application public key. PHP Sodium is required for this path.
ajax_status.php, ajax_restart.php, ajax_bot_start.phpBrowser actions used by authorized ACP screens.CMS session, role and request checks; these are not public automation APIs.
ajax_edit_post.php, ajax_editpost.php, ajax_reports.phpForum editing and moderation requests.Logged-in CMS user plus the applicable forum permission and CSRF controls.
rss.php, sitemap.php, robots.phpPublic discovery and syndication resources.Public; output follows the current content and visibility configuration.

Live-event examples

# Publish a server event. Use an environment variable or protected secret store in real automation.
curl -X POST "https://cms.example/api_events.php" \
  --data-urlencode "secret=REDACTED" \
  --data-urlencode "type=keep_capture" \
  --data-urlencode "message=Albion captured Caer Benowyc"

# Read events newer than ID 120
curl "https://cms.example/api_events.php?last_id=120"

The GET result has the shape {"ok":true,"events":[...]}. Each event contains id, type, message and time. Clients should retain the highest processed ID and tolerate an empty array.

AldhranConsole HTTP API

The console defaults to http://127.0.0.1:5100. /health is unauthenticated; all other routes require X-Aldhran-Secret. The CMS console client calls route names without the leading slash.

MethodRoutePurpose
GET/healthProcess health only; a successful response does not prove the bridge or game server is reachable.
GET/statusIntegrated status of console, bridge and game-facing components.
POST/players/onlineReturns which names from a supplied list are online; used by webshop delivery.
POST/kick, /privlevel, /teleport, /giveitem, /setstatsPlayer administration and item delivery.
POST/broadcast, /guildchat, /rawMessaging and advanced bridge command dispatch. Raw blocks shutdown/quit commands but remains highly privileged.
POST/restart, /heal, /revive, /freeze, /muteLive server/player operations implemented by the C# bridge.
GET/items/searchSearches compatible item records.
GET/POST/shop/cm-listings, /shop/purchaseConsignment-merchant listing and purchase integration.
GET/POST/world-forge/realms, /world-forge/upload, /world-forge/sync-realmWorld Forge realm inspection, upload and synchronization.
# Process liveness
curl http://127.0.0.1:5100/health

# Integrated status
curl -H "X-Aldhran-Secret: REDACTED" http://127.0.0.1:5100/status
Network boundary: keep AldhranConsole on loopback when the CMS is on the same machine. If it must cross hosts, use a private network or authenticated TLS reverse proxy, restrict source IPs and rotate the shared secret after any suspected disclosure.
Reference

27. Database model

DAoC CMS uses two logical data domains. The CMS database owns website users, content, settings, forum, logs and integration state. The game database remains the authority for accounts, characters, guilds, items, world data and server properties. They may be separate schemas on one server or on different MySQL hosts, provided the CMS credentials have the required access.

Browser / botrequest
CMS logicauthorization
CMS databasecommunity state
Game databaseshard state

Major CMS table families

AreaRepresentative tablesResponsibility
Identity and trustusers, user_known_devices, user_blocks, login_attempts, ip_bansCMS identity, privilege level, verification, TOTP/device state, blocks and abuse controls.
Contentpages, pages_history, pages_media, pages_templates, faq, cms_menuPublished pages, revision history, uploaded media, templates, FAQ and navigation.
Localization and appearancecms_languages, cms_translations, aldhran_themes, aldhran_styles, aldhran_styles_historyLanguage catalog, translation keys, theme definitions, CSS and style revisions.
Spike Forumspike_categories, spike_boards, spike_threads, spike_posts, spike_attachments, spike_reports, spike_notifications, spike_mentionsForum hierarchy, posts, attachments, moderation and unread/notification state.
Messagingpm_messages, cms_live_events, cms_gm_tasksPrivate messages, public live feed and staff task workflow.
Discord and botcms_bot_settings, cms_bot_commands, cms_bot_command_permissions, cms_bot_events, bot_debug_logsBot secrets/settings, command policy, dispatch queues and diagnostics.
AIcms_ai_settings, cms_ai_provider_keys, cms_ai_tasks, cms_ai_suggestions, cms_ai_logsProvider configuration, queued jobs, reviewed proposals and usage/error history.
Commerce and toolsshop_system_items, webshop_orders, cms_suit_templates, cms_suit_template_items, igc_zone_pointsShop catalog/delivery, reusable equipment suits and coordinate points.
Operationssettings, cms_backups, admin_logs, aldhran_logs, sys_error_log, aldhran_plugins, plugin_documentationRuntime configuration, archive inventory, audits/errors and plugin lifecycle.

Game schema compatibility

Common game tables include account, dolcharacters, guild, itemtemplate, mob, mobxitemtemplate, merchantitem, dataquest, keeps, relics, zones and server properties. Exact names, identifiers and columns differ between Dawn of Light and OpenDAoC. Use includes/game_server_compat.php or module-specific compatibility helpers instead of duplicating schema assumptions.

  • Character, guild and item identifiers can be numeric, textual or UUID-like depending on the core/schema.
  • Privacy filters must be applied before exposing Herald or account-linked character data.
  • OpenDAoC-specific editor behavior includes different mob fields and optional/default brain behavior.
  • Merchant and suit pricing can belong to different tables across supported layouts.

Connection policy

  • Use separate MySQL users for the CMS schema and game schema where practical.
  • Grant only the operations required by enabled modules. Editors and restore tools require writes; public Herald/PvE pages can operate with reads.
  • Use utf8mb4 for the CMS database.
  • Do not point setup's public-schema import or uploaded-schema option at a populated production game database: those workflows are intended to create/import a schema and can be destructive.
  • Take transactionally consistent backups before migrations, restores, bulk edits or compatibility experiments.

Migrations

Fresh setup installs the baseline schema and records migration baseline 20260812000000. Later schema changes live in migrations/. A migration file is named YYYYMMDDHHMMSS_short_description.php and returns a callable. Fresh-install SQL and migrations must converge on the same final schema.

php migrate.php --status
php migrate.php

migrate.php is CLI-only. Run status first, back up both databases, apply once, then run status again. Never mark a migration as complete manually unless you have audited and reproduced its exact effect.

Developer reference

28. Plugins, hooks and extensions

Plugins are PHP classes loaded by the CMS and therefore execute with the web process's access to files, databases and secrets. Install only reviewed source from a trusted origin. The Plugin Manager is a Super Admin operation in the effective implementation.

File and class contract

An upload is limited to 512 KB and its filename must match NamePlugin.php. The class implements PluginInterface and provides the methods below. Start with plugins/ExamplePlugin.php, but replace its demonstration remote asset with a reviewed local asset.

MethodPurpose
public static function getMetadata(): arrayReturns at least slug, display name, version and descriptive metadata. Dependencies and minimum privilege can also be declared.
__construct(PDO $db, int $userPriv, int $currentUserId)Receives the active CMS database connection and current authorization context.
initialize(): voidPer-request setup. Keep it idempotent and light.
registerHooks(): voidRegisters callbacks through cms_register_hook().
render(): stringReturns the plugin's page output where the host router invokes it.
uninstall(): boolRemoves plugin-owned state when safe and reports success. Do not delete user data silently.

Allowed hook points

HookPlacement / returnOutput handling
hook_headPublic page <head>Raw head markup; asset policy still applies.
hook_after_headerImmediately after the public headerScript-aware filtering.
hook_sidebar_navEnd of public sidebar navigationPurified HTML.
hook_footerPublic footer before </body>Purified HTML.
hook_acp_headACP <head>Raw head markup; use only reviewed local assets.
hook_acp_sidebar_navACP navigation additionsPurified HTML.
hook_acp_dashboard_topTop of ACP dashboardACP-card filtering.
hook_acp_dashboard_modulesDashboard card gridACP-card filtering.
hook_acp_register_sectionReturns ACP section registration dataStructured array.
hook_acp_register_viewReturns ACP view callable registrationStructured array/callable.

Minimal pattern

<?php
class StatusNotePlugin implements PluginInterface
{
    public static function getMetadata(): array
    {
        return [
            'slug' => 'status_note',
            'name' => 'Status Note',
            'version' => '1.0.0',
            'description' => 'Adds a small status note.',
            'dependencies' => [],
            'min_priv' => 1,
        ];
    }

    public function __construct(private PDO $db, private int $userPriv, private int $currentUserId) {}
    public function initialize(): void {}
    public function registerHooks(): void
    {
        cms_register_hook('hook_footer', fn(): string => '<p class="status-note">Shard status updated hourly.</p>');
    }
    public function render(): string { return ''; }
    public function uninstall(): bool { return true; }
}

Extension rules

  • Escape dynamic output and use prepared PDO statements.
  • Apply CMS authorization and CSRF checks to every state-changing action; metadata min_priv is not a substitute.
  • Namespace tables, settings, routes, CSS selectors and translation keys with the plugin slug.
  • Add schema changes through reversible plugin setup logic or project migrations, with clear uninstall data-retention behavior.
  • Use local CSS/JS. The core local-asset policy has no general remote CDN allowlist.
  • Never store tokens in the plugin file or return them in rendered HTML.
  • Test disabled, enabled, update and uninstall paths on a staging copy before production.
Runbook

29. Operations, updates and recovery

A reliable installation separates routine content work from privileged maintenance. Define who may deploy code, run migrations, restore data, rotate secrets and operate the live bridge. Keep a written recovery path that still works when the CMS itself is unavailable.

Recommended maintenance cycle

  1. Announce a maintenance window if game or account data may be affected.
  2. Enable maintenance mode and verify that authorized staff retain access.
  3. Back up CMS files, CMS database and game database. Copy the verified archive off the web host.
  4. Review the target published release notes, PHP/MySQL requirements and migration status.
  5. Deploy the published release through the same method used for the installation.
  6. Run php migrate.php --status, then php migrate.php if pending migrations exist.
  7. Clear the CMS/CSS cache and reset OPcache through the Cache ACP section or the host process.
  8. Smoke-test login, ACP, content, forum, game-database pages and every enabled integration.
  9. Disable maintenance mode, monitor error/audit logs and retain the pre-change backup until the release is stable.

Git-based update

git status
git fetch origin
git pull --ff-only origin main
php migrate.php --status
php migrate.php

Do not pull over unexplained local modifications. Commit the customization on a separate branch or recreate it as a maintained plugin/theme. The ACP update widget compares VERSION, local Git revision and published GitHub releases; it is informational and follows the published-release policy.

Backup Manager

The ACP backup feature can archive site files and create dumps of the CMS and game databases. ZIP and 7-Zip workflows are supported when their executables are configured. Database export/import uses the configured mysqldump and mysql paths. Built-in Windows/XAMPP-looking paths are examples, not requirements—set the actual executable paths on the host.

  • Add a clear description and optional PIN according to your operational policy.
  • Run archive verification and check that both database dumps are present.
  • Download or replicate backups to a separate system with restricted access.
  • Periodically restore into an isolated environment; an untested archive is not a recovery plan.
  • Restore modes can target all data, databases, ACP/CMS data or game data. Resolve the exact selection before confirming because restore overwrites live state.
Restore is destructive. Capture a fresh emergency backup first, stop writes from users/bots/workers, verify the selected archive and target databases, then restore. Test login and database compatibility before reopening service.

Schedulers and background work

WorkerTypical cadenceResponsibility
cron_ai_worker.phpBased on expected task volumeProcesses queued AI work and suggestion tasks. Run only when the AI subsystem is intentionally configured.
includes/cron_webshop_worker.phpEvery 30–60 secondsChecks pending recipients through AldhranConsole and delivers paid items when the player is online. Stops retrying an order after ten failed delivery attempts.
Bot processContinuous serviceRuns node assets/js/bot.js; use a service manager with restart limits and protected environment variables.
AldhranConsoleContinuous serviceHosts the local HTTP API and maintains access to the game bridge/database.
# Linux cron example; replace paths and PHP binary
* * * * * /usr/bin/php /var/www/daoc-cms/includes/cron_webshop_worker.php >> /var/log/daoc-webshop.log 2>&1

# Windows Task Scheduler action example
Program:   C:\php\php.exe
Arguments: C:\sites\daoc-cms\includes\cron_webshop_worker.php

Cache behavior

The Cache ACP section bumps the CSS asset version and can reset OPcache. Browser responses may retain ETag/cache state for up to 24 hours. After a theme or stylesheet deployment, clear server-side caches first, then hard-refresh one test browser before diagnosing the code as stale.

Logs and retention

  • Admin logs: privileged actions and actor context.
  • Aldhran logs: bridge/integration activity.
  • System error log: captured application errors; PHP also writes to php_errors.log when configured by the CMS bootstrap.
  • Bot debug/event logs: configuration, socket, webhook and command troubleshooting.
  • Web server, PHP, Node, service and game logs: required for failures that occur before CMS logging starts.

IP addresses recorded by CMS audit helpers are anonymized at the last IPv4 octet or final IPv6 component. Some security records are pruned after 30 days and unverified registrations after seven days; external infrastructure logs follow their own retention policy.

Daily health checklist

  • Public homepage and login load over HTTPS without warnings.
  • CMS and game database connections succeed.
  • No unexpected maintenance banner or critical-integrity alert is present.
  • Recent error/admin logs contain no unexplained spike.
  • AldhranConsole /health and authenticated /status match expected state.
  • Bot process, commands and any guild-chat relay operate in the intended guild.
  • Pending webshop orders are not accumulating at the retry limit.
  • The latest off-host backup exists and the last restore test is still within policy.
Hardening

30. Security model and production checklist

DAoC CMS contains layered controls—strict sessions, CSRF validation, role checks, prepared statements, upload validation, rate limits, audit logs and web-server deny rules—but secure deployment still depends on the surrounding host and correct secrets. A feature being reachable only from the ACP does not make its network calls safe by default.

Built-in protections

  • Session cookies are HTTP-only, SameSite Strict, Secure and tied to an instance-specific name; strict/only-cookie modes are enabled and the default session lifetime is one hour.
  • ACP access begins at privilege level 3. Sensitive level-5 access requires TOTP and privileged operations use recent-authentication controls.
  • CSRF tokens protect state-changing browser actions, while integration endpoints use dedicated secrets, HMAC or Ed25519 signatures.
  • Core database paths use prepared PDO statements and compatibility-aware helpers.
  • Upload paths check extension/MIME and are protected by server rules; directory indexing is disabled by the supplied .htaccess.
  • Configuration, database helpers, logs, SQL/YAML files, dependency manifests, migrations, hidden files and backup content are denied by the Apache rules.
  • Production PHP error display is disabled while server-side logging remains active.

Required production controls

  • Serve the entire site through HTTPS and redirect HTTP before application handling. Secure session cookies will not work correctly on plain HTTP.
  • Keep includes/config.php outside backups shared with untrusted parties and deny it at the web server even when not using Apache.
  • Delete or web-deny setup/ after installation and retain install.lock.
  • Use a dedicated OS account for the web process; grant write access only to required upload, cache, backup, plugin and configuration paths.
  • Use strong, unique values for password pepper, ASP_KEY, Aldhran shared secret, bot bootstrap secret, bot socket secret, database passwords, Discord token and provider keys.
  • Restrict MySQL to required hosts and use least-privilege accounts; never expose port 3306 to the public internet.
  • Bind AldhranConsole and the Node bot socket to loopback when possible. Firewall game bridge and management ports.
  • Require TOTP for all Super Admins, keep the group very small and never share administrator accounts.
  • Keep backups encrypted/restricted and off-host; they contain credentials, private messages and account/game data.
  • Review and patch PHP, web server, MySQL, Node.js, .NET and the operating system on a defined schedule.

Secret inventory and rotation

SecretConsumersRotation effect
Password pepper / ALDHRAN_PEPPERCMS password processingChanging it can invalidate existing password verification. Plan a migration/reset path; do not casually rotate.
ASP_KEYLegacy/fallback server integrationsUpdate every remaining consumer; prefer a feature-specific secret where supported.
Game-server/Aldhran shared secretCMS, AldhranConsole and AldhranBridge/event scriptsRestart/reload components after updating both sides; mismatches return 401 or bridge authentication errors.
BOT_BOOTSTRAP_SECRETNode bot startup → api_bot_config.phpUpdate the bot environment and restart it.
Bot socket secretNode bot, CMS webhooks/socket dispatchUpdate ACP state and bot configuration together; confirm webhook signatures afterward.
Discord token/public keyNode login / interaction verificationReset token in Discord, save in ACP and restart. Public key is not confidential but must be authentic.
AI/API keys and SMTP keyOptional outbound providersRotate at provider, update the encrypted CMS setting, then send a limited test request.

Reverse proxy and non-Apache servers

The bundled .htaccess protects Apache deployments only. Recreate the deny rules in nginx, IIS or the chosen proxy. Preserve the real client IP only from trusted proxy addresses, set HTTPS forwarding correctly and do not allow direct access to the backend that bypasses TLS or path restrictions.

Incident response

  1. Contain: enable maintenance mode, restrict ingress or stop affected bot/bridge services.
  2. Preserve: snapshot relevant logs and database/files before cleanup.
  3. Scope: identify account, secret, endpoint, host and time range involved.
  4. Rotate exposed feature secrets and revoke sessions/tokens. Treat a leaked database or config backup as multiple secret exposures.
  5. Repair from a known-good release or verified backup; apply patches and migrations.
  6. Validate integrity, privileged accounts, plugins, scheduled tasks and bridge scripts before reopening.
  7. Document the event and prevention changes without publishing credentials or an exploitable proof before users can patch.
Plugin boundary: an enabled plugin is trusted PHP code, not sandboxed content. Reviewing metadata in the UI is insufficient; review the complete source and any network/SQL behavior before activation.
Diagnosis

31. Troubleshooting guide

Start with the smallest failing boundary. Record the exact URL/action, timestamp, HTTP status or exception, active core type and recent change. Test from the same host and user context as the failing component; a successful request from an administrator workstation may not prove reachability from PHP, Node or the game process.

SymptomLikely causesChecks and correction
Setup redirects or reports already installedinstall.lock exists or setup is web-denied.Do not delete the lock on a live installation. For an intentional clean reinstall, back up and recreate an empty target environment first.
Requirement/permission check is redPHP below 8.2, missing PDO/MySQL/JSON/cURL/ZIP/Fileinfo/Zlib, or unwritable required paths.Compare web-PHP and CLI-PHP versions/modules. Grant the web process minimal write access to the paths named by the installer.
CMS database test failsHost/port/user error, missing create-table rights during test/install, TLS/firewall or wrong MySQL server.Connect from the web host with the same credentials; verify the empty CMS schema and MySQL 8 compatibility.
Login loops or never persistsSite is served over HTTP while cookies are Secure, proxy HTTPS headers are wrong, or hostname/path changed.Use HTTPS, correct trusted-proxy forwarding and verify the browser receives the instance-specific session cookie.
ACP access deniedPrivilege below 3, stale session, recent-authentication expired, or level-5 TOTP not complete.Confirm the user's effective level and reauthenticate. Repair account state through a controlled database procedure only if no valid Super Admin remains.
Unknown column/table in Herald, PvE or editorWrong game_server_core, custom schema drift or incomplete public schema.Select DOL/OpenDAoC correctly, compare the failing query with the real schema and extend compatibility helpers rather than hard-coding one fork.
C# script fails with CS compiler errorsSource API differs from the target game-server release.Run Test-OpenDAoCScripts.ps1 against the exact release folder and fix the reported symbol/type incompatibility.
Game server reports bad IL / invalid programScript was compiled against mismatched assemblies or by a different pipeline.Use Build-OpenDAoCScriptAssembly.ps1 against the exact target release and deploy the resulting compatible assembly/source as required by that core.
AldhranConsole /health works but CMS commands failHealth only proves the HTTP process. Secret, BridgeHost/Port, game script or firewall can still fail.Call authenticated /status, inspect console and game logs, then test TCP reachability to bridge port 2000 (or configured value).
AldhranConsole returns 401X-Aldhran-Secret differs from SharedSecret.Compare exact values without posting them publicly; remove surrounding whitespace, update both sides and restart/reload.
CMS reports console unreachable / 502Wrong host/port, console stopped, loopback used across different machines, or firewall.From the PHP host, request /health. Use the console host's private address only when services are on separate hosts and secure that route.
Discord bot is online but slash commands are absentMissing application-command installation, registration REST error, wrong guild or stale Discord client cache.Check Node log for successful global and per-guild registration, reinstall with command support, restart the bot and test in a guild it joined.
Discord bot cannot load configWrong DAOC_CMS_CONFIG_URL, bootstrap secret, TLS trust or HTTP routing.Request the URL from the bot host with the header, check 401/404/TLS output, then restart after correction.
Bot socket test failsNode process stopped, host/port mismatch, secret mismatch or port bound only on another host.Confirm the process is listening on the configured loopback port (default 15000) and that CMS and bot use the same socket secret.
Guild chat works in game but not DiscordGuild sync disabled, no discord_channel_id, bot cannot send to channel, or event secret mismatch.Enable sync, map/create the guild channel, verify channel permission, then inspect api_events.php and bot event logs.
Live feed stays emptyC# event script missing/not loaded, endpoint/secret wrong, or browser is polling a different CMS instance.POST a safe manual event, inspect response/logs and verify INSTANCE_ID/site URL and game script configuration.
Webshop order remains pendingWorker not scheduled, player offline, Aldhran presence call fails, item ID invalid or ten-attempt limit reached.Run the worker once in a console, inspect its log and order fields, verify /players/online and /giveitem with a staging item.
Theme/CSS change not visibleCMS CSS version, OPcache, proxy cache or browser ETag cache is stale.Use ACP Cache, reset OPcache if applicable, purge the trusted proxy cache and hard-refresh.
Critical security banner appearsAudit-integrity anomaly or IP-registration threshold triggered.Do not suppress it first. Preserve logs, review recent administrator/account actions and determine whether it is attack traffic, corruption or a known maintenance effect.
Game log shows network error 10060 / UPnPGame-server port mapping or outbound network timeout.Diagnose the game server's UPnP/router settings separately. It is not evidence that the CMS HTTP or Aldhran bridge secret is wrong.

OpenDAoC script diagnostic commands

.\tools\Test-OpenDAoCScripts.ps1 -ReleasePath "C:\Path\To\OpenDAoC\Release"
.\tools\Build-OpenDAoCScriptAssembly.ps1 -ReleasePath "C:\Path\To\OpenDAoC\Release"

The tools compile against the complete source tree and the exact target release assemblies, which distinguishes normal C# compile failures from runtime bad-IL/assembly mismatches.

Evidence to include in a useful bug report

  • DAoC CMS version from VERSION and Git commit if installed from Git.
  • Game core (DOL/OpenDAoC), exact release/fork and database schema version.
  • PHP, MySQL, web server, operating system and—where relevant—Node/.NET versions.
  • Exact reproduction steps, expected result, actual result and timestamp/timezone.
  • Sanitized error text and the relevant narrow log window.
  • Whether the problem reproduces with custom plugins/theme disabled in a staging copy.
Sanitize first: remove session cookies, database DSNs/passwords, Discord tokens, bootstrap/shared/socket secrets, private keys, authorization headers and personal player/account data. Do not redact the error class, file/line or non-secret schema names needed to diagnose the issue.
Contributing

32. Development workflow

The main application repository is github.com/Darku11/daoc_cms. C# bridges, AldhranConsole, terrain package and compatibility tools live in github.com/Darku11/daoc_cms_utilities. Keep changes focused and test every affected boundary.

Local preparation

git clone https://github.com/Darku11/daoc_cms.git
cd daoc_cms
git switch -c fix/short-description
php -v
php -m

Use a disposable CMS database and a copy or purpose-built public game schema. Never develop destructive editors against the only production database. Enable visible errors only in the isolated development environment; production should retain server-side logging.

Project structure

PathResponsibility
index.php, header.php, sidebar.php, footer.phpPublic routing and shared layout.
acp.phpACP routing, section authorization and view loading.
includes/Database/bootstrap, compatibility, integrations, hooks, AI, bot, templates, errors, update and shared services.
modules/Public and ACP logic/view modules. Preserve separation where a module has explicit _logic and _view files.
setup/Installer, schema sources, configuration writer and downloadable bridge assets.
migrations/Ordered upgrades for installed systems.
plugins/Optional trusted PHP extensions.
templates/, themes/styles tablesLayout rendering and database-backed appearance.
tests/Automated checks currently included with the project; extend for regressions.

Change checklist

  • Reproduce the issue and write down the affected core/schema.
  • Keep SQL prepared and route schema differences through compatibility helpers.
  • Add role, recent-auth, TOTP and CSRF checks appropriate to the operation.
  • Escape browser output and validate uploaded files/JSON/IDs at the boundary.
  • Update both fresh-install schema and a timestamped migration for structural database changes.
  • Add/update translations rather than embedding new user-facing strings where the module is localized.
  • Test DOL and OpenDAoC for shared game-data logic or clearly mark the feature core-specific.
  • Test fresh install, upgrade, maintenance mode and a non-Super-Admin role relevant to the feature.
  • Check logs for new warnings and verify no secrets or generated configuration entered the commit.
  • Update documentation and release notes for configuration, migration, endpoint or deployment changes.

PHP checks

# Syntax-check tracked PHP files
git ls-files '*.php' | while read -r file; do php -l "$file" || exit 1; done

# Migration state against the development database
php migrate.php --status

The repository includes tests/DeviceCheckTest.php; run it with the compatible test runner available in the development environment. The absence of a broad packaged test suite means linting and a documented manual matrix remain important.

AldhranConsole development

cd AldhranConsole
dotnet restore
dotnet build
dotnet run

The current project targets net10.0, version 2.6.0, and uses MySqlConnector 2.6.1. Configure a development-only appsettings.json; never commit real connection strings or shared secrets.

Pull requests

Small fixes, documentation and translations can be submitted directly. Discuss larger features or architecture first. Describe the reason, testing, core compatibility, database/config changes and operational impact. Contributions are distributed under GPL-3.0-only and must not import incompatible third-party material.

Project information

33. License, support and glossary

License

DAoC CMS project-owned source is licensed under the GNU General Public License v3.0 only (GPL-3.0-only). The repository LICENSE contains the controlling terms. Bundled or referenced third-party components, game data, fonts, images and other assets retain their original copyright and license notices; a DAoC CMS SPDX header does not override those terms.

Contributors retain copyright in their own contributions and agree that submitted work is distributed under GPL-3.0-only. Modified redistributions must satisfy the GPL, preserve applicable notices and identify modifications as required by the license. This summary is operational guidance, not a substitute for the license text.

Support and reporting

Report exploitable security issues privately first; do not open a public issue containing an active exploit, secret or private dataset. Include a safe impact description, affected version and a private reproduction path.

Glossary

TermMeaning in this documentation
ACPAdministration Control Panel, reached through acp.php.
AuthLevel / privilege levelCMS authorization scale from Guest/0 through Super Admin/5. Game-server privileges are related operationally but must not be assumed identical in every core.
DOLDawn of Light game-server implementation/schema family.
OpenDAoCSupported DOL-derived server implementation with schema/API differences handled by compatibility code.
AldhranConsole.NET HTTP management service used by the CMS and integrations.
AldhranBridgeC# game-server script accepting authenticated TCP commands from AldhranConsole.
CMSLiveEventsC# game-server script that publishes selected game events to api_events.php.
GuildChatBridgeC# script that preserves guild-command checks and relays eligible guild chat to the CMS/Discord path.
Minimal integrationWebsite/community features with CMS and game database access but without live C#/.NET/Node services.
Full integrationCMS plus compatible game schema, live bridge/console, selected C# scripts and optional Discord/worker services.
MigrationOrdered, code-owned database change applied by CLI to bring an existing installation forward.
Public game schemaA schema/data subset intended for public CMS features; it is not a substitute for understanding the production core's real schema.

Final production acceptance

  • Version and chosen game core are recorded.
  • Setup is locked and protected; HTTPS and secure sessions work.
  • CMS and game database permissions match enabled features.
  • At least two authorized operators can access the ACP, with level-5 TOTP verified.
  • Backups are verified off-host and a restore has been tested.
  • Every enabled bridge, bot, event, guild-chat and worker path passes its own test.
  • Secrets are unique, stored outside source control and covered by a rotation procedure.
  • Monitoring/log retention and a maintenance/update owner are defined.

Documentation baseline: DAoC CMS 1.0.0-rc2 and the matching utilities repository state reviewed on 13 August 2026. For later releases, read published release notes and migrations before treating a field, route or default as unchanged.

No documentation section matches this search.