Toolvana: production-ready media tools platform (CodeIgniter 4)
- 134-tool registry with programmatic SEO (unique titles/H1/descriptions, JSON-LD graphs, sitemap index, canonical 301 enforcement via required filter) - DB-backed job queue (SKIP LOCKED) with drivers: Ffmpeg, Images (GD), Pdf (qpdf/gs/poppler), Youtube (thumbnails), Qr (server-side PNG) - Security: SSRF guard, MIME validation, rate limits, API-key auth, bcrypt admin login, security headers - Admin panel: dashboard, tools/categories/guides CRUD, SEO audit, analytics, job inspector with retry, system health, feature flags - Docker deployment (nginx + web/api FPM pools + scalable workers), PHPUnit suite (19 tests / 1139 assertions), PWA manifest + service worker
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
# ---------------------------------------------------------------------------
|
||||
# Toolvana production topology.
|
||||
#
|
||||
# browser -> nginx -> php-fpm (web) stateless, page-cached
|
||||
# -> api (php-fpm) /api/v1 traffic isolation
|
||||
#
|
||||
# queue: postgres/mysql durable jobs; workers scale horizontally:
|
||||
# worker-1 .. worker-N (spark queue:work --loop)
|
||||
# scheduler (media:cleanup every 5 min + stale reaper)
|
||||
#
|
||||
# Replace the DB image or add Redis freely — the app only needs a
|
||||
# PDO-compatible database and the file cache driver works everywhere.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
x-app-common: &app-common
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile
|
||||
restart: unless-stopped
|
||||
env_file: .env.docker
|
||||
volumes:
|
||||
- media-storage:/app/writable/media
|
||||
- incoming-storage:/app/writable/incoming
|
||||
- session-storage:/app/writable/session
|
||||
- og-cache:/app/writable/og
|
||||
|
||||
services:
|
||||
nginx:
|
||||
image: nginx:1.27-alpine
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443" # mount certs + full server block for TLS in production
|
||||
volumes:
|
||||
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
- ./public:/app/public:ro
|
||||
- ./writable/og:/app/writable/og:ro
|
||||
depends_on:
|
||||
- web
|
||||
- api
|
||||
|
||||
web:
|
||||
<<: *app-common
|
||||
environment:
|
||||
TV_ROLE: web
|
||||
|
||||
# Dedicated pool for developer API + processing endpoints so large
|
||||
# conversions never starve page rendering.
|
||||
api:
|
||||
<<: *app-common
|
||||
environment:
|
||||
TV_ROLE: api
|
||||
|
||||
worker-1:
|
||||
<<: *app-common
|
||||
command: ["php", "spark", "queue:work", "--loop", "--sleep", "2"]
|
||||
deploy:
|
||||
replicas: 3 # worker-1..worker-N: scale to taste
|
||||
|
||||
scheduler:
|
||||
<<: *app-common
|
||||
command: >
|
||||
bash -c "while true; do
|
||||
php spark media:cleanup >> writable/logs/scheduler.log 2>&1;
|
||||
sleep 300;
|
||||
done"
|
||||
|
||||
db:
|
||||
image: mariadb:11
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MARIADB_DATABASE: toolvana
|
||||
MARIADB_USER: toolvana
|
||||
MARIADB_PASSWORD: ${DB_PASSWORD:-toolvana}
|
||||
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-root-secret}
|
||||
volumes:
|
||||
- db-data:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||
interval: 10s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
db-data:
|
||||
media-storage:
|
||||
incoming-storage:
|
||||
session-storage:
|
||||
og-cache:
|
||||
Reference in New Issue
Block a user