feat: 🚀 Initialize TSYS Developer Support Stack demo environment

- Add comprehensive Docker Compose configuration with 16 developer services
- Configure Homepage dashboard with service discovery and grouping
- Set up environment configuration for demo deployment
- Include project documentation (PRD, README, User Guide, Agent guidelines)
- Establish foundation for developer tooling stack with proper networking and security

Services include developer tools (Homepage, Atuin, Wakapi, ArchiveBox, Tube Archivist, MailHog),
infrastructure (PostgreSQL, Elasticsearch, Redis, Docker Socket Proxy),
monitoring (InfluxDB, Grafana), and documentation (Draw.io, Kroki).
This commit is contained in:
TSYSDevStack Team
2025-11-13 17:35:34 -05:00
parent f6437abf0d
commit 0785722981
8 changed files with 1814 additions and 0 deletions

View File

@@ -0,0 +1,545 @@
---
# TSYS Developer Support Stack - Docker Compose Configuration for Demo
#
# NOTE: This configuration uses only Docker named volumes for storage, not bind mounts.
# All data is ephemeral and will be lost when the stack is removed with 'docker compose down -v'.
# This is intentional for the demo environment to ensure no persistent data accumulation.
#
services:
# Homepage - Developer dashboard
homepage:
image: ghcr.io/gethomepage/homepage:latest
container_name: tsysdevstack-supportstack-homepage
ports:
- "${HOMEPAGE_PORT}:3000"
volumes:
- ./homepage/config:/app/config:ro,Z # Demo: read-only config mount for functionality
# Running as root to avoid permission issues in demo
labels:
- "homepage.group=Developer Tools"
- "homepage.name=Homepage"
- "homepage.icon=homepage"
- "homepage.href=http://192.168.3.6:4000"
- "homepage.description=Developer dashboard and service discovery"
environment:
DOCKER_HOST: >
tcp://tsysdevstack-supportstack-docker-socket-proxy:${DOCKER_PROXY_PORT}
HOMEPAGE_ALLOWED_HOSTS: "*"
HOMEPAGE_VAR_DOCKER_HOST: >
tcp://tsysdevstack-supportstack-docker-socket-proxy:${DOCKER_PROXY_PORT}
# Use docker.yaml with explicit include/exclude filtering
depends_on:
- tsysdevstack-supportstack-docker-socket-proxy
restart: unless-stopped
# Atuin - Shell history
atuin:
image: ghcr.io/atuinsh/atuin:latest
container_name: tsysdevstack-supportstack-atuin
ports:
- "${ATUIN_PORT}:8888"
labels:
- "homepage.group=Developer Tools"
- "homepage.name=Atuin"
- "homepage.icon=atuin"
- "homepage.href=http://192.168.3.6:4001"
- "homepage.description=Synced shell history database"
environment:
ATUIN_HOST: "0.0.0.0"
ATUIN_PORT: "8888"
ATUIN_OPEN_REGISTRATION: "true"
ATUIN_DB_URI: >
postgres://atuin:demo_password@tsysdevstack-supportstack-postgres:5432/atuin
RUST_LOG: "debug,atuin_server=debug,sqlx=debug"
command: server start
# No persistent volumes for demo - config is ephemeral
user: "${PUID}:${PGID}"
depends_on:
tsysdevstack-supportstack-postgres:
condition: service_healthy
restart: unless-stopped
healthcheck:
test:
- CMD-SHELL
- "wget --no-verbose --tries=1 --spider http://localhost:8080/ || exit 1"
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
# Wakapi - Time tracking
wakapi:
image: ghcr.io/muety/wakapi:latest
container_name: tsysdevstack-supportstack-wakapi
ports:
- "${WAKAPI_PORT}:3000"
labels:
- "homepage.group=Developer Tools"
- "homepage.name=Wakapi"
- "homepage.icon=wakapi"
- "homepage.href=http://192.168.3.6:4002"
- "homepage.description=Self-hosted time tracking"
environment:
- WAKAPI_PASSWORD_SALT=demo_password
# No persistent volumes for demo - data is ephemeral
restart: unless-stopped
healthcheck:
test:
- CMD-SHELL
- "wget --no-verbose --tries=1 --spider http://localhost:8086/ping || exit 1"
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
# MailHog - Email testing
mailhog:
image: mailhog/mailhog:latest
container_name: tsysdevstack-supportstack-mailhog
ports:
- "1025:1025"
- "${MAILHOG_PORT}:8025"
labels:
- "homepage.group=Developer Tools"
- "homepage.name=MailHog"
- "homepage.icon=mailhog"
- "homepage.href=http://192.168.3.6:4005"
- "homepage.description=Email testing service"
restart: unless-stopped
healthcheck:
test:
- CMD-SHELL
- "echo > /dev/tcp/localhost:8025"
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
memory: 128M
cpus: '0.25'
# Pi-hole - DNS management
pihole:
image: pihole/pihole:latest
container_name: tsysdevstack-supportstack-pihole
# Note: Pi-hole requires root for DNS capabilities and file permissions
ports:
- "${PIHOLE_PORT}:80"
- "53:53/tcp"
- "53:53/udp"
- "67:67/udp"
labels:
- "homepage.group=Infrastructure"
- "homepage.name=Pi-hole"
- "homepage.icon=pihole"
- "homepage.href=http://192.168.3.6:4006"
- "homepage.description=DNS-based ad blocking and network monitoring"
environment:
- TZ=UTC
- WEBPASSWORD=${DEMO_PASSWORD}
- PIHOLE_DNS_=1.1.1.1;1.0.0.1
- DNSMASQ_LISTENING=all
- WEBTHEME=default-dark
# No persistent volumes for demo - configuration is ephemeral
restart: unless-stopped
healthcheck:
test:
- CMD-SHELL
- "echo > /dev/tcp/localhost/80"
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
resources:
limits:
memory: 512M
cpus: '0.75'
# Portainer - Container management
portainer:
image: portainer/portainer-ce:latest
container_name: tsysdevstack-supportstack-portainer
ports:
- "${PORTAINER_PORT}:9000"
labels:
- "homepage.group=Infrastructure"
- "homepage.name=Portainer"
- "homepage.icon=portainer"
- "homepage.href=http://192.168.3.6:4007"
- "homepage.description=Container management interface"
# No persistent volumes for demo - data is ephemeral
# Note: Portainer needs root for data directory permissions
environment:
DOCKER_HOST: >
tcp://tsysdevstack-supportstack-docker-socket-proxy:${DOCKER_PROXY_PORT}
restart: unless-stopped
healthcheck:
test:
- CMD-SHELL
- "echo > /dev/tcp/localhost/9000"
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
# ArchiveBox - Web archiving
archivebox:
image: archivebox/archivebox:latest
container_name: tsysdevstack-supportstack-archivebox
ports:
- "${ARCHIVEBOX_PORT}:8000"
labels:
- "homepage.group=Developer Tools"
- "homepage.name=ArchiveBox"
- "homepage.icon=archivebox"
- "homepage.href=http://192.168.3.6:4003"
- "homepage.description=Self-hosted web archiving"
environment:
- ALLOWED_HOSTS=*
- MEDIA_MAX_SIZE=750m
# No persistent volumes for demo - data is ephemeral
restart: unless-stopped
healthcheck:
test:
- CMD-SHELL
- "wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1"
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
# InfluxDB - Time series database
influxdb:
image: influxdb:2.7-alpine
container_name: tsysdevstack-supportstack-influxdb
ports:
- "${INFLUXDB_PORT}:8086"
labels:
- "homepage.group=Monitoring"
- "homepage.name=InfluxDB"
- "homepage.icon=influxdb"
- "homepage.href=http://192.168.3.6:4008"
- "homepage.description=Time series database for metrics storage"
environment:
- DOCKER_INFLUXDB_INIT_MODE=setup
- DOCKER_INFLUXDB_INIT_USERNAME=admin
- DOCKER_INFLUXDB_INIT_PASSWORD=${DEMO_PASSWORD}
- DOCKER_INFLUXDB_INIT_ORG=tsysdev
- DOCKER_INFLUXDB_INIT_BUCKET=metrics
# No persistent volumes for demo - data is ephemeral
user: "${PUID}:${PGID}"
restart: unless-stopped
healthcheck:
test:
- CMD-SHELL
- "wget --no-verbose --tries=1 --spider http://localhost:8086/ping || exit 1"
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
# Grafana - Analytics visualization
grafana:
image: grafana/grafana:latest
container_name: tsysdevstack-supportstack-grafana
ports:
- "${GRAFANA_PORT}:3000"
labels:
- "homepage.group=Monitoring"
- "homepage.name=Grafana"
- "homepage.icon=grafana"
- "homepage.href=http://192.168.3.6:4009"
- "homepage.description=Analytics and visualization platform"
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=${DEMO_PASSWORD}
- GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource
- GF_SERVER_DOMAIN=192.168.3.6:4009
- GF_SERVER_ROOT_URL=http://192.168.3.6:4009
# No persistent volumes for demo - data is ephemeral
user: "${PUID}:${PGID}"
depends_on:
- influxdb
restart: unless-stopped
healthcheck:
test:
- CMD-SHELL
- "echo > /dev/tcp/localhost/3000"
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
memory: 512M
cpus: '0.75'
# Draw.io - Diagramming
drawio:
image: jgraph/drawio:latest
container_name: tsysdevstack-supportstack-drawio
user: "${PUID}:${PGID}"
ports:
- "${DRAWIO_PORT}:8080"
labels:
- "homepage.group=Documentation"
- "homepage.name=Draw.io"
- "homepage.icon=diagram"
- "homepage.href=http://192.168.3.6:4010"
- "homepage.description=Web-based diagramming tool"
restart: unless-stopped
healthcheck:
test:
- CMD-SHELL
- "echo > /dev/tcp/localhost/3000"
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
# Tube Archivist - YouTube media archiving
tube-archivist:
image: bbilly1/tubearchivist:latest
container_name: tsysdevstack-supportstack-tube-archivist
ports:
- "4004:8000"
labels:
- "homepage.group=Developer Tools"
- "homepage.name=Tube Archivist"
- "homepage.icon=youtube"
- "homepage.href=http://192.168.3.6:4004"
- "homepage.description=Self-hosted YouTube media archiving"
environment:
- TA_HOST=192.168.3.6:4004
- TA_USERNAME=demo_user
- TA_PASSWORD=demo_password
- ES_URL=http://elastic:demo_password@tsysdevstack-supportstack-elasticsearch:9200
- ELASTIC_PASSWORD=demo_password
- REDIS_CON=redis://tsysdevstack-supportstack-redis:6379
- TZ=UTC
depends_on:
tsysdevstack-supportstack-elasticsearch:
condition: service_healthy
tsysdevstack-supportstack-redis:
condition: service_healthy
# No persistent volumes for demo - cache and media are ephemeral
restart: unless-stopped
healthcheck:
test:
- CMD-SHELL
- "wget --no-verbose --tries=1 --spider http://localhost:8000/ || exit 1"
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
resources:
limits:
memory: 512M
cpus: '1.0'
# Kroki - Diagrams as code
kroki:
image: yuzutech/kroki:latest
container_name: tsysdevstack-supportstack-kroki
user: "${PUID}:${PGID}"
ports:
- "${KROKI_PORT}:8000"
labels:
- "homepage.group=Documentation"
- "homepage.name=Kroki"
- "homepage.icon=diagram"
- "homepage.href=http://192.168.3.6:4011"
- "homepage.description=Service for converting text diagrams to images"
environment:
- KROKI_SAFE_MODE=0
- KROKI_PLANTUML_ALLOW_LIST=*
- KROKI_MERMAID_ALLOW_LIST=*
restart: unless-stopped
healthcheck:
test:
- CMD-SHELL
- "wget --no-verbose --tries=1 --spider http://localhost:8000/health || exit 1"
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
# Docker Socket Proxy - Secure Docker API access
tsysdevstack-supportstack-docker-socket-proxy:
image: tecnativa/docker-socket-proxy:latest
container_name: tsysdevstack-supportstack-docker-socket-proxy
ports:
- "${DOCKER_PROXY_PORT}:2375"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- CONTAINERS=1
- SERVICES=1
- TASKS=1
- NETWORKS=1
- NODES=1
- IMAGES=1
- VOLUMES=1
- EXEC=0
- SECRETS=0
- CONFIGS=0
- PLUGINS=0
- SYSTEM=0
- INFO=1
- VERSION=1
- EVENTS=0
- POST=0
- DELETE=0
- PUT=0
restart: unless-stopped
healthcheck:
test:
- CMD-SHELL
- "wget --no-verbose --tries=1 --spider http://localhost:2375/version || exit 1"
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
resources:
limits:
memory: 128M
cpus: '0.25'
# PostgreSQL - Database for Atuin
tsysdevstack-supportstack-postgres:
image: postgres:15-alpine
container_name: tsysdevstack-supportstack-postgres
labels:
- "homepage.group=Infrastructure"
- "homepage.name=PostgreSQL"
- "homepage.icon=postgresql"
- "homepage.description=PostgreSQL database server"
environment:
- POSTGRES_DB=atuin
- POSTGRES_USER=atuin
- POSTGRES_PASSWORD=${DEMO_PASSWORD}
# No persistent volumes for demo - data is ephemeral
restart: unless-stopped
healthcheck:
test:
- CMD
- pg_isready
- -U
- atuin
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
# Elasticsearch - Search engine
tsysdevstack-supportstack-elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.11.1
container_name: tsysdevstack-supportstack-elasticsearch
labels:
- "homepage.group=Infrastructure"
- "homepage.name=Elasticsearch"
- "homepage.icon=elasticsearch"
- "homepage.description=Search and analytics engine"
environment:
- "discovery.type=single-node"
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- "xpack.security.enabled=true"
- "ELASTIC_PASSWORD=${DEMO_PASSWORD}"
- "path.repo=/usr/share/elasticsearch/data/snapshot"
# No persistent volumes for demo - data is ephemeral
user: "${PUID}:${PGID}"
restart: unless-stopped
healthcheck:
test:
- CMD-SHELL
- >
curl -f -u elastic:demo_password
http://localhost:9200/_cluster/health?wait_for_status=yellow&timeout=30s || exit 1
interval: 30s
timeout: 10s
retries: 5
start_period: 120s
deploy:
resources:
limits:
memory: 1G
cpus: '1.0'
# Redis for Tube Archivist
tsysdevstack-supportstack-redis:
image: redis:7-alpine
container_name: tsysdevstack-supportstack-redis
user: "${PUID}:${PGID}"
labels:
- "homepage.group=Infrastructure"
- "homepage.name=Redis"
- "homepage.icon=redis"
- "homepage.description=In-memory data structure store"
restart: unless-stopped
healthcheck:
test:
- CMD
- redis-cli
- ping
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
memory: 128M
cpus: '0.25'
# No persistent volumes - demo is 100% ephemeral
# Only Docker socket bind mount is used for functionality
networks:
default:
name: tsysdevstack_supportstack