Highclere Castle Ticketing & Commerce · Disaster Recovery Programme Updated: October 2026 · Status: Phase 0 & Component 1 Ready
System Architecture

Clean PostgreSQL core.
Decoupled TypeScript domain.

The architecture is designed around two non-negotiable constraints: immediate delivery speed for disaster recovery and strict separation of concerns so legacy database quirks never pollute the new codebase.

Transition Topology

How Public Traffic, Clean PostgreSQL, and NetBird Legacy Admin Coexist

┌────────────────────────────────────────────────────────────────────────────────┐
│                        PUBLIC INTERNET (Cloudflare WAF)                        │
└───────────────────────────────────────┬────────────────────────────────────────┘
                                        │ HTTPS (highclerecastleshop.co.uk)
                                        ▼
┌────────────────────────────────────────────────────────────────────────────────┐
│                 NEW APPLICATION SERVER (Debian / Docker / Node.js)             │
│                                                                                │
│  ┌──────────────────────────────┐        ┌──────────────────────────────────┐  │
│  │ Astro SSR + Svelte Islands   │───────▶│ Framework-Agnostic Domain Layer  │  │
│  │ (Thin Presentation Views)    │        │ (src/domain/*, Hono API, Zod)    │  │
│  └──────────────────────────────┘        └─────────────────┬────────────────┘  │
│                                                            │                   │
│                                                            ▼                   │
│                                          ┌──────────────────────────────────┐  │
│                                          │ Clean PostgreSQL Database        │  │
│                                          │ (Managed via Drizzle Migrations) │  │
│                                          └─────────────────▲────────────────┘  │
└────────────────────────────────────────────────────────────┼───────────────────┘
                                                             │
                                 Idempotent ETL Sync         │ (Every 1–2 mins:
                                 (ON CONFLICT DO UPDATE)     │  users, orders,
                                                             │  order_item, vouchers)
┌────────────────────────────────────────────────────────────┼───────────────────┐
│              PRIVATE NETBIRD VPN MESH (No Public Ingress)  │                   │
│                                                            │                   │
│  ┌──────────────────────────────┐        ┌─────────────────┴────────────────┐  │
│  │ Office Staff Browsers        │───────▶│ Legacy PHP 7.4 (/admin only)     │  │
│  │ (Order Lookup & Gate Lists)  │        │ + Legacy MariaDB 10.11           │  │
│  └──────────────────────────────┘        └──────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────────────────────┘
Technology Choices

Core Stack & Layer Responsibilities

Presentation Layer

Astro SSR (@astrojs/node) + Svelte Islands

Server-rendered HTML for fast ticket loading on mobile connections at the Castle gates, paired with Svelte islands for interactive calendars and admin tables in Components 2–4.

Domain & API Layer

Pure TypeScript + Hono + Zod

All business rules (src/domain/), barcode generation, Postmark email dispatch, and API routes live outside .astro files—making UI retooling effortless if ever required.

Persistence & Migration

PostgreSQL + Drizzle ORM

Replaces legacy MyISAM tables with ACID transactions, foreign keys, TIMESTAMPTZ, row-level locking for ticket capacity, and transactional schema migrations.

Brand & Visual Identity

Distinguishing Ticketing & Commerce from Friends of Highclere

While sharing heritage typography (Cormorant Garamond + Jost) and sharp architectural border-radius: 0 geometry with Friends of Highclere, this platform uses its own distinct colour system so customers immediately recognise which Highclere property they are using:

Highclere Ticketing & Commerce (This Site)

Palette: Estate Forest Green (#1d3b2a), Burnished Brass (#9a7832), and Warm Parchment (#f6f3ec).
Character: Parkland gates, formal printed admission tickets, clarity under outdoor mobile use.

Friends of Highclere Castle (Sibling Product)

Palette: Deep Crimson (#572130), Soft Teal (#A0D1CA), and Warm Stone (#f7f4f0).
Character: Intimate drawing-room club, editorial video archive, and member community.

Architectural Decision Records

Recorded Decisions (docs/adr/)

ADR-0001: Clean PostgreSQL Schema with Idempotent Legacy MariaDB ETL Sync

Accepted

During disaster recovery, the legacy CodeIgniter 3 / MariaDB 10.11 application is restricted to internal staff over NetBird VPN for back-office operations, while customer-facing functionality is rebuilt incrementally in Node.js and Astro. Rather than coupling the new application to the legacy 118-table MariaDB schema or waiting to rebuild the back office before launching, the new application will exclusively query a clean PostgreSQL database managed via Drizzle migrations, populated from the legacy MariaDB database via a scheduled, idempotent ETL sync (ON CONFLICT DO UPDATE). Once back-office workflows are migrated to the new application, the ETL sync and legacy MariaDB instance will be retired with zero changes required in the new application's domain or data-access code.

ADR-0002: Passwordless Customer Auth and Email-Based Account Consolidation

Accepted

The legacy users table stored passwords in plaintext and permitted multiple rows with the same email address. Rather than migrating compromised plaintext passwords or perpetuating duplicate accounts, the new PostgreSQL schema consolidates Customer records by normalised email address and authenticates customers via Email OTP / Magic Link (or single-order lookup using Order Number, Email, and Billing Postcode). Because the legacy Gate List barcode format ({order_number}-{order_item_id}-{user_id}) embeds the original MariaDB users.id, each migrated Order preserves its original legacy_user_id so generated barcodes remain 100% compatible with on-site gate scanners.

ADR-0003: Astro SSR with Framework-Agnostic Domain Layer and Svelte Islands

Accepted

To maximise delivery speed during disaster recovery, the application will use Astro SSR (@astrojs/node) with Svelte islands for interactive widgets, leveraging existing team familiarity with Astro. Because Astro is content-first and may hit ergonomic limits as complex interactive workflows (Coach Portal, Timed-Entry Checkout, Staff Back-Office) are added, all database schemas (src/db/), ETL pipelines (src/etl/), business rules (src/domain/), and HTTP API handlers (src/api/ via Hono) must be written in framework-agnostic TypeScript. .astro pages must act strictly as thin view templates calling into src/domain/ or src/api/, ensuring the presentation layer can be swapped to SvelteKit or another full-stack framework later without rewriting domain or data logic.