← Portfolio

Technical Documentation

Custom CMS & Admin Panel

A bespoke full-stack content management system built from scratch — public PHP site, local Python admin backend, dual-mode storage

Python · JavaScript · CSS · PHP · SQLite · Jest · pytest  ·  Live


Origin

This system was built for a non-profit operating in a hostile political environment. I was genuinely worried about retaliation, hacking, and exposure — so the architecture started from a question: what's the safest possible publishing setup for an organization that can't afford to be compromised? The answer was local-first. If the admin never runs in the cloud, there's nothing to breach remotely. Every other decision followed from that constraint.


Overview

This is a purpose-built content management system designed around a specific operational constraint: a single operator managing a public-facing website entirely from a local machine, with no cloud CMS, no third-party admin interface, and no unnecessary dependencies. Every part of the system — from the storage layer to the publish workflow — was designed to serve that constraint precisely.

The public site is intentionally lightweight: PHP, JSON, and vanilla JavaScript. The local admin panel is a sophisticated browser UI backed by a Python standard-library HTTP server with modular handlers, a dual-mode SQLite/JSON storage adapter, and an extensive suite of utility scripts covering post ingestion, media backup, QR tracking, access log analytics, resource management, and publishing.

The architecture was shaped by a deliberate choice to avoid external dependencies wherever possible. The Python backend uses only the standard library. The public site consumes static JSON files. The admin panel runs locally and publishes to a remote PHP host — a workflow that influenced every design decision in the system.

The codebase includes Python unit tests via pytest, frontend tests via Jest, and documentation covering current architecture, admin workflows, operations and maintenance, and a full configuration reference.


Project Map

site/                          Public website
site/posts.json                Published posts data
site/action/action-items.json  Published action artwork and download data
site/resources/resources.json  Published resources sections and cards
site/wikipedia-tracker/        Public Wikipedia tracker config, cache, PHP API

admin-panel/                   Local admin UI
admin-panel/index.html         Admin shell and tab markup
admin-panel/_resources/js/     Admin ES modules and Jest tests
admin-panel/_resources/python/ Python backend, scripts, handlers, tests
admin-panel/_resources/data/   SQLite database and QR history data

_commands/                     macOS command launchers, test helpers, migrations
_config/                       Templates and local configuration examples
_assets/docs/                  Current docs and historical plans and reports
_production_logs/              Local synced access log input

Storage Model

The backend uses a dual-mode storage adapter that supports both SQLite and JSON, selectable via configuration. Active admin operations prefer SQLite; the public site consumes JSON files under site/ . Handlers that mutate SQLite state sync back to JSON as part of the publish workflow.


Admin Panel Capabilities

Posts

Post ingestion pipeline

The ingestion pipeline handles the full lifecycle of bringing a new post into the system. Each step is automated where possible and logged where not:

Action items

QR system

Resources

Access log analytics

Wikipedia tracker

Publishing and export


Tech Stack

Public site PHP, JSON, vanilla JavaScript
Admin UI HTML, CSS, ES modules (vanilla JS)
Admin backend Python 3, standard library HTTP server
Storage SQLite (primary), JSON (legacy / public consumption)
Frontend tests Jest
Backend tests pytest
Platform macOS (local admin), Apache (production host)

Backend Architecture

The Python backend is built entirely on the standard library — no Flask, no Django, no third-party web framework. The HTTP server dispatches requests to modular handlers, each responsible for a discrete feature area. This architecture makes it straightforward to add, test, or remove handlers independently.

Starting the backend

cd admin-panel/_resources/python
./setup_venv.sh
python3 simple_server.py

The configured admin start port is 5500, with up to 10 attempts for the next free port.

Starting the public site

open "_commands/ports_and_servers/servers/launch_PHP.command"

Combined launcher

open "_commands/CLEAN+LAUNCH.command"

Running tests

# Python backend tests
cd admin-panel/_resources/python
python3 -m pytest

# Frontend tests
cd admin-panel/_resources/js
npm test

Documentation Structure

The project maintains a layered documentation system covering current state, historical decisions, and operational procedures:


Security Baseline

The admin panel is designed to run locally or behind trusted network controls. A code review identified the absence of active admin authentication in simple_server.py . The following are documented as required before any public or network exposure:

None of these represent an architectural constraint — they are known gaps, deliberately deferred given the local-only operational model, and clearly documented for any future deployment that changes that assumption.