Headless CMS replacement for The Triangle, with:
server/Go APIfrontend/React frontendobservability/Loki + Promtail + Grafanascripts/local setup helpers
API docs and data models: https://github.com/DrexelTriangle/triangle-cms/wiki
- Python 3.10+
- Git
- Docker + Docker Compose
- Go 1.24+
- Node.js 20+ + npm
Create a triangle directory first, then clone triangle-cms into it
(triangle-cms contains the setup script):
mkdir triangle
cd triangle
git clone https://github.com/DrexelTriangle/triangle-cms.git
cd triangle-cmsThen run:
python ./scripts/first_time_setup.pyWhen run from inside triangle/triangle-cms, this installs dependencies for the current checkout and clones:
wordpress-etlScaleneas sibling directories insidetriangle/.
If you want a custom location, set --target-dir explicitly.
This prepares and installs dependencies for:
triangle-cmswordpress-etlScalene
Optional flags:
--pullto update already-cloned repos (git pull --ff-only)--skip-embeddingsto skipsentence-transformersinstall inwordpress-etl
- Create Docker env vars for required secrets:
cp .env.example .envUpdate .env with strong values before running Compose.
- Generate ETL SQL in
wordpress-etl:
cd ../wordpress-etl
.venv/bin/python main.pyWindows PowerShell:
cd ../wordpress-etl
.venv/Scripts/python.exe main.pyFor embeddings SQL:
cd ../wordpress-etl
.venv/bin/python main.py --generate-embeddings- Copy ETL SQL into CMS bootstrap files:
cd ../triangle-cms
python ./scripts/generate_wordpress_sql.py- Start services (Path A is recommended):
Path A (recommended): full Docker stack (CMS + observability):
python ./scripts/setup_containers.pyThis stack uses a shared Docker bridge network scoped to the Compose project, so services can resolve each other by container/service name (for example mariadb, loki, grafana).
Path B: Docker MariaDB + local Go backend:
docker compose up -d mariadbThen run backend locally:
cd server
go run ./main.go- Verify API (works with either path):
curl -k https://localhost:8080/v1/articles/christmas- Run the Triangle CMS frontend dashboard:
cd frontend
npm run dev -- --port 5173Frontend dashboard: http://localhost:5173
- Run Scalene frontend:
cd ../Scalene
npm run dev -- --port 4321Scalene: http://localhost:4321
Reset DB + logs (fresh install):
python ./scripts/setup_containers.py --reset-dataRun backend locally (instead of Docker cms service):
docker compose stop cms
cd server
go run ./main.goIf running backend locally against Docker MariaDB, create server/.env:
DB_NAME=triangle
DB_USER=triangle_user
DB_PASSWORD=triangle_password
DB_HOST=127.0.0.1
DB_PORT=3306Run Triangle CMS frontend dashboard:
cd frontend
npm run dev -- --port 5173Frontend dashboard: http://localhost:5173
Note
If you want Scalene to use your local CMS instead of our production WordPress you need to be on the CMS-Testing branch
Use git switch CMS-Testing to switch
Run Scalene:
cd ../Scalene
npm run dev -- --port 4321Scalene: http://localhost:4321
Default usage:
python ./scripts/generate_wordpress_sql.pyOptional override usage:
python ./scripts/generate_wordpress_sql.py [source_sql_dir] [output_dir]Environment variable overrides:
WP_ETL_SQL_DIR=../wordpress-etl/logs/sql WP_ETL_OUT_DIR=server/internal/database/wordpress_etl python ./scripts/generate_wordpress_sql.pyGenerated files:
01-authors.sql02-articles.sql03-articles-authors.sql04-seo.sql05-article-embeddings.sql(real file when available, placeholder otherwise)06-taxonomy.sql
cd server
go test ./...Coverage:
cd server
go test -coverprofile=cover.out ./...