Compare commits
20 Commits
c2d8b502cc
...
v0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1628b1dfea | ||
|
|
b03f4b2ba2 | ||
|
|
50206dce6b | ||
|
|
8362e1ce51 | ||
|
|
190b0aff3e | ||
|
|
be03c95929 | ||
|
|
9f40e16b25 | ||
|
|
0c13069304 | ||
|
|
088a4cba07 | ||
|
|
265d146bd3 | ||
|
|
904fc6d727 | ||
|
|
6a70131f9c | ||
|
|
55aa340a6c | ||
|
|
eff78907d4 | ||
|
|
077f483faf | ||
| ed2dbea6c0 | |||
| f7fc8ccf1a | |||
| 45abd5c2e0 | |||
| ac7e644ba3 | |||
| 937ec852eb |
33
.gitignore
vendored
Normal file
33
.gitignore
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Generated files
|
||||||
|
demo/docker-compose.yml
|
||||||
|
|
||||||
|
# Environment with secrets
|
||||||
|
demo/demo.env
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Editor files
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*.tmp
|
||||||
|
*.bak
|
||||||
|
tmp_template.yml
|
||||||
|
|
||||||
|
# Homepage auto-generated files
|
||||||
|
demo/config/homepage/logs/
|
||||||
|
demo/config/homepage/kubernetes.yaml
|
||||||
|
demo/config/homepage/custom.css
|
||||||
|
demo/config/homepage/custom.js
|
||||||
|
demo/config/homepage/proxmox.yaml
|
||||||
|
|
||||||
|
# Playwright
|
||||||
|
node_modules/
|
||||||
|
test-results/
|
||||||
|
package-lock.json
|
||||||
394
AGENTS.md
Normal file
394
AGENTS.md
Normal file
@@ -0,0 +1,394 @@
|
|||||||
|
# TSYS Developer Support Stack - Agent Guide
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
This repository contains a Docker Compose-based multi-service stack that provides off-the-shelf applications running locally on developer workstations. It's designed to enhance developer productivity and quality of life for the TSYS engineering team.
|
||||||
|
|
||||||
|
### Project Type
|
||||||
|
- **Infrastructure as Code**: Docker Compose with shell orchestration
|
||||||
|
- **Multi-Service Stack**: 16 services across 4 categories
|
||||||
|
- **Demo-First Architecture**: All configurations for demonstration purposes only
|
||||||
|
|
||||||
|
### Directory Structure
|
||||||
|
```
|
||||||
|
TSYSDevStack-SupportStack-LocalWorkstation/
|
||||||
|
├── LICENSE
|
||||||
|
├── README.md # Root-level documentation
|
||||||
|
├── AGENTS.md # This file - agent guide
|
||||||
|
├── demo/ # Demo environment (primary focus)
|
||||||
|
│ ├── AGENTS.md # Detailed development guidelines
|
||||||
|
│ ├── PRD.md # Product Requirements Document
|
||||||
|
│ ├── README.md # Demo-specific documentation
|
||||||
|
│ ├── demo.env # Environment variables (dynamic)
|
||||||
|
│ ├── docker-compose.yml # Generated compose file
|
||||||
|
│ ├── docker-compose.yml.template # Template for compose file
|
||||||
|
│ ├── scripts/ # Orchestration scripts
|
||||||
|
│ │ ├── demo-stack.sh # Deployment/management
|
||||||
|
│ │ ├── demo-test.sh # QA/testing suite
|
||||||
|
│ │ └── validate-all.sh # Pre-deployment validation
|
||||||
|
│ ├── tests/ # Test suite
|
||||||
|
│ │ ├── unit/ # Unit tests
|
||||||
|
│ │ ├── integration/ # Integration tests
|
||||||
|
│ │ └── e2e/ # End-to-end tests
|
||||||
|
│ ├── config/ # Service configurations
|
||||||
|
│ │ ├── homepage/ # Homepage dashboard config
|
||||||
|
│ │ ├── grafana/ # Grafana dashboards/datasources
|
||||||
|
│ │ ├── pihole/ # Pi-hole configuration
|
||||||
|
│ │ ├── dockhand/ # Dockhand configuration
|
||||||
|
│ │ ├── influxdb/ # InfluxDB configuration
|
||||||
|
│ │ ├── drawio/ # Draw.io configuration
|
||||||
|
│ │ ├── kroki/ # Kroki configuration
|
||||||
|
│ │ ├── atomictracker/ # Atomic Tracker configuration
|
||||||
|
│ │ ├── archivebox/ # ArchiveBox configuration
|
||||||
|
│ │ ├── tubearchivist/ # Tube Archivist configuration
|
||||||
|
│ │ ├── wakapi/ # Wakapi configuration
|
||||||
|
│ │ ├── mailhog/ # MailHog configuration
|
||||||
|
│ │ └── atuin/ # Atuin configuration
|
||||||
|
│ └── docs/ # Additional documentation
|
||||||
|
│ ├── service-guides/ # Service-specific guides
|
||||||
|
│ ├── troubleshooting/ # Troubleshooting documentation
|
||||||
|
│ └── api-docs/ # API documentation
|
||||||
|
└── prod/ # Production environment (placeholder)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Essential Commands
|
||||||
|
|
||||||
|
### Deployment & Management
|
||||||
|
```bash
|
||||||
|
# Deploy the demo stack
|
||||||
|
./demo/scripts/demo-stack.sh deploy
|
||||||
|
|
||||||
|
# Stop all services
|
||||||
|
./demo/scripts/demo-stack.sh stop
|
||||||
|
|
||||||
|
# Restart all services
|
||||||
|
./demo/scripts/demo-stack.sh restart
|
||||||
|
|
||||||
|
# Show service status
|
||||||
|
./demo/scripts/demo-stack.sh status
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing & Validation
|
||||||
|
```bash
|
||||||
|
# Run comprehensive validation (before deployment)
|
||||||
|
./demo/scripts/validate-all.sh
|
||||||
|
|
||||||
|
# Run full test suite
|
||||||
|
./demo/scripts/demo-test.sh full
|
||||||
|
|
||||||
|
# Run security compliance tests only
|
||||||
|
./demo/scripts/demo-test.sh security
|
||||||
|
|
||||||
|
# Run permission validation tests only
|
||||||
|
./demo/scripts/demo-test.sh permissions
|
||||||
|
|
||||||
|
# Run network isolation tests only
|
||||||
|
./demo/scripts/demo-test.sh network
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker Operations
|
||||||
|
```bash
|
||||||
|
# View logs for all services
|
||||||
|
docker compose -f demo/docker-compose.yml logs -f
|
||||||
|
|
||||||
|
# View logs for specific service
|
||||||
|
docker compose -f demo/docker-compose.yml logs -f <service-name>
|
||||||
|
|
||||||
|
# Execute command in container
|
||||||
|
docker exec -it <container-name> <command>
|
||||||
|
|
||||||
|
# Check service health
|
||||||
|
docker compose -f demo/docker-compose.yml ps
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code Quality Validation
|
||||||
|
```bash
|
||||||
|
# Validate YAML files (yamllint)
|
||||||
|
docker run --rm -v "$(pwd):/data" cytopia/yamllint demo/docker-compose.yml.template
|
||||||
|
docker run --rm -v "$(pwd):/data" cytopia/yamllint demo/config/homepage/docker.yaml
|
||||||
|
docker run --rm -v "$(pwd):/data" cytopia/yamllint demo/config/grafana/datasources.yml
|
||||||
|
docker run --rm -v "$(pwd):/data" cytopia/yamllint demo/config/grafana/dashboards.yml
|
||||||
|
|
||||||
|
# Validate shell scripts (shellcheck)
|
||||||
|
docker run --rm -v "$(pwd):/data" koalaman/shellcheck demo/scripts/*.sh
|
||||||
|
docker run --rm -v "$(pwd):/data" koalaman/shellcheck demo/tests/**/*.sh
|
||||||
|
|
||||||
|
# Validate Dockerfiles (hadolint)
|
||||||
|
docker run --rm -v "$(pwd):/workdir" hadolint/hadolint <path-to-dockerfile>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code Organization & Structure
|
||||||
|
|
||||||
|
### Service Categories
|
||||||
|
1. **Infrastructure Services** (ports 4005-4007)
|
||||||
|
- Docker Socket Proxy (4005) - Security layer for Docker API access (internal only)
|
||||||
|
- Pi-hole (4006) - DNS management with ad blocking
|
||||||
|
- Dockhand (4007) - Web-based container management
|
||||||
|
|
||||||
|
2. **Monitoring & Observability** (ports 4008-4009)
|
||||||
|
- InfluxDB (4008) - Time series database for metrics
|
||||||
|
- Grafana (4009) - Visualization platform
|
||||||
|
|
||||||
|
3. **Documentation & Diagramming** (ports 4010-4011)
|
||||||
|
- Draw.io (4010) - Web-based diagramming application
|
||||||
|
- Kroki (4011) - Diagrams as a service
|
||||||
|
|
||||||
|
4. **Developer Tools** (ports 4000, 4012-4018)
|
||||||
|
- Homepage (4000) - Central dashboard for service discovery
|
||||||
|
- Atomic Tracker (4012) - Habit tracking and personal dashboard
|
||||||
|
- ArchiveBox (4013) - Web archiving solution
|
||||||
|
- Tube Archivist (4014) - YouTube video archiving (requires ta-redis + ta-elasticsearch)
|
||||||
|
- Wakapi (4015) - Open-source WakaTime alternative (time tracking)
|
||||||
|
- MailHog (4017 Web, 4019 SMTP) - Web and API based SMTP testing
|
||||||
|
- Atuin (4018) - Magical shell history synchronization
|
||||||
|
|
||||||
|
5. **Companion Services** (internal only, no host ports)
|
||||||
|
- ta-redis - Redis cache for Tube Archivist
|
||||||
|
- ta-elasticsearch - Elasticsearch index for Tube Archivist
|
||||||
|
|
||||||
|
### Configuration Management
|
||||||
|
- **Environment Variables**: All configuration via `demo/demo.env` (copy from `demo/demo.env.template`)
|
||||||
|
- **Template-Based**: `docker-compose.yml` generated from `docker-compose.yml.template` using `envsubst`
|
||||||
|
- **Dynamic User Detection**: UID/GID automatically detected and applied
|
||||||
|
- **Service Discovery**: Automatic via Homepage labels in docker-compose.yml
|
||||||
|
|
||||||
|
## Naming Conventions & Style Patterns
|
||||||
|
|
||||||
|
### Service Naming
|
||||||
|
- **Container Names**: `kneldevstack-supportstack-demo-<service-name>`
|
||||||
|
- **Volume Names**: `kneldevstack-supportstack-demo_<service>_data`
|
||||||
|
- **Network Name**: `kneldevstack-supportstack-demo-network`
|
||||||
|
- **Project Name**: `kneldevstack-supportstack-demo`
|
||||||
|
|
||||||
|
### Port Assignment
|
||||||
|
- **Range**: 4000-4099
|
||||||
|
- **Sequential Allocation**: Groups assigned consecutive ports
|
||||||
|
- **Documented**: All ports documented in README.md port table
|
||||||
|
|
||||||
|
### Docker Labels (Service Discovery)
|
||||||
|
```yaml
|
||||||
|
labels:
|
||||||
|
homepage.group: "Infrastructure" # Category
|
||||||
|
homepage.name: "Service Display Name" # Human-readable name
|
||||||
|
homepage.icon: "icon-name" # Icon identifier
|
||||||
|
homepage.href: "http://localhost:PORT" # Access URL
|
||||||
|
homepage.description: "Brief description" # Tool tip
|
||||||
|
```
|
||||||
|
|
||||||
|
### Shell Script Patterns
|
||||||
|
- **Strict Mode**: `set -euo pipefail` at top of all scripts
|
||||||
|
- **Color Output**: Consistent color codes for logging (RED, GREEN, YELLOW, BLUE, NC)
|
||||||
|
- **Log Functions**: `log_info()`, `log_success()`, `log_warning()`, `log_error()`
|
||||||
|
- **Function Organization**: Clear function headers with purpose description
|
||||||
|
- **Error Handling**: Check prerequisites before execution
|
||||||
|
|
||||||
|
### YAML Patterns
|
||||||
|
- **Header Comments**: Include purpose and version
|
||||||
|
- **Structured Sections**: Clear separation of networks, volumes, services
|
||||||
|
- **Consistent Indentation**: 2-space indentation
|
||||||
|
- **Environment Variables**: All via `${VARIABLE_NAME}` format
|
||||||
|
- **Health Checks**: All services include healthcheck section
|
||||||
|
|
||||||
|
## Testing Approach & Patterns
|
||||||
|
|
||||||
|
### Test Organization
|
||||||
|
- **Unit Tests**: `/demo/tests/unit/` - Test individual components
|
||||||
|
- **Integration Tests**: `/demo/tests/integration/` - Test service interactions
|
||||||
|
- **E2E Tests**: `/demo/tests/e2e/` - Test complete workflows
|
||||||
|
|
||||||
|
### Test Categories (demo-test.sh)
|
||||||
|
1. **File Ownership**: Verify no root-owned files on host
|
||||||
|
2. **User Mapping**: Validate UID/GID detection and application
|
||||||
|
3. **Docker Group**: Confirm docker group access
|
||||||
|
4. **Service Health**: All services passing health checks
|
||||||
|
5. **Port Accessibility**: Verify all ports accessible from host
|
||||||
|
6. **Network Isolation**: Confirm services isolated in demo network
|
||||||
|
7. **Volume Permissions**: Validate Docker volume permissions
|
||||||
|
8. **Security Compliance**: Docker socket proxy restrictions enforced
|
||||||
|
|
||||||
|
### Validation Before Deployment
|
||||||
|
Run `./demo/scripts/validate-all.sh` to check:
|
||||||
|
- YAML syntax (yamllint)
|
||||||
|
- Shell script syntax (shellcheck)
|
||||||
|
- Docker image availability
|
||||||
|
- Port availability
|
||||||
|
- Environment variables
|
||||||
|
- Health endpoints
|
||||||
|
- Service dependencies
|
||||||
|
- Resource requirements
|
||||||
|
|
||||||
|
## Important Gotchas & Non-Obvious Patterns
|
||||||
|
|
||||||
|
### ⚠️ CRITICAL: Process Management
|
||||||
|
**NEVER interfere with existing processes**:
|
||||||
|
1. **Always check first**: Run `screen -ls` and `ps aux | grep demo-stack` before starting new work
|
||||||
|
2. **Unique identifiers**: Use unique session names with timestamps: `demo-deploy-$(date +%Y%m%d-%H%M%S)`
|
||||||
|
3. **Ask before acting**: Never kill or modify existing processes without explicit permission
|
||||||
|
4. **Respect concurrent work**: Other users/processes may be running - do not assume exclusive access
|
||||||
|
|
||||||
|
### Demo-Only Security Model
|
||||||
|
- **Hardcoded Credentials**: All passwords set to `demo_password` or similar
|
||||||
|
- **No Encryption**: No TLS, no security hardening
|
||||||
|
- **Isolated Network**: Services contained in Docker network only
|
||||||
|
- **Not for Production**: Clear separation required for production deployments
|
||||||
|
- **Documentation Required**: All security assumptions must be documented
|
||||||
|
|
||||||
|
### Zero-Tolerance Quality Standards
|
||||||
|
Before ANY file is created or modified:
|
||||||
|
1. ✅ YAML syntax validated with yamllint
|
||||||
|
2. ✅ Shell script validated with shellcheck
|
||||||
|
3. ✅ Environment variables verified
|
||||||
|
4. ✅ Port availability confirmed
|
||||||
|
5. ✅ Docker image existence verified
|
||||||
|
6. ✅ Service dependencies validated
|
||||||
|
7. ✅ Health check endpoints confirmed
|
||||||
|
8. ✅ Resource requirements assessed
|
||||||
|
|
||||||
|
**Failure on any validation must block deployment.**
|
||||||
|
|
||||||
|
### Dynamic Environment Strategy
|
||||||
|
- **User Detection**: UID/GID automatically detected and written to `demo.env`
|
||||||
|
- **Template Generation**: `docker-compose.yml` generated from template using `envsubst`
|
||||||
|
- **Variable Expansion**: All configuration via environment variables
|
||||||
|
- **Source demo.env**: Always source `demo.env` before accessing variables
|
||||||
|
|
||||||
|
### Docker Socket Proxy Requirements
|
||||||
|
- **Mandatory**: All container operations must go through `docker-socket-proxy`
|
||||||
|
- **No Direct Access**: Never mount Docker socket directly in containers (except proxy)
|
||||||
|
- **Restricted API**: Minimal permissions per service requirements
|
||||||
|
- **Group-Based**: Dynamic docker group ID assignment
|
||||||
|
|
||||||
|
### Volume vs Bind Mount Strategy
|
||||||
|
- **Prefer Volumes**: Use Docker volumes for data storage
|
||||||
|
- **Minimal Bind Mounts**: Use host bind mounts only for configuration that needs persistence
|
||||||
|
- **Dynamic Naming**: Volume names follow pattern: `kneldevstack-supportstack-demo_<service>_data`
|
||||||
|
- **Permission Mapping**: UID/GID mapped via environment variables
|
||||||
|
|
||||||
|
### Service Discovery Mechanism
|
||||||
|
- **Homepage Labels**: Services automatically discovered via Docker labels
|
||||||
|
- **No Manual Config**: Don't manually add services to Homepage configuration
|
||||||
|
- **Group-Based**: Services organized by group (Infrastructure, Monitoring, Documentation, Developer Tools)
|
||||||
|
- **Real-Time**: Homepage updates automatically as services start/stop
|
||||||
|
|
||||||
|
### FOSS Only Policy
|
||||||
|
- **No Proprietary**: Exclusively use free/libre/open source software
|
||||||
|
- **Official Images**: Prefer official Docker images
|
||||||
|
- **Verify Licenses**: Check license compatibility before adding services
|
||||||
|
- **Document Exceptions**: Any proprietary dependencies must be documented
|
||||||
|
|
||||||
|
## Project-Specific Context
|
||||||
|
|
||||||
|
### Current State
|
||||||
|
- **Demo Environment**: Fully configured with 16 services
|
||||||
|
- **Production Environment**: Placeholder only, not yet implemented
|
||||||
|
- **Documentation**: Comprehensive (AGENTS.md, PRD.md, README.md)
|
||||||
|
- **Scripts**: Complete orchestration and testing scripts available
|
||||||
|
|
||||||
|
### Architecture Principles
|
||||||
|
1. **Demo-First**: All configurations for demonstration purposes
|
||||||
|
2. **No Persistence**: Zero data persistence between demo sessions
|
||||||
|
3. **Dynamic User Handling**: Automatic UID/GID detection
|
||||||
|
4. **Security-First**: Docker socket proxy for all container operations
|
||||||
|
5. **FOSS Only**: Exclusively open source software
|
||||||
|
6. **Inner Loop Focus**: Support daily development workflows
|
||||||
|
7. **Workstation Local**: Run locally on developer machines
|
||||||
|
|
||||||
|
### Development Workflow
|
||||||
|
1. **Research**: Verify FOSS status and official Docker image availability
|
||||||
|
2. **Plan**: Determine port assignment and service group
|
||||||
|
3. **Template Configuration**: Add to docker-compose.yml.template with variables
|
||||||
|
4. **Environment Setup**: Add service variables to demo.env
|
||||||
|
5. **Security Integration**: Configure docker-socket-proxy permissions
|
||||||
|
6. **Dynamic Testing**: Validate with demo-stack.sh and demo-test.sh
|
||||||
|
7. **Documentation Update**: Update README.md, PRD.md, and AGENTS.md
|
||||||
|
8. **Atomic Commit**: Conventional commit with detailed description
|
||||||
|
|
||||||
|
### Service Health Standards
|
||||||
|
- **All Services**: Must include healthcheck section
|
||||||
|
- **Completion**: Health checks must complete within 10 seconds
|
||||||
|
- **HTTP Endpoints**: Preferred health check method
|
||||||
|
- **Fallback**: Container status checks when HTTP not available
|
||||||
|
- **Monitoring**: All health checks visible via `docker compose ps`
|
||||||
|
|
||||||
|
### Resource Limits
|
||||||
|
- **Memory**: < 512MB per service (where applicable)
|
||||||
|
- **CPU**: < 25% per service (idle)
|
||||||
|
- **Startup Time**: < 60 seconds for full stack
|
||||||
|
- **Disk Usage**: Temporary volumes only (demo mode)
|
||||||
|
|
||||||
|
## Environment Variables (demo.env)
|
||||||
|
|
||||||
|
### Required Variables
|
||||||
|
```bash
|
||||||
|
COMPOSE_PROJECT_NAME=kneldevstack-supportstack-demo
|
||||||
|
COMPOSE_NETWORK_NAME=kneldevstack-supportstack-demo-network
|
||||||
|
|
||||||
|
# User Detection (Auto-populated by demo-stack.sh)
|
||||||
|
DEMO_UID=
|
||||||
|
DEMO_GID=
|
||||||
|
DEMO_DOCKER_GID=
|
||||||
|
|
||||||
|
# Service Ports (4000-4099 range)
|
||||||
|
HOMEPAGE_PORT=4000
|
||||||
|
DOCKER_SOCKET_PROXY_PORT=4005
|
||||||
|
PIHOLE_PORT=4006
|
||||||
|
DOCKHAND_PORT=4007
|
||||||
|
INFLUXDB_PORT=4008
|
||||||
|
GRAFANA_PORT=4009
|
||||||
|
DRAWIO_PORT=4010
|
||||||
|
KROKI_PORT=4011
|
||||||
|
ATOMIC_TRACKER_PORT=4012
|
||||||
|
ARCHIVEBOX_PORT=4013
|
||||||
|
TUBE_ARCHIVIST_PORT=4014
|
||||||
|
WAKAPI_PORT=4015
|
||||||
|
MAILHOG_PORT=4017
|
||||||
|
MAILHOG_SMTP_PORT=4019
|
||||||
|
ATUIN_PORT=4018
|
||||||
|
|
||||||
|
# Demo Credentials (NOT FOR PRODUCTION)
|
||||||
|
DEMO_ADMIN_USER=admin
|
||||||
|
DEMO_ADMIN_PASSWORD=demo_password
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Files Reference
|
||||||
|
|
||||||
|
| File | Purpose | Read Before... |
|
||||||
|
|------|---------|----------------|
|
||||||
|
| `demo/AGENTS.md` | Detailed development guidelines | Making any changes |
|
||||||
|
| `demo/PRD.md` | Product Requirements Document | Adding/removing services |
|
||||||
|
| `demo/README.md` | Demo-specific documentation | Deploying or troubleshooting |
|
||||||
|
| `demo/demo.env` | Environment configuration | Modifying service settings |
|
||||||
|
| `demo/docker-compose.yml.template` | Service definitions | Adding/modifying services |
|
||||||
|
| `demo/scripts/demo-stack.sh` | Deployment orchestration | Understanding deployment flow |
|
||||||
|
| `demo/scripts/demo-test.sh` | Test suite | Verifying changes |
|
||||||
|
| `demo/scripts/validate-all.sh` | Pre-deployment validation | Making any commits |
|
||||||
|
|
||||||
|
## Troubleshooting Quick Reference
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
1. **Port Conflicts**: Check with `netstat -tulpn | grep :<port>`
|
||||||
|
2. **Permission Issues**: Verify UID/GID in demo.env match current user
|
||||||
|
3. **Image Pull Failures**: Run `docker pull <image>` manually
|
||||||
|
4. **Health Check Failures**: Check service logs with `docker compose logs <service>`
|
||||||
|
5. **Network Issues**: Verify network exists: `docker network ls | grep kneldevstack`
|
||||||
|
|
||||||
|
### Getting Help
|
||||||
|
1. Check troubleshooting section in demo/README.md
|
||||||
|
2. Review service logs: `docker compose -f demo/docker-compose.yml logs {service}`
|
||||||
|
3. Consult individual service documentation
|
||||||
|
4. Check health status: `docker compose -f demo/docker-compose.yml ps`
|
||||||
|
5. **CRITICAL**: Always check for existing processes first
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
- **demo/AGENTS.md**: Detailed development guidelines and standards
|
||||||
|
- **demo/PRD.md**: Product Requirements Document
|
||||||
|
- **demo/README.md**: Demo-specific documentation and quick start
|
||||||
|
- **demo/docs/service-guides/**: Service-specific guides
|
||||||
|
- **demo/docs/troubleshooting/**: Detailed troubleshooting procedures
|
||||||
|
- **demo/docs/api-docs/**: API documentation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Last Updated**: 2025-01-24
|
||||||
|
**Version**: 1.0
|
||||||
57
README.md
57
README.md
@@ -1,3 +1,56 @@
|
|||||||
# TSYSDevStack-SupportStack-LocalWorkstation
|
# TSYS Developer Support Stack
|
||||||
|
|
||||||
Off the shelf applications running local to developer workstations
|
A Docker Compose-based multi-service stack of FOSS applications that run locally on developer workstations to enhance productivity and quality of life.
|
||||||
|
|
||||||
|
## What It Does
|
||||||
|
|
||||||
|
Deploys 16 services across 4 categories via a single command:
|
||||||
|
|
||||||
|
| Category | Services |
|
||||||
|
|----------|----------|
|
||||||
|
| **Infrastructure** | Homepage (dashboard), Pi-hole (DNS), Dockhand (Docker management), Docker Socket Proxy |
|
||||||
|
| **Monitoring** | InfluxDB (time series), Grafana (visualization) |
|
||||||
|
| **Documentation** | Draw.io (diagramming), Kroki (diagrams as code) |
|
||||||
|
| **Developer Tools** | Atomic Tracker, ArchiveBox, Tube Archivist, Wakapi, MailHog, Atuin |
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd demo
|
||||||
|
cp demo.env.template demo.env
|
||||||
|
./scripts/demo-stack.sh deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
Access the dashboard at **http://localhost:4000**
|
||||||
|
|
||||||
|
Credentials: `admin` / `demo_password` (demo only)
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Docker Engine + Docker Compose
|
||||||
|
- 8GB RAM minimum
|
||||||
|
- 10GB disk space
|
||||||
|
- Linux (tested on Ubuntu)
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
| Document | Purpose |
|
||||||
|
|----------|---------|
|
||||||
|
| [demo/PRD.md](demo/PRD.md) | Product requirements (the source of truth) |
|
||||||
|
| [demo/README.md](demo/README.md) | Full deployment and service documentation |
|
||||||
|
| [demo/AGENTS.md](demo/AGENTS.md) | Development guidelines |
|
||||||
|
| [AGENTS.md](AGENTS.md) | Quick reference for contributors |
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Unit tests (no Docker required)
|
||||||
|
bash demo/tests/unit/test_env_validation.sh
|
||||||
|
|
||||||
|
# Full test suite (requires running stack)
|
||||||
|
./demo/scripts/demo-test.sh full
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
See [LICENSE](LICENSE).
|
||||||
|
|||||||
6
demo/.proselintrc
Normal file
6
demo/.proselintrc
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"flags": [
|
||||||
|
"typography.symbols.curly_quotes",
|
||||||
|
"leonard.exclamation.30ppm"
|
||||||
|
]
|
||||||
|
}
|
||||||
384
demo/AGENTS.md
Normal file
384
demo/AGENTS.md
Normal file
@@ -0,0 +1,384 @@
|
|||||||
|
# TSYS Developer Support Stack - Development Guidelines
|
||||||
|
|
||||||
|
## 🎯 Development Principles
|
||||||
|
|
||||||
|
### Demo-First Architecture
|
||||||
|
- **Demo-Only Configuration**: All services configured for demonstration purposes only
|
||||||
|
- **No Persistent Data**: Zero data persistence between demo sessions
|
||||||
|
- **Dynamic User Handling**: Automatic UID/GID detection and application
|
||||||
|
- **Security-First**: Docker socket proxy for all container operations
|
||||||
|
- **Minimal Bind Mounts**: Prefer Docker volumes over host bind mounts. Use host bind mounts only for minimal bootstrap purposes of configuration data that needs to be persistent.
|
||||||
|
- **Consistent Naming**: `kneldevstack-supportstack-demo-` prefix everywhere including in the docker-compose file for the service names.
|
||||||
|
- **One-Command Deployment**: Single script deployment with full validation
|
||||||
|
|
||||||
|
### Dynamic Environment Strategy
|
||||||
|
- **User Detection**: Automatic current user and group ID detection
|
||||||
|
- **Docker Group Handling**: Dynamic docker group ID resolution
|
||||||
|
- **Variable-Driven Configuration**: All settings via environment variables
|
||||||
|
- **Template-Based Compose**: Generate docker-compose.yml from templates
|
||||||
|
- **Environment Isolation**: Separate demo.env for all configuration
|
||||||
|
|
||||||
|
### FOSS Only Policy
|
||||||
|
- Exclusively use free/libre/open source software
|
||||||
|
- Verify license compatibility
|
||||||
|
- Prefer official Docker images
|
||||||
|
- Document any proprietary dependencies
|
||||||
|
|
||||||
|
### Inner Loop Focus
|
||||||
|
- Support daily development workflows
|
||||||
|
- Avoid project-specific dependencies
|
||||||
|
- Prioritize developer productivity
|
||||||
|
- Maintain workstation-local deployment
|
||||||
|
|
||||||
|
### Code Organization Policy
|
||||||
|
- **Mandatory Code Subdirectory**: ALL created files, configurations, scripts, and code MUST be placed in the `code/` subdirectory
|
||||||
|
- **No Root-Level Code**: Absolutely NO code files shall be created at the project root level
|
||||||
|
- **Structured Organization**: All implementation artifacts belong under `code/` with proper subdirectory organization
|
||||||
|
|
||||||
|
### System Interference Policy
|
||||||
|
- **NEVER interfere with existing processes**: Do not kill, stop, or modify any running processes without explicit permission
|
||||||
|
- **Check before acting**: Always verify what processes/screen sessions are running before taking any action
|
||||||
|
- **Use unique identifiers**: Create uniquely named sessions/processes to avoid conflicts
|
||||||
|
- **Ask first**: Always request permission before touching any existing work on the system
|
||||||
|
- **Respect concurrent work**: Other users/processes may be running - do not assume exclusive access
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛡️ Quality Assurance Standards
|
||||||
|
|
||||||
|
### Mandatory Tool Validation
|
||||||
|
- **yamllint**: ALL YAML files MUST pass yamllint validation before commit
|
||||||
|
- **shellcheck**: ALL shell scripts MUST pass shellcheck validation before commit
|
||||||
|
- **hadolint**: ALL Dockerfiles MUST pass hadolint validation before commit
|
||||||
|
- **Pre-commit Hooks**: Automated validation on every commit attempt
|
||||||
|
|
||||||
|
### Zero-Tolerance Policy
|
||||||
|
- **No YAML syntax errors**: Prevents Docker Compose failures
|
||||||
|
- **No shell script errors**: Prevents deployment script failures
|
||||||
|
- **No Docker image issues**: Prevents container startup failures
|
||||||
|
- **No port conflicts**: Prevents service accessibility issues
|
||||||
|
- **No permission problems**: Prevents file ownership issues
|
||||||
|
|
||||||
|
### Proactive Validation Checklist
|
||||||
|
Before ANY file is created or modified:
|
||||||
|
1. ✅ YAML syntax validated with yamllint
|
||||||
|
2. ✅ Shell script validated with shellcheck
|
||||||
|
3. ✅ Environment variables verified
|
||||||
|
4. ✅ Port availability confirmed
|
||||||
|
5. ✅ Docker image existence verified
|
||||||
|
6. ✅ Service dependencies validated
|
||||||
|
7. ✅ Health check endpoints confirmed
|
||||||
|
8. ✅ Resource requirements assessed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏗️ Architecture Guidelines
|
||||||
|
|
||||||
|
### Service Categories
|
||||||
|
- **Infrastructure Services**: Core platform services
|
||||||
|
- **Monitoring & Observability**: Metrics and visualization
|
||||||
|
- **Documentation & Diagramming**: Knowledge management
|
||||||
|
- **Developer Tools**: Productivity enhancers
|
||||||
|
|
||||||
|
### Design Patterns
|
||||||
|
- **Service Discovery**: Automatic via Homepage dashboard
|
||||||
|
- **Health Checks**: Comprehensive for all services
|
||||||
|
- **Network Isolation**: Docker network per stack
|
||||||
|
- **Resource Limits**: Memory and CPU constraints
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Technical Standards
|
||||||
|
|
||||||
|
### Docker Configuration Standards
|
||||||
|
|
||||||
|
#### Demo Service Template
|
||||||
|
```yaml
|
||||||
|
# Standard service template (docker-compose.yml.template)
|
||||||
|
services:
|
||||||
|
service-name:
|
||||||
|
image: official/image:tag
|
||||||
|
user: "${UID}:${GID}"
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-service-name"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
volumes:
|
||||||
|
- "${COMPOSE_PROJECT_NAME}_service_data:/path"
|
||||||
|
environment:
|
||||||
|
- PUID=${UID}
|
||||||
|
- PGID=${GID}
|
||||||
|
labels:
|
||||||
|
homepage.group: "Group Name"
|
||||||
|
homepage.name: "Display Name"
|
||||||
|
homepage.icon: "icon-name"
|
||||||
|
homepage.href: "http://localhost:${SERVICE_PORT}"
|
||||||
|
homepage.description: "Brief description"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Dynamic Variable Requirements
|
||||||
|
- **UID/GID**: Current user and group detection
|
||||||
|
- **DOCKER_GID**: Docker group ID for socket access
|
||||||
|
- **COMPOSE_PROJECT_NAME**: `kneldevstack-supportstack-demo`
|
||||||
|
- **COMPOSE_NETWORK_NAME**: `kneldevstack-supportstack-demo-network`
|
||||||
|
- **Service Ports**: All configurable via environment variables
|
||||||
|
|
||||||
|
### Port Assignment Strategy
|
||||||
|
- Range: 4000-4099
|
||||||
|
- Groups: Sequential allocation
|
||||||
|
- Document in README.md port table
|
||||||
|
- Avoid conflicts with host services
|
||||||
|
|
||||||
|
### Network Configuration
|
||||||
|
- Network name: `kneldevstack-supportstack-demo`
|
||||||
|
- IP binding: `192.168.3.6:{port}` where applicable
|
||||||
|
- Inter-service communication via container names
|
||||||
|
- Only necessary ports exposed to host
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Quality Assurance
|
||||||
|
|
||||||
|
### Testing Requirements
|
||||||
|
- Automated health check validation
|
||||||
|
- Port accessibility verification
|
||||||
|
- Service discovery functionality
|
||||||
|
- Resource usage monitoring
|
||||||
|
- User workflow validation
|
||||||
|
|
||||||
|
### Code Quality Standards
|
||||||
|
- Clear, commented configurations
|
||||||
|
- Consistent naming conventions
|
||||||
|
- Comprehensive documentation
|
||||||
|
- Atomic commits with conventional messages
|
||||||
|
|
||||||
|
### Security Guidelines
|
||||||
|
|
||||||
|
#### Demo Security Model
|
||||||
|
- **Demo-Hardened Configurations**: All settings optimized for demonstration
|
||||||
|
- **No External Network Access**: Isolated except for image pulls
|
||||||
|
- **Production Separation**: Clear distinction from production deployments
|
||||||
|
- **Security Documentation**: All assumptions clearly documented
|
||||||
|
|
||||||
|
#### Docker Socket Security
|
||||||
|
- **Mandatory Proxy**: All container operations through docker-socket-proxy
|
||||||
|
- **Restricted API Access**: Minimal permissions per service requirements
|
||||||
|
- **No Direct Socket Access**: Prevent direct Docker socket mounting
|
||||||
|
- **Group-Based Access**: Dynamic docker group ID assignment
|
||||||
|
|
||||||
|
#### File System Security
|
||||||
|
- **Dynamic User Mapping**: Automatic UID/GID detection prevents ownership issues
|
||||||
|
- **Volume-First Storage**: Prefer Docker volumes over bind mounts
|
||||||
|
- **Read-Only Bind Mounts**: Minimal host filesystem access
|
||||||
|
- **Permission Validation**: Automated file ownership verification
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Development Workflow
|
||||||
|
|
||||||
|
### Demo-First Service Addition
|
||||||
|
1. **Research**: Verify FOSS status and official Docker image availability
|
||||||
|
2. **Plan**: Determine port assignment and service group
|
||||||
|
3. **Template Configuration**: Add to docker-compose.yml.template with variables
|
||||||
|
4. **Environment Setup**: Add service variables to demo.env
|
||||||
|
5. **Security Integration**: Configure docker-socket-proxy permissions
|
||||||
|
6. **Dynamic Testing**: Validate with demo-stack.sh and demo-test.sh
|
||||||
|
7. **Documentation Update**: Update README.md, PRD.md, and AGENTS.md
|
||||||
|
8. **Atomic Commit**: Conventional commit with detailed description
|
||||||
|
|
||||||
|
### Process Management Guidelines
|
||||||
|
- **Screen Sessions**: Use descriptive, unique names (e.g., `demo-deploy-YYYYMMDD-HHMMSS`)
|
||||||
|
- **Background Processes**: Always use logging to track progress
|
||||||
|
- **Process Discovery**: Use `ps aux | grep` and `screen -ls` to check existing work
|
||||||
|
- **Safe Termination**: Only terminate processes you explicitly started
|
||||||
|
- **Permission First**: Always ask before modifying/killing any existing process
|
||||||
|
|
||||||
|
### Template-Driven Development
|
||||||
|
- **Variable Configuration**: All settings via environment variables
|
||||||
|
- **Naming Convention**: Consistent `kneldevstack-supportstack-demo-` prefix
|
||||||
|
- **User Handling**: Dynamic UID/GID detection in all services
|
||||||
|
- **Security Integration**: Docker socket proxy for container operations
|
||||||
|
- **Volume Strategy**: Docker volumes with dynamic naming
|
||||||
|
|
||||||
|
### Service Removal Process
|
||||||
|
1. **Deprecate**: Mark service for removal in documentation
|
||||||
|
2. **Test**: Verify stack functionality without service
|
||||||
|
3. **Remove**: Delete from docker-compose.yml
|
||||||
|
4. **Update**: Clean up documentation and port assignments
|
||||||
|
5. **Commit**: Document removal in commit message
|
||||||
|
|
||||||
|
### Configuration Changes
|
||||||
|
1. **Plan**: Document change rationale and impact
|
||||||
|
2. **Test**: Validate in development environment
|
||||||
|
3. **Update**: Apply changes to configuration files
|
||||||
|
4. **Verify**: Run full test suite
|
||||||
|
5. **Document**: Update relevant documentation
|
||||||
|
6. **Commit**: Atomic commit with detailed description
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Monitoring & Observability
|
||||||
|
|
||||||
|
### Health Check Standards
|
||||||
|
- All services must include health checks
|
||||||
|
- Health checks complete within 10 seconds
|
||||||
|
- HTTP endpoints preferred
|
||||||
|
- Fallback to container status checks
|
||||||
|
|
||||||
|
### Resource Limits
|
||||||
|
- Memory: < 512MB per service (where applicable)
|
||||||
|
- CPU: < 25% per service (idle)
|
||||||
|
- Startup time: < 60 seconds for full stack
|
||||||
|
- Disk usage: Temporary volumes only
|
||||||
|
|
||||||
|
### Logging Standards
|
||||||
|
- Structured logging where possible
|
||||||
|
- Log levels: INFO, WARN, ERROR
|
||||||
|
- Container logs accessible via `docker compose logs`
|
||||||
|
- No persistent log storage in demo mode
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Testing Guidelines
|
||||||
|
|
||||||
|
### Demo Testing Framework
|
||||||
|
```bash
|
||||||
|
# ALWAYS check for existing work first
|
||||||
|
screen -ls
|
||||||
|
ps aux | grep demo-stack
|
||||||
|
|
||||||
|
# Dynamic deployment and testing (use unique session names)
|
||||||
|
screen -S demo-deploy-$(date +%Y%m%d-%H%M%S) -dm -L -Logfile deploy-$(date +%Y%m%d-%H%M%S).log ./scripts/demo-stack.sh deploy
|
||||||
|
./scripts/demo-test.sh full # Comprehensive QA/validation
|
||||||
|
./scripts/demo-test.sh security # Security compliance validation
|
||||||
|
./scripts/demo-test.sh permissions # File ownership validation
|
||||||
|
./scripts/demo-test.sh network # Network isolation validation
|
||||||
|
```
|
||||||
|
|
||||||
|
### Automated Validation Suite
|
||||||
|
- **File Ownership**: Verify no root-owned files on host
|
||||||
|
- **User Mapping**: Validate UID/GID detection and application
|
||||||
|
- **Docker Group**: Confirm docker group access for socket proxy
|
||||||
|
- **Service Health**: All services passing health checks
|
||||||
|
- **Port Accessibility**: Verify all ports accessible from host
|
||||||
|
- **Network Isolation**: Confirm services isolated in demo network
|
||||||
|
- **Volume Permissions**: Validate Docker volume permissions
|
||||||
|
- **Security Compliance**: Docker socket proxy restrictions enforced
|
||||||
|
|
||||||
|
### Manual Testing Checklist
|
||||||
|
- [ ] All web interfaces accessible via browser
|
||||||
|
- [ ] Demo credentials work correctly
|
||||||
|
- [ ] Service discovery functional in Homepage
|
||||||
|
- [ ] Inter-service communication working through proxy
|
||||||
|
- [ ] Resource usage within defined limits
|
||||||
|
- [ ] No port conflicts on host system
|
||||||
|
- [ ] All health checks passing
|
||||||
|
- [ ] No root-owned files created on host
|
||||||
|
- [ ] Docker socket proxy functioning correctly
|
||||||
|
- [ ] Dynamic user detection working properly
|
||||||
|
|
||||||
|
### Performance Testing
|
||||||
|
- Startup time measurement
|
||||||
|
- Memory usage monitoring
|
||||||
|
- CPU usage validation
|
||||||
|
- Network connectivity testing
|
||||||
|
- Resource leak detection
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Documentation Standards
|
||||||
|
|
||||||
|
### README.md Requirements
|
||||||
|
- Quick start instructions
|
||||||
|
- Service overview table
|
||||||
|
- Technical configuration details
|
||||||
|
- Troubleshooting guide
|
||||||
|
- Security notes and warnings
|
||||||
|
|
||||||
|
### PRD.md Requirements
|
||||||
|
- Product vision and goals
|
||||||
|
- Functional requirements
|
||||||
|
- User experience requirements
|
||||||
|
- Acceptance criteria
|
||||||
|
- Success metrics
|
||||||
|
|
||||||
|
### AGENTS.md Requirements
|
||||||
|
- Development principles
|
||||||
|
- Technical standards
|
||||||
|
- Quality assurance guidelines
|
||||||
|
- Development workflow
|
||||||
|
- Testing procedures
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 Security Considerations
|
||||||
|
|
||||||
|
### Demo Security Model
|
||||||
|
- Hardcoded credentials clearly marked
|
||||||
|
- No encryption or security hardening
|
||||||
|
- Network isolation within Docker
|
||||||
|
- No external access except image pulls
|
||||||
|
|
||||||
|
### Security Checklist
|
||||||
|
- [ ] All services use demo credentials
|
||||||
|
- [ ] No persistent sensitive data
|
||||||
|
- [ ] Network properly isolated
|
||||||
|
- [ ] Only necessary ports exposed
|
||||||
|
- [ ] Security warnings documented
|
||||||
|
- [ ] Production deployment guidance included
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Deployment Guidelines
|
||||||
|
|
||||||
|
### Local Development
|
||||||
|
```bash
|
||||||
|
# Check for existing work BEFORE starting
|
||||||
|
screen -ls
|
||||||
|
ps aux | grep demo-stack
|
||||||
|
|
||||||
|
# Start development stack with unique session name
|
||||||
|
screen -S demo-deploy-$(date +%Y%m%d-%H%M%S) -dm -L -Logfile deploy-$(date +%Y%m%d-%H%M%S).log ./scripts/demo-stack.sh deploy
|
||||||
|
|
||||||
|
# Monitor startup
|
||||||
|
docker compose logs -f
|
||||||
|
|
||||||
|
# Validate deployment
|
||||||
|
./scripts/demo-test.sh full
|
||||||
|
```
|
||||||
|
|
||||||
|
### Demo Preparation
|
||||||
|
1. Clean all containers and volumes
|
||||||
|
2. Pull latest images
|
||||||
|
3. Verify all health checks
|
||||||
|
4. Test complete user workflows
|
||||||
|
5. Document any known issues
|
||||||
|
|
||||||
|
### Production Migration
|
||||||
|
- Replace demo credentials with secure ones
|
||||||
|
- Implement persistent data storage
|
||||||
|
- Add encryption and security hardening
|
||||||
|
- Configure backup and recovery
|
||||||
|
- Set up monitoring and alerting
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📞 Development Support
|
||||||
|
|
||||||
|
### Getting Help
|
||||||
|
1. Check troubleshooting section in README.md
|
||||||
|
2. Review service logs: `docker compose logs {service}`
|
||||||
|
3. Consult individual service documentation
|
||||||
|
4. Check health status: `docker compose ps`
|
||||||
|
5. **CRITICAL**: Always check for existing processes before starting new ones: `screen -ls` and `ps aux | grep demo-stack`
|
||||||
|
|
||||||
|
### Issue Reporting
|
||||||
|
- Include full error messages
|
||||||
|
- Provide system information
|
||||||
|
- Document reproduction steps
|
||||||
|
- Include relevant configuration snippets
|
||||||
|
- Specify demo vs production context
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Last updated: 2025-11-13*
|
||||||
766
demo/PRD.md
Normal file
766
demo/PRD.md
Normal file
@@ -0,0 +1,766 @@
|
|||||||
|
# 📋 TSYS Developer Support Stack - Product Requirements Document
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
[](#)
|
||||||
|
[](#)
|
||||||
|
[](#)
|
||||||
|
[](#)
|
||||||
|
[](#)
|
||||||
|
|
||||||
|
**Demo Version - Product Requirements Document**
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📖 Table of Contents
|
||||||
|
|
||||||
|
- [🎯 Product Vision](#-product-vision)
|
||||||
|
- [🏗️ Architecture Overview](#️-architecture-overview)
|
||||||
|
- [📊 Functional Requirements](#-functional-requirements)
|
||||||
|
- [🔧 Technical Requirements](#-technical-requirements)
|
||||||
|
- [🎨 User Experience Requirements](#-user-experience-requirements)
|
||||||
|
- [🔒 Security Requirements](#-security-requirements)
|
||||||
|
- [📋 Non-Functional Requirements](#-non-functional-requirements)
|
||||||
|
- [🧪 Testing Requirements](#-testing-requirements)
|
||||||
|
- [📚 Documentation Requirements](#-documentation-requirements)
|
||||||
|
- [✅ Acceptance Criteria](#-acceptance-criteria)
|
||||||
|
- [🚀 Success Metrics](#-success-metrics)
|
||||||
|
- [📅 Implementation Timeline](#-implementation-timeline)
|
||||||
|
- [🔄 Change Management](#-change-management)
|
||||||
|
- [📞 Support & Maintenance](#-support--maintenance)
|
||||||
|
- [📋 Appendix](#-appendix)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Product Vision
|
||||||
|
|
||||||
|
> **To create a comprehensive, demo-ready developer support services stack that enhances developer productivity and quality of life for the TSYS engineering team.**
|
||||||
|
|
||||||
|
This stack is designed to:
|
||||||
|
- 🏠 **Run locally** on every developer workstation
|
||||||
|
- ⚡ **Support daily development workflows** with essential services
|
||||||
|
- 🔒 **Maintain security** and simplicity
|
||||||
|
- 🆓 **Adhere to free/libre/open source principles**
|
||||||
|
- 🎯 **Focus on inner loop development** rather than project-specific dependencies
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏗️ Architecture Overview
|
||||||
|
|
||||||
|
### 🎨 Design Principles
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
A[Demo-First] --> E[TSYS Support Stack]
|
||||||
|
B[Service Discovery] --> E
|
||||||
|
C[FOSS Only] --> E
|
||||||
|
D[Inner Loop Focus] --> E
|
||||||
|
F[Workstation Local] --> E
|
||||||
|
G[Security Conscious] --> E
|
||||||
|
|
||||||
|
style A fill:#ffeb3b
|
||||||
|
style B fill:#4caf50
|
||||||
|
style C fill:#2196f3
|
||||||
|
style D fill:#ff9800
|
||||||
|
style F fill:#9c27b0
|
||||||
|
style G fill:#f44336
|
||||||
|
style E fill:#e1f5fe
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
| Principle | Description | Priority |
|
||||||
|
|-----------|-------------|----------|
|
||||||
|
| **🎭 Demo-First Architecture** | Demonstration-only deployment with dynamic user detection, no persistence, one-command deployment | 🔥 High |
|
||||||
|
| **🔍 Service Discovery** | Automatic discovery via Homepage dashboard with Docker labels | 🔥 High |
|
||||||
|
| **🆓 FOSS Only** | Exclusively use free/libre/open source software | 🔥 High |
|
||||||
|
| **⚡ Inner Loop Focus** | Support daily development workflows, not project-specific dependencies | 🔥 High |
|
||||||
|
| **🏠 Workstation Local** | Run locally on developer machines, not centralized infrastructure | 🔥 High |
|
||||||
|
| **🔒 Security Conscious** | Demo-hardened configurations with clear production separation | 🔥 High |
|
||||||
|
|
||||||
|
### 📦 Service Categories
|
||||||
|
|
||||||
|
| Category | Purpose | Services |
|
||||||
|
|----------|---------|----------|
|
||||||
|
| **🏗️ Infrastructure Services** | Core platform and management services | DNS Management, Container Socket Proxy, Container Management |
|
||||||
|
| **📊 Monitoring & Observability** | Data collection and visualization services | Time Series Database, Visualization Platform |
|
||||||
|
| **📚 Documentation & Diagramming** | Knowledge management and creation tools | Diagramming Server, Diagrams as a Service |
|
||||||
|
| **🛠️ Developer Tools** | Productivity and workflow enhancement services | Homepage, Time Tracking, Archiving, Email Testing, Habit Tracking |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Functional Requirements
|
||||||
|
|
||||||
|
### 🏗️ FR-001: Infrastructure Services
|
||||||
|
|
||||||
|
#### FR-001.1: DNS Management Service
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[DNS Management Service] --> B[Web Administration]
|
||||||
|
A --> C[DNS Filtering]
|
||||||
|
A --> D[Network Monitoring]
|
||||||
|
A --> E[Demo Configuration]
|
||||||
|
A --> F[Health Monitoring]
|
||||||
|
A --> G[Service Discovery]
|
||||||
|
|
||||||
|
style A fill:#e3f2fd
|
||||||
|
style B fill:#bbdefb
|
||||||
|
style C fill:#bbdefb
|
||||||
|
style D fill:#bbdefb
|
||||||
|
style E fill:#fff3e0
|
||||||
|
style F fill:#e8f5e8
|
||||||
|
style G fill:#fce4ec
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
| Requirement | Description | Acceptance |
|
||||||
|
|-------------|-------------|------------|
|
||||||
|
| **🌐 Web Interface** | Browser-based administration interface | ✅ Required |
|
||||||
|
| **🛡️ DNS Filtering** | Ad blocking and content filtering capabilities | ✅ Required |
|
||||||
|
| **📊 Network Monitoring** | Traffic analysis and reporting | ✅ Required |
|
||||||
|
| **🎭 Demo Configuration** | Default settings for demonstration | ✅ Required |
|
||||||
|
| **🔗 Web Access** | Assigned port for web interface | ✅ Required |
|
||||||
|
| **❤️ Health Check** | Endpoint for service monitoring | ✅ Required |
|
||||||
|
| **🏷️ Service Discovery** | Integration with Infrastructure group | ✅ Required |
|
||||||
|
|
||||||
|
#### FR-001.2: Container Socket Proxy
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[Container Socket Proxy] --> B[API Access Control]
|
||||||
|
A --> C[Request Filtering]
|
||||||
|
A --> D[Security Restrictions]
|
||||||
|
A --> E[Permission Management]
|
||||||
|
A --> F[Health Monitoring]
|
||||||
|
A --> G[Service Discovery]
|
||||||
|
|
||||||
|
style A fill:#ffebee
|
||||||
|
style B fill:#ffcdd2
|
||||||
|
style C fill:#ffcdd2
|
||||||
|
style D fill:#ffcdd2
|
||||||
|
style E fill:#fff3e0
|
||||||
|
style F fill:#e8f5e8
|
||||||
|
style G fill:#fce4ec
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
| Requirement | Description | Acceptance |
|
||||||
|
|-------------|-------------|------------|
|
||||||
|
| **🛡️ API Access Control** | Restrict Docker socket API endpoints | ✅ Required |
|
||||||
|
| **🔍 Request Filtering** | Block dangerous operations by default | ✅ Required |
|
||||||
|
| **🔒 Security Restrictions** | Granular permission management | ✅ Required |
|
||||||
|
| **⚙️ Permission Management** | Environment-based access control | ✅ Required |
|
||||||
|
| **❤️ Health Check** | Endpoint for service monitoring | ✅ Required |
|
||||||
|
| **🏷️ Service Discovery** | Integration with Infrastructure group | ✅ Required |
|
||||||
|
|
||||||
|
#### FR-001.3: Container Management Service
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[Container Management Service] --> B[Container Lifecycle]
|
||||||
|
A --> C[Image Management]
|
||||||
|
A --> D[Volume & Network Management]
|
||||||
|
A --> E[User Authentication]
|
||||||
|
A --> F[Health Monitoring]
|
||||||
|
A --> G[Service Discovery]
|
||||||
|
|
||||||
|
style A fill:#f3e5f5
|
||||||
|
style B fill:#e1bee7
|
||||||
|
style C fill:#e1bee7
|
||||||
|
style D fill:#e1bee7
|
||||||
|
style E fill:#fff3e0
|
||||||
|
style F fill:#e8f5e8
|
||||||
|
style G fill:#fce4ec
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
| Requirement | Description | Acceptance |
|
||||||
|
|-------------|-------------|------------|
|
||||||
|
| **🔄 Container Lifecycle** | Start/stop/restart container operations | ✅ Required |
|
||||||
|
| **📦 Image Management** | Registry integration and image operations | ✅ Required |
|
||||||
|
| **💾 Volume & Network** | Storage and network configuration | ✅ Required |
|
||||||
|
| **🔐 Authentication** | User authentication with demo credentials | ✅ Required |
|
||||||
|
| **🔗 Web Access** | Assigned port for web interface | ✅ Required |
|
||||||
|
| **❤️ Health Check** | Endpoint for service monitoring | ✅ Required |
|
||||||
|
| **🏷️ Service Discovery** | Integration with Infrastructure group | ✅ Required |
|
||||||
|
|
||||||
|
### 📊 FR-002: Monitoring & Observability
|
||||||
|
|
||||||
|
#### FR-002.1: Time Series Database
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[Time Series Database] --> B[HTTP API]
|
||||||
|
A --> C[Web Administration]
|
||||||
|
A --> D[Demo Database]
|
||||||
|
A --> E[Data Access]
|
||||||
|
A --> F[Health Monitoring]
|
||||||
|
A --> G[Service Discovery]
|
||||||
|
|
||||||
|
style A fill:#e8f5e8
|
||||||
|
style B fill:#c8e6c9
|
||||||
|
style C fill:#c8e6c9
|
||||||
|
style D fill:#fff3e0
|
||||||
|
style E fill:#bbdefb
|
||||||
|
style F fill:#e8f5e8
|
||||||
|
style G fill:#fce4ec
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
| Requirement | Description | Acceptance |
|
||||||
|
|-------------|-------------|------------|
|
||||||
|
| **🌐 HTTP API** | Data ingestion and querying interface | ✅ Required |
|
||||||
|
| **🖥️ Web Interface** | Browser-based administration | ✅ Required |
|
||||||
|
| **🎭 Demo Database** | Sample data for demonstration | ✅ Required |
|
||||||
|
| **🔗 Data Access** | Assigned port for API and web access | ✅ Required |
|
||||||
|
| **❤️ Health Check** | Endpoint for service monitoring | ✅ Required |
|
||||||
|
| **🏷️ Service Discovery** | Integration with Monitoring group | ✅ Required |
|
||||||
|
|
||||||
|
#### FR-002.2: Visualization Platform
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[Visualization Platform] --> B[Data Source Connection]
|
||||||
|
A --> C[Demo Dashboards]
|
||||||
|
A --> D[Dashboard Creation]
|
||||||
|
A --> E[Admin Authentication]
|
||||||
|
A --> F[Health Monitoring]
|
||||||
|
A --> G[Service Discovery]
|
||||||
|
|
||||||
|
style A fill:#fff3e0
|
||||||
|
style B fill:#ffe0b2
|
||||||
|
style C fill:#ffe0b2
|
||||||
|
style D fill:#ffe0b2
|
||||||
|
style E fill:#fff3e0
|
||||||
|
style F fill:#e8f5e8
|
||||||
|
style G fill:#fce4ec
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
| Requirement | Description | Acceptance |
|
||||||
|
|-------------|-------------|------------|
|
||||||
|
| **🔗 Data Connection** | Pre-configured connection to time series database | ✅ Required |
|
||||||
|
| **📊 Demo Dashboards** | System metrics visualization | ✅ Required |
|
||||||
|
| **🎨 Dashboard Creation** | Web-based dashboard editing | ✅ Required |
|
||||||
|
| **🔐 Admin Authentication** | Authentication with demo credentials | ✅ Required |
|
||||||
|
| **🔗 Web Access** | Assigned port for web interface | ✅ Required |
|
||||||
|
| **❤️ Health Check** | Endpoint for service monitoring | ✅ Required |
|
||||||
|
| **🏷️ Service Discovery** | Integration with Monitoring group | ✅ Required |
|
||||||
|
|
||||||
|
### 🛠️ FR-003: Developer Tools
|
||||||
|
|
||||||
|
#### FR-003.1: Habit Tracking Service
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[Habit Tracking Service] --> B[Personal Dashboard]
|
||||||
|
A --> C[Habit Management]
|
||||||
|
A --> D[Progress Tracking]
|
||||||
|
A --> E[Gamification System]
|
||||||
|
A --> F[Integrations Support]
|
||||||
|
A --> G[Health Monitoring]
|
||||||
|
A --> H[Service Discovery]
|
||||||
|
|
||||||
|
style A fill:#fff3e0
|
||||||
|
style B fill:#ffe0b2
|
||||||
|
style C fill:#ffe0b2
|
||||||
|
style D fill:#ffe0b2
|
||||||
|
style E fill:#ffe0b2
|
||||||
|
style F fill:#e8f5e8
|
||||||
|
style G fill:#e8f5e8
|
||||||
|
style H fill:#fce4ec
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
| Requirement | Description | Acceptance |
|
||||||
|
|-------------|-------------|------------|
|
||||||
|
| **📊 Personal Dashboard** | Visual overview of habits and progress | ✅ Required |
|
||||||
|
| **🎯 Habit Management** | Create, edit, and delete habits | ✅ Required |
|
||||||
|
| **📈 Progress Tracking** | Track consistency and improvements | ✅ Required |
|
||||||
|
| **🎮 Gamification** | Points system and achievement tracking | ✅ Required |
|
||||||
|
| **🔗 Integrations** | Support for external data providers | ✅ Optional |
|
||||||
|
| **🔗 Web Access** | Assigned port for web interface | ✅ Required |
|
||||||
|
| **❤️ Health Check** | Endpoint for service monitoring | ✅ Required |
|
||||||
|
| **🏷️ Service Discovery** | Integration with Developer Tools group | ✅ Required |
|
||||||
|
|
||||||
|
### 📚 FR-004: Documentation & Diagramming
|
||||||
|
|
||||||
|
#### FR-004.1: Diagramming Server
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[Diagramming Server] --> B[Browser-based Editing]
|
||||||
|
A --> C[Multiple Export Formats]
|
||||||
|
A --> D[Cloud Storage Integration]
|
||||||
|
A --> E[No Authentication]
|
||||||
|
A --> F[Health Monitoring]
|
||||||
|
A --> G[Service Discovery]
|
||||||
|
|
||||||
|
style A fill:#fce4ec
|
||||||
|
style B fill:#f8bbd9
|
||||||
|
style C fill:#f8bbd9
|
||||||
|
style D fill:#fff3e0
|
||||||
|
style E fill:#e8f5e8
|
||||||
|
style F fill:#e8f5e8
|
||||||
|
style G fill:#fce4ec
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
| Requirement | Description | Acceptance |
|
||||||
|
|-------------|-------------|------------|
|
||||||
|
| **🎨 Browser Editing** | Diagram creation and editing in browser | ✅ Required |
|
||||||
|
| **📤 Export Formats** | PNG, SVG, PDF export capabilities | ✅ Required |
|
||||||
|
| **☁️ Cloud Integration** | Optional cloud storage integration | ✅ Optional |
|
||||||
|
| **🔓 No Authentication** | Demo mode without login requirements | ✅ Required |
|
||||||
|
| **🔗 Web Access** | Assigned port for web interface | ✅ Required |
|
||||||
|
| **❤️ Health Check** | Endpoint for service monitoring | ✅ Required |
|
||||||
|
| **🏷️ Service Discovery** | Integration with Documentation group | ✅ Required |
|
||||||
|
|
||||||
|
#### FR-004.2: Diagrams as a Service
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[Diagrams as a Service] --> B[Multiple Diagram Types]
|
||||||
|
A --> C[HTTP API]
|
||||||
|
A --> D[Web Interface]
|
||||||
|
A --> E[No Authentication]
|
||||||
|
A --> F[Health Monitoring]
|
||||||
|
A --> G[Service Discovery]
|
||||||
|
|
||||||
|
style A fill:#e0f2f1
|
||||||
|
style B fill:#b2dfdb
|
||||||
|
style C fill:#b2dfdb
|
||||||
|
style D fill:#b2dfdb
|
||||||
|
style E fill:#e8f5e8
|
||||||
|
style F fill:#e8f5e8
|
||||||
|
style G fill:#fce4ec
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
| Requirement | Description | Acceptance |
|
||||||
|
|-------------|-------------|------------|
|
||||||
|
| **🎨 Diagram Types** | PlantUML, Mermaid, GraphViz support | ✅ Required |
|
||||||
|
| **🌐 HTTP API** | Programmatic diagram generation | ✅ Required |
|
||||||
|
| **🖥️ Web Interface** | Simple testing interface | ✅ Required |
|
||||||
|
| **🔓 No Authentication** | Demo mode without login requirements | ✅ Required |
|
||||||
|
| **🔗 API Access** | Assigned port for API and web access | ✅ Required |
|
||||||
|
| **❤️ Health Check** | Endpoint for service monitoring | ✅ Required |
|
||||||
|
| **🏷️ Service Discovery** | Integration with Documentation group | ✅ Required |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Technical Requirements
|
||||||
|
|
||||||
|
### 🐳 TR-001: Containerization Standards
|
||||||
|
|
||||||
|
| Requirement | Description | Priority |
|
||||||
|
|-------------|-------------|----------|
|
||||||
|
| **📦 Official Images** | Use official Docker images only | 🔥 High |
|
||||||
|
| **❤️ Health Checks** | Comprehensive health monitoring | 🔥 High |
|
||||||
|
| **🔍 Service Discovery** | Automatic dashboard integration | 🔥 High |
|
||||||
|
| **🔄 Restart Policies** | Appropriate recovery mechanisms | 🔥 High |
|
||||||
|
|
||||||
|
### 🌐 TR-002: Network Architecture
|
||||||
|
|
||||||
|
| Requirement | Description | Priority |
|
||||||
|
|-------------|-------------|----------|
|
||||||
|
| **🔒 Dedicated Network** | Isolated network environment | 🔥 High |
|
||||||
|
| **🔢 Port Consistency** | Sequential numbering pattern | 🔥 High |
|
||||||
|
| **🌐 Web Access** | Standard browser interfaces | 🔥 High |
|
||||||
|
| **🤝 Inter-service Communication** | Required service interactions | 🔥 High |
|
||||||
|
|
||||||
|
### 💾 TR-003: Data Strategy
|
||||||
|
|
||||||
|
| Requirement | Description | Priority |
|
||||||
|
|-------------|-------------|----------|
|
||||||
|
| **🚫 No Persistence** | Demo simplicity focus | 🔥 High |
|
||||||
|
| **⏰ Temporary Data** | Service functionality support | 🔥 High |
|
||||||
|
| **🔄 Session Reset** | Clean state between demos | 🔥 High |
|
||||||
|
| **🔐 Demo Credentials** | Simplified authentication | 🔥 High |
|
||||||
|
|
||||||
|
### 🔗 TR-004: Service Integration
|
||||||
|
|
||||||
|
| Requirement | Description | Priority |
|
||||||
|
|-------------|-------------|----------|
|
||||||
|
| **🏷️ Dashboard Discovery** | Centralized service visibility | 🔥 High |
|
||||||
|
| **📊 Consistent Metadata** | Standardized service information | 🔥 High |
|
||||||
|
| **🎨 Unified Access** | Consistent user experience | 🔥 High |
|
||||||
|
| **🔄 Standard Interfaces** | Common interaction patterns | 🔥 High |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎨 User Experience Requirements
|
||||||
|
|
||||||
|
### 🏠 UX-001: Unified Dashboard
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
A[Single Entry Point] --> B[Automatic Discovery]
|
||||||
|
A --> C[Intuitive Organization]
|
||||||
|
A --> D[Consistent Design]
|
||||||
|
A --> E[Real-time Status]
|
||||||
|
|
||||||
|
style A fill:#e1f5fe
|
||||||
|
style B fill:#b3e5fc
|
||||||
|
style C fill:#b3e5fc
|
||||||
|
style D fill:#b3e5fc
|
||||||
|
style E fill:#b3e5fc
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
| Requirement | Description | Success Metric |
|
||||||
|
|-------------|-------------|----------------|
|
||||||
|
| **🚪 Single Entry Point** | One dashboard for all services | 100% service visibility |
|
||||||
|
| **🔍 Automatic Discovery** | No manual configuration required | Zero-touch setup |
|
||||||
|
| **📂 Intuitive Organization** | Logical service grouping | User satisfaction > 90% |
|
||||||
|
| **🎨 Consistent Design** | Unified visual experience | Design consistency > 95% |
|
||||||
|
| **📊 Real-time Status** | Live service health indicators | Status accuracy > 99% |
|
||||||
|
|
||||||
|
### ⚡ UX-002: Zero-Configuration Access
|
||||||
|
|
||||||
|
| Requirement | Description | Success Metric |
|
||||||
|
|-------------|-------------|----------------|
|
||||||
|
| **🌐 Browser Access** | Immediate web interface availability | 100% browser compatibility |
|
||||||
|
| **🚫 No Manual Setup** | Eliminate configuration steps | Setup time < 2 minutes |
|
||||||
|
| **🔐 Pre-configured Auth** | Default authentication where needed | Login success rate > 95% |
|
||||||
|
| **💡 Clear Error Messages** | Intuitive troubleshooting guidance | Issue resolution < 2 minutes |
|
||||||
|
|
||||||
|
### 🎭 UX-003: Instant Demo Experience
|
||||||
|
|
||||||
|
| Requirement | Description | Success Metric |
|
||||||
|
|-------------|-------------|----------------|
|
||||||
|
| **⚡ Single Command** | One-command deployment | Deployment time < 5 minutes |
|
||||||
|
| **🚀 Rapid Initialization** | Fast service startup | All services ready < 5 minutes |
|
||||||
|
| **🎯 Immediate Features** | No setup delays for functionality | Feature availability = 100% |
|
||||||
|
| **🔄 Clean Sessions** | Fresh state between demos | Data reset success = 100% |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 Security Requirements
|
||||||
|
|
||||||
|
### 🛡️ SEC-001: Demo-Only Security Model
|
||||||
|
|
||||||
|
| Requirement | Description | Implementation |
|
||||||
|
|-------------|-------------|----------------|
|
||||||
|
| **🎭 Demo Configuration** | Development/demo use only | Clear documentation warnings |
|
||||||
|
| **🔓 Hardcoded Credentials** | Clearly marked demo credentials | Obvious demo-only labeling |
|
||||||
|
| **🚫 No External Access** | Isolated from external networks | Docker network isolation |
|
||||||
|
| **🔓 No Hardening** | No encryption or security features | Simplified demo setup |
|
||||||
|
|
||||||
|
### 🔒 SEC-002: Network Isolation
|
||||||
|
|
||||||
|
| Requirement | Description | Implementation |
|
||||||
|
|-------------|-------------|----------------|
|
||||||
|
| **🏠 Docker Isolation** | Services contained within Docker network | Dedicated network configuration |
|
||||||
|
| **🔌 Minimal Exposure** | Only necessary ports exposed | Port access control |
|
||||||
|
| **🚫 No Privilege Escalation** | Prevent container privilege escalation | Security context configuration |
|
||||||
|
| **🔗 Secure API Access** | Container socket proxy for API access | Proxy service implementation |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Non-Functional Requirements
|
||||||
|
|
||||||
|
### ⚡ NFR-001: Performance
|
||||||
|
|
||||||
|
| Metric | Requirement | Target |
|
||||||
|
|--------|-------------|--------|
|
||||||
|
| **🚀 Startup Time** | All services must start within | 60 seconds |
|
||||||
|
| **❤️ Health Check Speed** | Health checks must complete within | 10 seconds |
|
||||||
|
| **💾 Memory Usage** | Per service memory limit | < 512MB |
|
||||||
|
| **🖥️ CPU Usage** | Per service CPU usage (idle) | < 25% |
|
||||||
|
|
||||||
|
### 🔄 NFR-002: Reliability
|
||||||
|
|
||||||
|
| Requirement | Description | Implementation |
|
||||||
|
|-------------|-------------|----------------|
|
||||||
|
| **❤️ Health Checks** | All services include health monitoring | Comprehensive health endpoints |
|
||||||
|
| **🔄 Auto Restart** | Automatic recovery on failure | Restart policy configuration |
|
||||||
|
| **⏹️ Graceful Shutdown** | Proper service termination handling | Signal handling implementation |
|
||||||
|
| **🔗 Dependency Management** | Service startup order management | Dependency configuration |
|
||||||
|
|
||||||
|
### 🔧 NFR-003: Maintainability
|
||||||
|
|
||||||
|
| Requirement | Description | Standard |
|
||||||
|
|-------------|-------------|----------|
|
||||||
|
| **📝 Clear Configuration** | Well-documented setup | Commented configurations |
|
||||||
|
| **🏷️ Consistent Naming** | Standardized service organization | Naming conventions |
|
||||||
|
| **📚 Comprehensive Docs** | Complete documentation coverage | Documentation standards |
|
||||||
|
| **➕ Easy Service Management** | Simple addition/removal processes | Modular architecture |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Testing Requirements
|
||||||
|
|
||||||
|
### 🤖 TST-001: Automated Testing
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[Automated Testing] --> B[Health Validation]
|
||||||
|
A --> C[Port Verification]
|
||||||
|
A --> D[Service Discovery]
|
||||||
|
A --> E[Resource Monitoring]
|
||||||
|
A --> F[Comprehensive Suite]
|
||||||
|
|
||||||
|
style A fill:#e8f5e8
|
||||||
|
style B fill:#c8e6c9
|
||||||
|
style C fill:#c8e6c9
|
||||||
|
style D fill:#c8e6c9
|
||||||
|
style E fill:#c8e6c9
|
||||||
|
style F fill:#c8e6c9
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
| Test Type | Description | Tool/Script |
|
||||||
|
|-----------|-------------|-------------|
|
||||||
|
| **❤️ Health Validation** | Service health check verification | `demo-test.sh` |
|
||||||
|
| **🔌 Port Accessibility** | Port availability and response testing | `test-stack.sh` |
|
||||||
|
| **🔍 Service Discovery** | Dashboard integration verification | `test-stack.sh` |
|
||||||
|
| **📊 Resource Monitoring** | Memory and CPU usage validation | `test-stack.sh` |
|
||||||
|
| **📋 Comprehensive Suite** | Full integration testing | `test-stack.sh` |
|
||||||
|
|
||||||
|
### ✋ TST-002: Manual Testing
|
||||||
|
|
||||||
|
| Test Area | Description | Success Criteria |
|
||||||
|
|-----------|-------------|------------------|
|
||||||
|
| **🌐 Web Interfaces** | Browser interface functionality | All interfaces accessible |
|
||||||
|
| **🔐 Demo Credentials** | Authentication verification | Login success = 100% |
|
||||||
|
| **🔗 Service Integration** | Cross-service functionality | Integration tests pass |
|
||||||
|
| **👤 User Workflows** | End-to-end user scenarios | Workflow completion = 100% |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Documentation Requirements
|
||||||
|
|
||||||
|
### 📖 DOC-001: Technical Documentation
|
||||||
|
|
||||||
|
| Requirement | Description | Location |
|
||||||
|
|-------------|-------------|----------|
|
||||||
|
| **📋 README Updates** | Complete service documentation | `README.md` |
|
||||||
|
| **🌐 Access Information** | Service URLs and credentials | `README.md` |
|
||||||
|
| **⚙️ Configuration Details** | Technical setup specifications | `README.md` |
|
||||||
|
| **🔧 Troubleshooting Guide** | Common issue resolution | `README.md` |
|
||||||
|
|
||||||
|
### 👥 DOC-002: User Documentation
|
||||||
|
|
||||||
|
| Requirement | Description | Location |
|
||||||
|
|-------------|-------------|----------|
|
||||||
|
| **🚀 Quick Start** | Rapid deployment instructions | `README.md` |
|
||||||
|
| **📚 Service Descriptions** | Feature and use case documentation | `README.md` |
|
||||||
|
| **🔐 Credential Reference** | Demo credential information | `README.md` |
|
||||||
|
| **❓ FAQ Section** | Common questions and answers | `README.md` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Acceptance Criteria
|
||||||
|
|
||||||
|
### 🚀 AC-001: Deployment Success
|
||||||
|
|
||||||
|
| Criteria | Description | Status |
|
||||||
|
|----------|-------------|--------|
|
||||||
|
| **⚡ Service Startup** | All services start with `docker compose up -d` | ✅ Required |
|
||||||
|
| **❤️ Health Validation** | All services pass health checks within 60 seconds | ✅ Required |
|
||||||
|
| **🔍 Service Discovery** | Homepage discovers and displays all services | ✅ Required |
|
||||||
|
| **🌐 Web Access** | All interfaces accessible via browser | ✅ Required |
|
||||||
|
|
||||||
|
### 🔧 AC-002: Functionality Verification
|
||||||
|
|
||||||
|
| Criteria | Description | Status |
|
||||||
|
|----------|-------------|--------|
|
||||||
|
| **🛡️ DNS Management** | Web interface loads and functions correctly | ✅ Required |
|
||||||
|
| **🔄 Container Management** | Container operations work properly | ✅ Required |
|
||||||
|
| **📊 Database Operations** | Data storage and retrieval functional | ✅ Required |
|
||||||
|
| **📈 Visualization** | Dashboards display and update correctly | ✅ Required |
|
||||||
|
| **🎨 Diagramming** | Creation and export functions work | ✅ Required |
|
||||||
|
| **📐 Diagram Service** | Text-to-diagram conversion functional | ✅ Required |
|
||||||
|
|
||||||
|
### 🔗 AC-003: Integration Testing
|
||||||
|
|
||||||
|
| Criteria | Description | Status |
|
||||||
|
|----------|-------------|--------|
|
||||||
|
| **🔍 Service Discovery** | Automatic discovery works correctly | ✅ Required |
|
||||||
|
| **🤝 Inter-service Communication** | Required communications function | ✅ Required |
|
||||||
|
| **❤️ Health Monitoring** | Health checks trigger appropriately | ✅ Required |
|
||||||
|
| **📊 Resource Management** | Usage remains within defined limits | ✅ Required |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Success Metrics
|
||||||
|
|
||||||
|
### 📊 Deployment Metrics
|
||||||
|
|
||||||
|
| Metric | Target | Measurement |
|
||||||
|
|--------|--------|-------------|
|
||||||
|
| **⏱️ Stack Readiness** | < 2 minutes | Time to full functionality |
|
||||||
|
| **✅ Service Success Rate** | 100% | Services starting successfully |
|
||||||
|
| **❤️ Health Check Pass Rate** | 100% | Services passing health checks |
|
||||||
|
|
||||||
|
### 👥 User Experience Metrics
|
||||||
|
|
||||||
|
| Metric | Target | Measurement |
|
||||||
|
|--------|--------|-------------|
|
||||||
|
| **⚡ Deployment Success** | 100% | Single-command deployment success |
|
||||||
|
| **🔍 Dashboard Accessibility** | 100% | Services accessible via Homepage |
|
||||||
|
| **🚫 Configuration Required** | None | Zero configuration for basic use |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📅 Implementation Timeline
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
gantt
|
||||||
|
title TSYS Developer Support Stack Implementation
|
||||||
|
dateFormat YYYY-MM-DD
|
||||||
|
section Phase 1: Core Infrastructure
|
||||||
|
DNS Management Service :active, p1-1, 2025-11-13, 3d
|
||||||
|
Container Management :p1-2, after p1-1, 2d
|
||||||
|
Service Discovery Validation :p1-3, after p1-2, 2d
|
||||||
|
|
||||||
|
section Phase 2: Monitoring Stack
|
||||||
|
Time Series Database :p2-1, after p1-3, 2d
|
||||||
|
Visualization Platform :p2-2, after p2-1, 3d
|
||||||
|
Dashboard Creation :p2-3, after p2-2, 2d
|
||||||
|
|
||||||
|
section Phase 3: Documentation Tools
|
||||||
|
Diagramming Server :p3-1, after p2-3, 2d
|
||||||
|
Diagram Service :p3-2, after p3-1, 2d
|
||||||
|
Integration Testing :p3-3, after p3-2, 2d
|
||||||
|
|
||||||
|
section Phase 4: Testing & Documentation
|
||||||
|
Comprehensive Test Suite :p4-1, after p3-3, 3d
|
||||||
|
Documentation Updates :p4-2, after p4-1, 2d
|
||||||
|
Final Validation :p4-3, after p4-2, 2d
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### 📅 Phase Details
|
||||||
|
|
||||||
|
| Phase | Duration | Focus | Deliverables |
|
||||||
|
|-------|----------|-------|--------------|
|
||||||
|
| **🏗️ Phase 1** | Week 1 | Core Infrastructure | DNS Management, Container Management, Service Discovery |
|
||||||
|
| **📊 Phase 2** | Week 1 | Monitoring Stack | Time Series Database, Visualization Platform, Dashboards |
|
||||||
|
| **📚 Phase 3** | Week 2 | Documentation Tools | Diagramming Server, Diagram Service, Integration |
|
||||||
|
| **🧪 Phase 4** | Week 2 | Testing & Documentation | Test Suite, Documentation, Validation |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Change Management
|
||||||
|
|
||||||
|
### 📝 Version Control Strategy
|
||||||
|
|
||||||
|
| Practice | Description | Standard |
|
||||||
|
|----------|-------------|----------|
|
||||||
|
| **📊 Comprehensive Tracking** | All changes tracked via Git | 100% change coverage |
|
||||||
|
| **📋 Structured Messages** | Conventional commit formatting | Commit message standards |
|
||||||
|
| **⚛️ Atomic Changes** | Small, focused commits | Single-purpose commits |
|
||||||
|
| **📝 Detailed Descriptions** | Clear change documentation | Comprehensive commit messages |
|
||||||
|
|
||||||
|
### 🔍 Quality Assurance Process
|
||||||
|
|
||||||
|
| Step | Description | Tool/Process |
|
||||||
|
|------|-------------|--------------|
|
||||||
|
| **🤖 Automated Validation** | Automated testing on all changes | Test suite execution |
|
||||||
|
| **✋ Manual Testing** | Manual validation for new services | User acceptance testing |
|
||||||
|
| **📚 Documentation Updates** | Synchronized documentation updates | Documentation review |
|
||||||
|
| **✅ Requirements Validation** | Continuous validation against PRD | Requirements traceability |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📞 Support & Maintenance
|
||||||
|
|
||||||
|
### 🔧 Troubleshooting Framework
|
||||||
|
|
||||||
|
| Component | Description | Implementation |
|
||||||
|
|-----------|-------------|----------------|
|
||||||
|
| **📋 Comprehensive Logging** | Service logging and diagnostics | Docker log integration |
|
||||||
|
| **📊 Real-time Monitoring** | Live health and status reporting | Health check endpoints |
|
||||||
|
| **📖 Documented Procedures** | Resolution procedures for common issues | Troubleshooting guides |
|
||||||
|
|
||||||
|
### 🔄 Maintenance Strategy
|
||||||
|
|
||||||
|
| Activity | Description | Frequency |
|
||||||
|
|----------|-------------|----------|
|
||||||
|
| **📦 Image Updates** | Regular service image updates | Weekly |
|
||||||
|
| **⚙️ Configuration Management** | Change tracking and validation | Continuous |
|
||||||
|
| **🔗 Compatibility Preservation** | Maintain backward compatibility | During updates |
|
||||||
|
| **📈 Continuous Improvement** | User feedback-based enhancements | Ongoing |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Appendix
|
||||||
|
|
||||||
|
### 📦 A. Service Categories
|
||||||
|
|
||||||
|
| Category | Purpose | Example Services |
|
||||||
|
|----------|---------|-----------------|
|
||||||
|
| **🏗️ Infrastructure Services** | Core platform and management tools | DNS Management, Container Socket Proxy, Container Management |
|
||||||
|
| **📊 Monitoring & Observability** | Data collection and visualization | Time Series Database, Visualization Platform |
|
||||||
|
| **📚 Documentation & Diagramming** | Knowledge management and creation | Diagramming Server, Diagrams as a Service |
|
||||||
|
| **🛠️ Developer Tools** | Productivity and workflow enhancement | Homepage, Time Tracking, Archiving, Habit Tracking |
|
||||||
|
|
||||||
|
### 🔗 B. Integration Requirements
|
||||||
|
|
||||||
|
| Requirement | Description | Implementation |
|
||||||
|
|-------------|-------------|----------------|
|
||||||
|
| **🏷️ Dashboard Discovery** | Centralized service visibility | Homepage integration |
|
||||||
|
| **🤝 Inter-service Communication** | Required service interactions | Network configuration |
|
||||||
|
| **🔐 Consistent Authentication** | Unified access patterns | Demo credential strategy |
|
||||||
|
| **❤️ Unified Monitoring** | Standardized health checking | Health check standards |
|
||||||
|
|
||||||
|
### ✅ C. Success Criteria
|
||||||
|
|
||||||
|
| Criteria | Description | Measurement |
|
||||||
|
|----------|-------------|-------------|
|
||||||
|
| **🔍 Service Discoverability** | All services accessible from central dashboard | 100% service visibility |
|
||||||
|
| **⚡ Rapid Demonstration** | Complete functionality demonstration within 2 minutes | Time-to-demo < 120 seconds |
|
||||||
|
| **🎯 Intuitive Experience** | Minimal training required for basic use | User satisfaction > 90% |
|
||||||
|
| **🔄 Cross-Platform Reliability** | Consistent operation across development environments | Platform compatibility > 95% |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📄 Document Information
|
||||||
|
|
||||||
|
**Document ID**: PRD-SUPPORT-DEMO-001
|
||||||
|
**Version**: 2.0
|
||||||
|
**Date**: 2026-05-01
|
||||||
|
**Author**: TSYS Development Team
|
||||||
|
**Status**: Final
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*This PRD serves as the source of truth for the TSYS Developer Support Stack demo implementation and will be used for audit and quality assurance purposes.*
|
||||||
|
|
||||||
|
</div>
|
||||||
416
demo/README.md
Normal file
416
demo/README.md
Normal file
@@ -0,0 +1,416 @@
|
|||||||
|
# 🚀 TSYS Developer Support Stack - Demo
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
[](https://opensource.org/licenses/MIT)
|
||||||
|
[](https://www.docker.com/)
|
||||||
|
[](https://www.fsf.org/)
|
||||||
|
[](#)
|
||||||
|
|
||||||
|
*A comprehensive, demo-ready developer support services stack that enhances productivity and quality of life for the TSYS engineering team.*
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📖 Table of Contents
|
||||||
|
|
||||||
|
- [🚀 Quick Start](#-quick-start)
|
||||||
|
- [📋 Services Overview](#-services-overview)
|
||||||
|
- [🔧 Technical Configuration](#-technical-configuration)
|
||||||
|
- [🔐 Demo Credentials](#-demo-credentials)
|
||||||
|
- [📊 Service Dependencies](#-service-dependencies)
|
||||||
|
- [🧪 Testing](#-testing)
|
||||||
|
- [🔍 Troubleshooting](#-troubleshooting)
|
||||||
|
- [📁 Data Management](#-data-management)
|
||||||
|
- [🔄 Updates & Maintenance](#-updates--maintenance)
|
||||||
|
- [📚 Documentation](#-documentation)
|
||||||
|
- [🚨 Security Notes](#-security-notes)
|
||||||
|
- [📞 Support](#-support)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Quick Start
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 🎯 Demo deployment with dynamic user detection
|
||||||
|
./scripts/demo-stack.sh deploy
|
||||||
|
|
||||||
|
# 🔧 Comprehensive testing and validation
|
||||||
|
./scripts/demo-test.sh full
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
🎉 **Access all services via the Homepage dashboard at** **[http://localhost:4000](http://localhost:4000)**
|
||||||
|
|
||||||
|
> ⚠️ **Demo Configuration Only** - This stack is designed for demonstration purposes with no data persistence.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Dynamic Deployment Architecture
|
||||||
|
|
||||||
|
### 📋 Environment Variables
|
||||||
|
|
||||||
|
All configuration is managed through `demo.env` and dynamic detection:
|
||||||
|
|
||||||
|
| Variable | Description | Default |
|
||||||
|
|-----------|-------------|----------|
|
||||||
|
| **COMPOSE_PROJECT_NAME** | Consistent naming prefix | `kneldevstack-supportstack-demo` |
|
||||||
|
| **UID** | Current user ID | Auto-detected |
|
||||||
|
| **GID** | Current group ID | Auto-detected |
|
||||||
|
| **DOCKER_GID** | Docker group ID | Auto-detected |
|
||||||
|
| **COMPOSE_NETWORK_NAME** | Docker network name | `kneldevstack-supportstack-demo-network` |
|
||||||
|
|
||||||
|
### 🎯 Deployment Scripts
|
||||||
|
|
||||||
|
| Script | Purpose | Usage |
|
||||||
|
|---------|---------|--------|
|
||||||
|
| **demo-stack.sh** | Dynamic deployment with user detection | `./scripts/demo-stack.sh [deploy|stop|restart]` |
|
||||||
|
| **demo-test.sh** | Comprehensive QA and validation | `./scripts/demo-test.sh [full|security|permissions]` |
|
||||||
|
| **demo.env** | All environment variables | Source of configuration |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Services Overview
|
||||||
|
|
||||||
|
### 🛠️ Developer Tools
|
||||||
|
| Service | Port | Description | 🌐 Access |
|
||||||
|
|---------|------|-------------|-----------|
|
||||||
|
| **Homepage** | 4000 | Central dashboard for service discovery | [Open](http://localhost:4000) |
|
||||||
|
| **Atomic Tracker** | 4012 | Habit tracking and personal dashboard | [Open](http://localhost:4012) |
|
||||||
|
| **Wakapi** | 4015 | Open-source WakaTime alternative for time tracking | [Open](http://localhost:4015) |
|
||||||
|
| **MailHog** | 4017 (Web), 4019 (SMTP) | Web and API based SMTP testing tool | [Open](http://localhost:4017) |
|
||||||
|
| **Atuin** | 4018 | Magical shell history synchronization | [Open](http://localhost:4018) |
|
||||||
|
|
||||||
|
### 📚 Archival & Content Management
|
||||||
|
| Service | Port | Description | 🌐 Access |
|
||||||
|
|---------|------|-------------|-----------|
|
||||||
|
| **ArchiveBox** | 4013 | Web archiving solution | [Open](http://localhost:4013) |
|
||||||
|
| **Tube Archivist** | 4014 | YouTube video archiving | [Open](http://localhost:4014) |
|
||||||
|
|
||||||
|
### 🏗️ Infrastructure Services
|
||||||
|
| Service | Port | Description | 🌐 Access |
|
||||||
|
|---------|------|-------------|-----------|
|
||||||
|
| **Pi-hole** | 4006 | DNS-based ad blocking and monitoring | [Open](http://localhost:4006) |
|
||||||
|
| **Dockhand** | 4007 | Modern Docker management UI | [Open](http://localhost:4007) |
|
||||||
|
|
||||||
|
### 📊 Monitoring & Observability
|
||||||
|
| Service | Port | Description | 🌐 Access |
|
||||||
|
|---------|------|-------------|-----------|
|
||||||
|
| **InfluxDB** | 4008 | Time series database for metrics | [Open](http://localhost:4008) |
|
||||||
|
| **Grafana** | 4009 | Analytics and visualization platform | [Open](http://localhost:4009) |
|
||||||
|
|
||||||
|
### 📚 Documentation & Diagramming
|
||||||
|
| Service | Port | Description | 🌐 Access |
|
||||||
|
|---------|------|-------------|-----------|
|
||||||
|
| **Draw.io** | 4010 | Web-based diagramming application | [Open](http://localhost:4010) |
|
||||||
|
| **Kroki** | 4011 | Diagrams as a service | [Open](http://localhost:4011) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Technical Configuration
|
||||||
|
|
||||||
|
### 🐳 Docker Integration
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Demo service template (docker-compose.yml.template)
|
||||||
|
services:
|
||||||
|
service-name:
|
||||||
|
image: official/image:tag
|
||||||
|
user: "${UID}:${GID}"
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-service-name"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
volumes:
|
||||||
|
- "${COMPOSE_PROJECT_NAME}_service_data:/path"
|
||||||
|
environment:
|
||||||
|
- PUID=${UID}
|
||||||
|
- PGID=${GID}
|
||||||
|
labels:
|
||||||
|
homepage.group: "Group Name"
|
||||||
|
homepage.name: "Display Name"
|
||||||
|
homepage.icon: "icon-name"
|
||||||
|
homepage.href: "http://localhost:${SERVICE_PORT}"
|
||||||
|
homepage.description: "Brief description"
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### ⚙️ Dynamic Configuration
|
||||||
|
|
||||||
|
| Setting | Variable | Description |
|
||||||
|
|---------|-----------|-------------|
|
||||||
|
| **Service Naming** | `${COMPOSE_PROJECT_NAME}-{service}` | Dynamic container naming |
|
||||||
|
| **Network** | `${COMPOSE_NETWORK_NAME}` | Dedicated Docker network |
|
||||||
|
| **User Mapping** | `${UID}:${GID}` | Dynamic user detection |
|
||||||
|
| **Docker Group** | `${DOCKER_GID}` | Docker socket access |
|
||||||
|
| **Volume Naming** | `${COMPOSE_PROJECT_NAME}_{service}_data` | Consistent volumes |
|
||||||
|
| **Restart Policy** | `unless-stopped` | Automatic recovery |
|
||||||
|
|
||||||
|
### 🔍 Health Check Endpoints
|
||||||
|
|
||||||
|
| Service | Health Check Path | Status |
|
||||||
|
|---------|-------------------|--------|
|
||||||
|
| **Pi-hole** (DNS Management) | `HTTP GET /` | ✅ Active |
|
||||||
|
| **Dockhand** (Container Management) | `HTTP GET /` | ✅ Active |
|
||||||
|
| **InfluxDB** (Time Series Database) | `HTTP GET /ping` | ✅ Active |
|
||||||
|
| **Grafana** (Visualization Platform) | `HTTP GET /api/health` | ✅ Active |
|
||||||
|
| **Draw.io** (Diagramming Server) | `HTTP GET /` | ✅ Active |
|
||||||
|
| **Kroki** (Diagrams as a Service) | `HTTP GET /health` | ✅ Active |
|
||||||
|
|
||||||
|
### 🏷️ Service Discovery Labels
|
||||||
|
|
||||||
|
All services include Homepage labels for auto-discovery:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
labels:
|
||||||
|
homepage.group: "Service category"
|
||||||
|
homepage.name: "Display name"
|
||||||
|
homepage.icon: "Appropriate icon"
|
||||||
|
homepage.href: "Full URL"
|
||||||
|
homepage.description: "Brief service description"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔐 Demo Credentials
|
||||||
|
|
||||||
|
> ⚠️ **Demo Configuration Only** - Reset all credentials before production use
|
||||||
|
|
||||||
|
| Service | Username | Password | 🔗 Access |
|
||||||
|
|---------|----------|----------|-----------|
|
||||||
|
| **Grafana** | `admin` | `demo_password` | [Login](http://localhost:4009) |
|
||||||
|
| **Dockhand** | `admin` | `demo_password` | [Login](http://localhost:4007) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Service Dependencies
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[Homepage Dashboard] --> B[All Services]
|
||||||
|
C[Container Management] --> D[Container Socket Proxy]
|
||||||
|
E[Visualization Platform] --> F[Time Series Database]
|
||||||
|
G[All Other Services] --> H[No Dependencies]
|
||||||
|
|
||||||
|
style A fill:#e1f5fe
|
||||||
|
style C fill:#f3e5f5
|
||||||
|
style E fill:#e8f5e8
|
||||||
|
style G fill:#fff3e0
|
||||||
|
```
|
||||||
|
|
||||||
|
| Service | Dependencies | Status |
|
||||||
|
|---------|--------------|--------|
|
||||||
|
| **Container Management** (Dockhand) | Docker socket (direct mount) | 🔗 Required |
|
||||||
|
| **Visualization Platform** (Grafana) | Time Series Database (InfluxDB) | 🔗 Required |
|
||||||
|
| **Video Archiving** (Tube Archivist) | Redis (ta-redis) + Elasticsearch (ta-elasticsearch) | 🔗 Required |
|
||||||
|
| **All Other Services** | None | ✅ Standalone |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Testing & Validation
|
||||||
|
|
||||||
|
### 🤖 Automated Demo Testing
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 🎯 Full deployment and validation
|
||||||
|
./scripts/demo-stack.sh deploy && ./scripts/demo-test.sh full
|
||||||
|
|
||||||
|
# 🔍 Security compliance validation
|
||||||
|
./scripts/demo-test.sh security
|
||||||
|
|
||||||
|
# 👤 File ownership validation
|
||||||
|
./scripts/demo-test.sh permissions
|
||||||
|
|
||||||
|
# 🌐 Network isolation validation
|
||||||
|
./scripts/demo-test.sh network
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### ✅ Manual Validation Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 📊 Check service status with dynamic naming
|
||||||
|
docker compose ps
|
||||||
|
|
||||||
|
# 📋 View service logs
|
||||||
|
docker compose logs {service-name}
|
||||||
|
|
||||||
|
# 🌐 Test individual endpoints with variables
|
||||||
|
curl -f http://localhost:4000/
|
||||||
|
curl -f http://localhost:4008/ping
|
||||||
|
curl -f http://localhost:4009/api/health
|
||||||
|
|
||||||
|
# 🔍 Validate user permissions
|
||||||
|
ls -la /var/lib/docker/volumes/kneldevstack-supportstack-demo_*/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Troubleshooting
|
||||||
|
|
||||||
|
### 🚨 Common Issues
|
||||||
|
|
||||||
|
#### Services not starting
|
||||||
|
```bash
|
||||||
|
# 🔧 Check Docker daemon
|
||||||
|
docker info
|
||||||
|
|
||||||
|
# 🌐 Check network
|
||||||
|
docker network ls | grep kneldevstack-supportstack-demo
|
||||||
|
|
||||||
|
# 🔄 Recreate network
|
||||||
|
docker network create --subnet 192.168.3.0/24 --gateway 192.168.3.1 kneldevstack-supportstack-demo-network
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Port conflicts
|
||||||
|
```bash
|
||||||
|
# 🔍 Check port usage
|
||||||
|
netstat -tulpn | grep :400
|
||||||
|
|
||||||
|
# 🗑️ Kill conflicting processes
|
||||||
|
sudo fuser -k {port}/tcp
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Health check failures
|
||||||
|
```bash
|
||||||
|
# 🔍 Check individual service health
|
||||||
|
docker compose exec {service} curl -f http://localhost:{internal-port}/health
|
||||||
|
|
||||||
|
# 🔄 Restart specific service
|
||||||
|
docker compose restart {service}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🛠️ Service-Specific Issues
|
||||||
|
|
||||||
|
| Issue | Service | Solution |
|
||||||
|
|-------|---------|----------|
|
||||||
|
| **DNS issues** | Pi-hole | Ensure Docker DNS settings allow custom DNS servers<br>Check that port 53 is available on the host |
|
||||||
|
| **Database connection** | Grafana-InfluxDB | Verify both services are on the same network<br>Check database connectivity: `curl http://localhost:4008/ping` |
|
||||||
|
| **Container access** | Dockhand | Ensure container socket is properly mounted<br>Check Container Socket Proxy service if used |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📁 Data Management
|
||||||
|
|
||||||
|
### 🎭 Demo Mode Configuration
|
||||||
|
|
||||||
|
> 💡 **No persistent data storage** - All data resets on container restart
|
||||||
|
|
||||||
|
| Feature | Configuration |
|
||||||
|
|---------|---------------|
|
||||||
|
| **Data Persistence** | ❌ Disabled (demo mode) |
|
||||||
|
| **Storage Type** | Docker volumes (temporary) |
|
||||||
|
| **Data Reset** | ✅ Automatic on restart |
|
||||||
|
| **Credentials** | 🔒 Hardcoded demo only |
|
||||||
|
|
||||||
|
### 🗂️ Volume Management
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 📋 List volumes
|
||||||
|
docker volume ls | grep kneldevstack
|
||||||
|
|
||||||
|
# 🗑️ Clean up all data
|
||||||
|
docker compose down -v
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Updates & Maintenance
|
||||||
|
|
||||||
|
### 📦 Image Updates
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 🔄 Pull latest images
|
||||||
|
docker compose pull
|
||||||
|
|
||||||
|
# 🚀 Recreate with new images
|
||||||
|
docker compose up -d --force-recreate
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### ⚙️ Configuration Changes
|
||||||
|
|
||||||
|
1. **Edit** `docker-compose.yml`
|
||||||
|
2. **Apply** changes: `docker compose up -d`
|
||||||
|
3. **Verify** with `docker compose ps`
|
||||||
|
4. **Test** functionality
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Documentation
|
||||||
|
|
||||||
|
| Document | Purpose | Link |
|
||||||
|
|----------|---------|------|
|
||||||
|
| **📋 Product Requirements** | Business requirements and specifications | [PRD.md](PRD.md) |
|
||||||
|
| **🤖 Development Guidelines** | Development principles and standards | [AGENTS.md](AGENTS.md) |
|
||||||
|
| **🌐 Service Documentation** | Individual service guides | Service web interfaces |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚨 Security Notes
|
||||||
|
|
||||||
|
> ⚠️ **Demo Configuration Only - Production Use Prohibited**
|
||||||
|
|
||||||
|
### 🔒 Demo Security Model
|
||||||
|
- 🔓 **Demo Credentials**: Hardcoded for demonstration only
|
||||||
|
- 🚫 **No Hardening**: No encryption or security features
|
||||||
|
- 🌐 **Network Isolation**: Do not expose to external networks
|
||||||
|
- 🔄 **Ephemeral Data**: All data resets on container restart
|
||||||
|
- 📡 **Docker Socket Proxy**: Mandatory for all container operations
|
||||||
|
|
||||||
|
### 🛡️ Security Requirements
|
||||||
|
- **Dynamic User Detection**: Prevents root file ownership issues
|
||||||
|
- **Docker Group Access**: Required for socket proxy functionality
|
||||||
|
- **Volume-First Storage**: Docker volumes preferred over bind mounts
|
||||||
|
- **Read-Only Host Access**: Minimal host filesystem interaction
|
||||||
|
- **Network Segregation**: Services isolated in demo network
|
||||||
|
|
||||||
|
### ⚠️ Production Migration Warning
|
||||||
|
- Reset all credentials before production deployment
|
||||||
|
- Implement persistent data storage
|
||||||
|
- Add encryption and security hardening
|
||||||
|
- Configure proper backup and recovery
|
||||||
|
- Set up monitoring and alerting
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📞 Support
|
||||||
|
|
||||||
|
### 🆘 Getting Help
|
||||||
|
|
||||||
|
1. **📖 Check** troubleshooting section above
|
||||||
|
2. **📋 Review** service logs: `docker compose logs`
|
||||||
|
3. **📚 Consult** individual service documentation
|
||||||
|
4. **🔍 Check** health status: `docker compose ps`
|
||||||
|
|
||||||
|
### 🐛 Issue Reporting
|
||||||
|
|
||||||
|
When reporting issues, please include:
|
||||||
|
- 📝 Full error messages
|
||||||
|
- 💻 System information
|
||||||
|
- 🔄 Reproduction steps
|
||||||
|
- ⚙️ Configuration snippets
|
||||||
|
- 🎭 Demo vs production context
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
**🎉 Happy Developing!**
|
||||||
|
|
||||||
|
*Last updated: 2025-11-13*
|
||||||
|
|
||||||
|
</div>
|
||||||
0
demo/config/archivebox/.gitkeep
Normal file
0
demo/config/archivebox/.gitkeep
Normal file
0
demo/config/atomictracker/.gitkeep
Normal file
0
demo/config/atomictracker/.gitkeep
Normal file
0
demo/config/atuin/.gitkeep
Normal file
0
demo/config/atuin/.gitkeep
Normal file
0
demo/config/drawio/.gitkeep
Normal file
0
demo/config/drawio/.gitkeep
Normal file
14
demo/config/grafana/dashboards.yml
Normal file
14
demo/config/grafana/dashboards.yml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
# TSYS Developer Support Stack - Grafana Dashboards Configuration
|
||||||
|
apiVersion: 1
|
||||||
|
|
||||||
|
providers:
|
||||||
|
- name: 'default'
|
||||||
|
orgId: 1
|
||||||
|
folder: ''
|
||||||
|
type: file
|
||||||
|
disableDeletion: false
|
||||||
|
updateIntervalSeconds: 10
|
||||||
|
allowUiUpdates: true
|
||||||
|
options:
|
||||||
|
path: /etc/grafana/provisioning/dashboards
|
||||||
229
demo/config/grafana/dashboards/docker-overview.json
Normal file
229
demo/config/grafana/dashboards/docker-overview.json
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
{
|
||||||
|
"annotations": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"builtIn": 1,
|
||||||
|
"datasource": "-- Grafana --",
|
||||||
|
"enable": true,
|
||||||
|
"hide": true,
|
||||||
|
"iconColor": "rgba(0, 211, 255, 1)",
|
||||||
|
"name": "Annotations & Alerts",
|
||||||
|
"type": "dashboard"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": "Docker container resource monitoring via InfluxDB",
|
||||||
|
"editable": true,
|
||||||
|
"fiscalYearStartMonth": 0,
|
||||||
|
"graphTooltip": 0,
|
||||||
|
"id": null,
|
||||||
|
"links": [],
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"datasource": "InfluxDB",
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisBorderShow": false,
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 10,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": {
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "auto",
|
||||||
|
"spanNulls": false,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "none"
|
||||||
|
},
|
||||||
|
"thresholdsStyle": {
|
||||||
|
"mode": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{ "color": "green", "value": null },
|
||||||
|
{ "color": "red", "value": 80 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "percent"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 },
|
||||||
|
"id": 1,
|
||||||
|
"options": {
|
||||||
|
"legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true },
|
||||||
|
"tooltip": { "mode": "single", "sort": "none" }
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": "InfluxDB",
|
||||||
|
"query": "from(bucket: \"demo_metrics\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"docker_container_cpu\")\n |> filter(fn: (r) => r._field == \"usage_percent\")",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Container CPU Usage",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": "InfluxDB",
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": { "mode": "palette-classic" },
|
||||||
|
"custom": {
|
||||||
|
"axisBorderShow": false,
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 10,
|
||||||
|
"gradientMode": "none",
|
||||||
|
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 5,
|
||||||
|
"scaleDistribution": { "type": "linear" },
|
||||||
|
"showPoints": "auto",
|
||||||
|
"spanNulls": false,
|
||||||
|
"stacking": { "group": "A", "mode": "none" },
|
||||||
|
"thresholdsStyle": { "mode": "off" }
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{ "color": "green", "value": null },
|
||||||
|
{ "color": "red", "value": 80 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "bytes"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 0 },
|
||||||
|
"id": 2,
|
||||||
|
"options": {
|
||||||
|
"legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true },
|
||||||
|
"tooltip": { "mode": "single", "sort": "none" }
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": "InfluxDB",
|
||||||
|
"query": "from(bucket: \"demo_metrics\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"docker_container_mem\")\n |> filter(fn: (r) => r._field == \"usage\")",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Container Memory Usage",
|
||||||
|
"type": "timeseries"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": "InfluxDB",
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": { "mode": "thresholds" },
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{ "color": "green", "value": null },
|
||||||
|
{ "color": "yellow", "value": 10 },
|
||||||
|
{ "color": "red", "value": 14 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": { "h": 4, "w": 6, "x": 0, "y": 8 },
|
||||||
|
"id": 3,
|
||||||
|
"options": {
|
||||||
|
"colorMode": "value",
|
||||||
|
"graphMode": "area",
|
||||||
|
"justifyMode": "auto",
|
||||||
|
"orientation": "auto",
|
||||||
|
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
|
||||||
|
"textMode": "auto"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": "InfluxDB",
|
||||||
|
"query": "from(bucket: \"demo_metrics\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"docker\")\n |> filter(fn: (r) => r._field == \"containers_running\")\n |> last()",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Running Containers",
|
||||||
|
"type": "stat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": "InfluxDB",
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": { "mode": "thresholds" },
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{ "color": "green", "value": null },
|
||||||
|
{ "color": "yellow", "value": 15 },
|
||||||
|
{ "color": "red", "value": 20 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": { "h": 4, "w": 6, "x": 6, "y": 8 },
|
||||||
|
"id": 4,
|
||||||
|
"options": {
|
||||||
|
"colorMode": "value",
|
||||||
|
"graphMode": "area",
|
||||||
|
"justifyMode": "auto",
|
||||||
|
"orientation": "auto",
|
||||||
|
"reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false },
|
||||||
|
"textMode": "auto"
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": "InfluxDB",
|
||||||
|
"query": "from(bucket: \"demo_metrics\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r._measurement == \"docker\")\n |> filter(fn: (r) => r._field == \"images\")\n |> last()",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Docker Images",
|
||||||
|
"type": "stat"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"refresh": "30s",
|
||||||
|
"schemaVersion": 38,
|
||||||
|
"style": "dark",
|
||||||
|
"tags": ["docker", "infrastructure"],
|
||||||
|
"templating": { "list": [] },
|
||||||
|
"time": { "from": "now-1h", "to": "now" },
|
||||||
|
"timepicker": {},
|
||||||
|
"timezone": "utc",
|
||||||
|
"title": "Docker Infrastructure Overview",
|
||||||
|
"uid": "docker-overview",
|
||||||
|
"version": 1
|
||||||
|
}
|
||||||
20
demo/config/grafana/datasources.yml
Normal file
20
demo/config/grafana/datasources.yml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
# TSYS Developer Support Stack - Grafana Datasources Configuration
|
||||||
|
apiVersion: 1
|
||||||
|
|
||||||
|
datasources:
|
||||||
|
- name: InfluxDB
|
||||||
|
type: influxdb
|
||||||
|
access: proxy
|
||||||
|
url: http://influxdb:8086
|
||||||
|
database: demo_metrics
|
||||||
|
user: admin
|
||||||
|
password: demo_password
|
||||||
|
isDefault: true
|
||||||
|
jsonData:
|
||||||
|
version: Flux
|
||||||
|
organization: tsysdemo
|
||||||
|
defaultBucket: demo_metrics
|
||||||
|
tlsSkipVerify: true
|
||||||
|
secureJsonData:
|
||||||
|
token: demo_token_replace_in_production
|
||||||
24
demo/config/homepage/bookmarks.yaml
Normal file
24
demo/config/homepage/bookmarks.yaml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
# Homepage Bookmarks
|
||||||
|
|
||||||
|
- Developer Resources:
|
||||||
|
- GitHub:
|
||||||
|
- abbr: GH
|
||||||
|
href: https://github.com
|
||||||
|
- Stack Overflow:
|
||||||
|
- abbr: SO
|
||||||
|
href: https://stackoverflow.com
|
||||||
|
- Docker Hub:
|
||||||
|
- abbr: DH
|
||||||
|
href: https://hub.docker.com
|
||||||
|
|
||||||
|
- Documentation:
|
||||||
|
- Docker Docs:
|
||||||
|
- abbr: DD
|
||||||
|
href: https://docs.docker.com
|
||||||
|
- Grafana Docs:
|
||||||
|
- abbr: GF
|
||||||
|
href: https://grafana.com/docs
|
||||||
|
- InfluxDB Docs:
|
||||||
|
- abbr: IF
|
||||||
|
href: https://docs.influxdata.com
|
||||||
6
demo/config/homepage/docker.yaml
Normal file
6
demo/config/homepage/docker.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
# TSYS Developer Support Stack - Homepage Docker Integration
|
||||||
|
# Connects Homepage to Docker for automatic service discovery
|
||||||
|
|
||||||
|
my-docker:
|
||||||
|
socket: docker-socket-proxy:2375
|
||||||
77
demo/config/homepage/services.yaml
Normal file
77
demo/config/homepage/services.yaml
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
---
|
||||||
|
# Homepage Services Configuration
|
||||||
|
# Services are auto-discovered via Docker labels, but this provides
|
||||||
|
# the manual layout and widget configuration.
|
||||||
|
|
||||||
|
- Infrastructure:
|
||||||
|
- Pi-hole:
|
||||||
|
href: http://localhost:4006/admin
|
||||||
|
description: DNS management with ad blocking
|
||||||
|
icon: pihole.png
|
||||||
|
widget:
|
||||||
|
type: pihole
|
||||||
|
url: http://localhost:4006
|
||||||
|
password: demo_password
|
||||||
|
|
||||||
|
- Dockhand:
|
||||||
|
href: http://localhost:4007
|
||||||
|
description: Modern Docker management UI
|
||||||
|
icon: dockhand.png
|
||||||
|
|
||||||
|
- Monitoring:
|
||||||
|
- InfluxDB:
|
||||||
|
href: http://localhost:4008
|
||||||
|
description: Time series database for metrics
|
||||||
|
icon: influxdb.png
|
||||||
|
|
||||||
|
- Grafana:
|
||||||
|
href: http://localhost:4009
|
||||||
|
description: Analytics and visualization platform
|
||||||
|
icon: grafana.png
|
||||||
|
widget:
|
||||||
|
type: grafana
|
||||||
|
url: http://localhost:4009
|
||||||
|
username: admin
|
||||||
|
password: demo_password
|
||||||
|
|
||||||
|
- Documentation:
|
||||||
|
- Draw.io:
|
||||||
|
href: http://localhost:4010
|
||||||
|
description: Web-based diagramming application
|
||||||
|
icon: drawio.png
|
||||||
|
|
||||||
|
- Kroki:
|
||||||
|
href: http://localhost:4011
|
||||||
|
description: Diagrams as a service
|
||||||
|
icon: kroki.png
|
||||||
|
|
||||||
|
- Developer Tools:
|
||||||
|
- Atomic Tracker:
|
||||||
|
href: http://localhost:4012
|
||||||
|
description: Habit tracking and personal dashboard
|
||||||
|
icon: atomic-tracker.png
|
||||||
|
|
||||||
|
- ArchiveBox:
|
||||||
|
href: http://localhost:4013
|
||||||
|
description: Web archiving solution
|
||||||
|
icon: archivebox.png
|
||||||
|
|
||||||
|
- Tube Archivist:
|
||||||
|
href: http://localhost:4014
|
||||||
|
description: YouTube video archiving
|
||||||
|
icon: tube-archivist.png
|
||||||
|
|
||||||
|
- Wakapi:
|
||||||
|
href: http://localhost:4015
|
||||||
|
description: Open-source WakaTime alternative
|
||||||
|
icon: wakapi.png
|
||||||
|
|
||||||
|
- MailHog:
|
||||||
|
href: http://localhost:4017
|
||||||
|
description: Web and API based SMTP testing
|
||||||
|
icon: mailhog.png
|
||||||
|
|
||||||
|
- Atuin:
|
||||||
|
href: http://localhost:4018
|
||||||
|
description: Magical shell history synchronization
|
||||||
|
icon: atuin.png
|
||||||
33
demo/config/homepage/settings.yaml
Normal file
33
demo/config/homepage/settings.yaml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
# Homepage Settings
|
||||||
|
|
||||||
|
title: TSYS Developer Support Stack
|
||||||
|
favicon: https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/png/docker.png
|
||||||
|
|
||||||
|
headerStyle: boxed
|
||||||
|
|
||||||
|
layout:
|
||||||
|
Infrastructure:
|
||||||
|
style: row
|
||||||
|
columns: 2
|
||||||
|
Monitoring:
|
||||||
|
style: row
|
||||||
|
columns: 2
|
||||||
|
Documentation:
|
||||||
|
style: row
|
||||||
|
columns: 2
|
||||||
|
Developer Tools:
|
||||||
|
style: row
|
||||||
|
columns: 3
|
||||||
|
|
||||||
|
providers:
|
||||||
|
docker:
|
||||||
|
socket: docker-socket-proxy:2375
|
||||||
|
|
||||||
|
quicklaunch:
|
||||||
|
searchDescriptions: true
|
||||||
|
hideInternetSearch: false
|
||||||
|
hideVisitURL: false
|
||||||
|
|
||||||
|
showStats: true
|
||||||
|
hideVersion: false
|
||||||
21
demo/config/homepage/widgets.yaml
Normal file
21
demo/config/homepage/widgets.yaml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
# Homepage Widgets Configuration
|
||||||
|
|
||||||
|
- greeting:
|
||||||
|
text_size: xl
|
||||||
|
text: TSYS Developer Support Stack
|
||||||
|
|
||||||
|
- datetime:
|
||||||
|
text_size: l
|
||||||
|
format:
|
||||||
|
dateStyle: long
|
||||||
|
timeStyle: short
|
||||||
|
|
||||||
|
- search:
|
||||||
|
provider: duckduckgo
|
||||||
|
target: _blank
|
||||||
|
|
||||||
|
- glances:
|
||||||
|
url: http://localhost:4006
|
||||||
|
type: pihole
|
||||||
|
password: demo_password
|
||||||
0
demo/config/influxdb/.gitkeep
Normal file
0
demo/config/influxdb/.gitkeep
Normal file
0
demo/config/kroki/.gitkeep
Normal file
0
demo/config/kroki/.gitkeep
Normal file
0
demo/config/mailhog/.gitkeep
Normal file
0
demo/config/mailhog/.gitkeep
Normal file
0
demo/config/pihole/.gitkeep
Normal file
0
demo/config/pihole/.gitkeep
Normal file
0
demo/config/tubearchivist/.gitkeep
Normal file
0
demo/config/tubearchivist/.gitkeep
Normal file
0
demo/config/wakapi/.gitkeep
Normal file
0
demo/config/wakapi/.gitkeep
Normal file
86
demo/demo.env.template
Normal file
86
demo/demo.env.template
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
# TSYS Developer Support Stack - Demo Environment Configuration
|
||||||
|
# FOR DEMONSTRATION PURPOSES ONLY - NOT FOR PRODUCTION
|
||||||
|
|
||||||
|
# Project Identification
|
||||||
|
COMPOSE_PROJECT_NAME=kneldevstack-supportstack-demo
|
||||||
|
COMPOSE_NETWORK_NAME=kneldevstack-supportstack-demo-network
|
||||||
|
|
||||||
|
# Dynamic User Detection (auto-populated by demo-stack.sh)
|
||||||
|
DEMO_UID=1000
|
||||||
|
DEMO_GID=1000
|
||||||
|
DEMO_DOCKER_GID=986
|
||||||
|
|
||||||
|
# Port Assignments (4000-4099 range)
|
||||||
|
HOMEPAGE_PORT=4000
|
||||||
|
HOMEPAGE_ALLOWED_HOSTS=*
|
||||||
|
DOCKER_SOCKET_PROXY_PORT=4005
|
||||||
|
PIHOLE_PORT=4006
|
||||||
|
DOCKHAND_PORT=4007
|
||||||
|
INFLUXDB_PORT=4008
|
||||||
|
GRAFANA_PORT=4009
|
||||||
|
DRAWIO_PORT=4010
|
||||||
|
KROKI_PORT=4011
|
||||||
|
ATOMIC_TRACKER_PORT=4012
|
||||||
|
ARCHIVEBOX_PORT=4013
|
||||||
|
TUBE_ARCHIVIST_PORT=4014
|
||||||
|
WAKAPI_PORT=4015
|
||||||
|
MAILHOG_PORT=4017
|
||||||
|
MAILHOG_SMTP_PORT=4019
|
||||||
|
ATUIN_PORT=4018
|
||||||
|
|
||||||
|
# Network Configuration
|
||||||
|
NETWORK_SUBNET=192.168.3.0/24
|
||||||
|
NETWORK_GATEWAY=192.168.3.1
|
||||||
|
|
||||||
|
# Health Check Timeouts
|
||||||
|
HEALTH_CHECK_TIMEOUT=10s
|
||||||
|
HEALTH_CHECK_INTERVAL=30s
|
||||||
|
HEALTH_CHECK_RETRIES=3
|
||||||
|
|
||||||
|
# Docker Socket Proxy Configuration
|
||||||
|
DOCKER_SOCKET_PROXY_CONTAINERS=1
|
||||||
|
DOCKER_SOCKET_PROXY_IMAGES=1
|
||||||
|
DOCKER_SOCKET_PROXY_NETWORKS=1
|
||||||
|
DOCKER_SOCKET_PROXY_VOLUMES=1
|
||||||
|
DOCKER_SOCKET_PROXY_EXEC=0
|
||||||
|
DOCKER_SOCKET_PROXY_PRIVILEGED=0
|
||||||
|
DOCKER_SOCKET_PROXY_SERVICES=0
|
||||||
|
DOCKER_SOCKET_PROXY_TASKS=0
|
||||||
|
DOCKER_SOCKET_PROXY_SECRETS=0
|
||||||
|
DOCKER_SOCKET_PROXY_CONFIGS=0
|
||||||
|
DOCKER_SOCKET_PROXY_PLUGINS=0
|
||||||
|
|
||||||
|
# InfluxDB Configuration
|
||||||
|
INFLUXDB_ORG=tsysdemo
|
||||||
|
INFLUXDB_BUCKET=demo_metrics
|
||||||
|
INFLUXDB_ADMIN_USER=admin
|
||||||
|
INFLUXDB_ADMIN_PASSWORD=demo_password
|
||||||
|
INFLUXDB_AUTH_TOKEN=demo_token_replace_in_production
|
||||||
|
|
||||||
|
# Grafana Configuration
|
||||||
|
GF_SECURITY_ADMIN_USER=admin
|
||||||
|
GF_SECURITY_ADMIN_PASSWORD=demo_password
|
||||||
|
GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource
|
||||||
|
|
||||||
|
# Pi-hole Configuration
|
||||||
|
PIHOLE_WEBPASSWORD=demo_password
|
||||||
|
WEBTHEME=default-darker
|
||||||
|
|
||||||
|
# ArchiveBox Configuration
|
||||||
|
ARCHIVEBOX_SECRET_KEY=demo_secret_replace_in_production
|
||||||
|
ARCHIVEBOX_ADMIN_USER=admin
|
||||||
|
ARCHIVEBOX_ADMIN_PASSWORD=demo_password
|
||||||
|
|
||||||
|
# Tube Archivist Configuration
|
||||||
|
TA_HOST=http://tubearchivist:8000
|
||||||
|
TA_USERNAME=admin
|
||||||
|
TA_PASSWORD=demo_password
|
||||||
|
ELASTIC_PASSWORD=demo_password
|
||||||
|
ES_JAVA_OPTS="-Xms512m -Xmx512m"
|
||||||
|
|
||||||
|
# Wakapi Configuration
|
||||||
|
WAKAPI_PASSWORD_SALT=demo_salt_replace_in_production
|
||||||
|
|
||||||
|
# Atuin Configuration
|
||||||
|
ATUIN_HOST=0.0.0.0
|
||||||
|
ATUIN_OPEN_REGISTRATION=true
|
||||||
587
demo/docker-compose.yml.template
Normal file
587
demo/docker-compose.yml.template
Normal file
@@ -0,0 +1,587 @@
|
|||||||
|
---
|
||||||
|
# TSYS Developer Support Stack - Docker Compose Template
|
||||||
|
# Version: 2.0
|
||||||
|
# Purpose: Demo deployment with dynamic configuration
|
||||||
|
# DEMO CONFIGURATION ONLY - NOT FOR PRODUCTION
|
||||||
|
|
||||||
|
networks:
|
||||||
|
${COMPOSE_NETWORK_NAME}:
|
||||||
|
driver: bridge
|
||||||
|
ipam:
|
||||||
|
config:
|
||||||
|
- subnet: ${NETWORK_SUBNET}
|
||||||
|
gateway: ${NETWORK_GATEWAY}
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
${COMPOSE_PROJECT_NAME}_homepage_data:
|
||||||
|
driver: local
|
||||||
|
${COMPOSE_PROJECT_NAME}_pihole_data:
|
||||||
|
driver: local
|
||||||
|
${COMPOSE_PROJECT_NAME}_dockhand_data:
|
||||||
|
driver: local
|
||||||
|
${COMPOSE_PROJECT_NAME}_influxdb_data:
|
||||||
|
driver: local
|
||||||
|
${COMPOSE_PROJECT_NAME}_grafana_data:
|
||||||
|
driver: local
|
||||||
|
${COMPOSE_PROJECT_NAME}_drawio_data:
|
||||||
|
driver: local
|
||||||
|
${COMPOSE_PROJECT_NAME}_kroki_data:
|
||||||
|
driver: local
|
||||||
|
${COMPOSE_PROJECT_NAME}_atomictracker_data:
|
||||||
|
driver: local
|
||||||
|
${COMPOSE_PROJECT_NAME}_archivebox_data:
|
||||||
|
driver: local
|
||||||
|
${COMPOSE_PROJECT_NAME}_tubearchivist_data:
|
||||||
|
driver: local
|
||||||
|
${COMPOSE_PROJECT_NAME}_ta_redis_data:
|
||||||
|
driver: local
|
||||||
|
${COMPOSE_PROJECT_NAME}_ta_es_data:
|
||||||
|
driver: local
|
||||||
|
${COMPOSE_PROJECT_NAME}_wakapi_data:
|
||||||
|
driver: local
|
||||||
|
${COMPOSE_PROJECT_NAME}_mailhog_data:
|
||||||
|
driver: local
|
||||||
|
${COMPOSE_PROJECT_NAME}_atuin_data:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
services:
|
||||||
|
# Docker Socket Proxy - Security Layer
|
||||||
|
docker-socket-proxy:
|
||||||
|
image: tecnativa/docker-socket-proxy:latest
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-docker-socket-proxy"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
environment:
|
||||||
|
- CONTAINERS=${DOCKER_SOCKET_PROXY_CONTAINERS}
|
||||||
|
- IMAGES=${DOCKER_SOCKET_PROXY_IMAGES}
|
||||||
|
- NETWORKS=${DOCKER_SOCKET_PROXY_NETWORKS}
|
||||||
|
- VOLUMES=${DOCKER_SOCKET_PROXY_VOLUMES}
|
||||||
|
- EXEC=${DOCKER_SOCKET_PROXY_EXEC}
|
||||||
|
- PRIVILEGED=${DOCKER_SOCKET_PROXY_PRIVILEGED}
|
||||||
|
- SERVICES=${DOCKER_SOCKET_PROXY_SERVICES}
|
||||||
|
- TASKS=${DOCKER_SOCKET_PROXY_TASKS}
|
||||||
|
- SECRETS=${DOCKER_SOCKET_PROXY_SECRETS}
|
||||||
|
- CONFIGS=${DOCKER_SOCKET_PROXY_CONFIGS}
|
||||||
|
- PLUGINS=${DOCKER_SOCKET_PROXY_PLUGINS}
|
||||||
|
- POST=1
|
||||||
|
- DELETE=1
|
||||||
|
- ALLOW_START=1
|
||||||
|
- ALLOW_STOP=1
|
||||||
|
- ALLOW_RESTARTS=1
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 128M
|
||||||
|
labels:
|
||||||
|
homepage.group: "Infrastructure"
|
||||||
|
homepage.name: "Docker Socket Proxy"
|
||||||
|
homepage.icon: "docker"
|
||||||
|
homepage.description: >-
|
||||||
|
Secure proxy for Docker socket access (internal only)
|
||||||
|
|
||||||
|
# Homepage - Central Dashboard
|
||||||
|
homepage:
|
||||||
|
image: ghcr.io/gethomepage/homepage:latest
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-homepage"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
ports:
|
||||||
|
- "${HOMEPAGE_PORT}:3000"
|
||||||
|
volumes:
|
||||||
|
- ./config/homepage:/app/config
|
||||||
|
environment:
|
||||||
|
- HOMEPAGE_ALLOWED_HOSTS=${HOMEPAGE_ALLOWED_HOSTS}
|
||||||
|
- PUID=${DEMO_UID}
|
||||||
|
- PGID=${DEMO_GID}
|
||||||
|
labels:
|
||||||
|
homepage.group: "Developer Tools"
|
||||||
|
homepage.name: "Homepage"
|
||||||
|
homepage.icon: "homepage"
|
||||||
|
homepage.href: "http://localhost:${HOMEPAGE_PORT}"
|
||||||
|
homepage.description: "Central dashboard for service discovery"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256M
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider",
|
||||||
|
"http://localhost:3000"]
|
||||||
|
interval: ${HEALTH_CHECK_INTERVAL}
|
||||||
|
timeout: ${HEALTH_CHECK_TIMEOUT}
|
||||||
|
retries: ${HEALTH_CHECK_RETRIES}
|
||||||
|
|
||||||
|
# Pi-hole - DNS Management
|
||||||
|
pihole:
|
||||||
|
image: pihole/pihole:latest
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-pihole"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
ports:
|
||||||
|
- "${PIHOLE_PORT}:80"
|
||||||
|
volumes:
|
||||||
|
- ${COMPOSE_PROJECT_NAME}_pihole_data:/etc/pihole
|
||||||
|
environment:
|
||||||
|
- TZ=UTC
|
||||||
|
- WEBPASSWORD=${PIHOLE_WEBPASSWORD}
|
||||||
|
- WEBTHEME=${WEBTHEME}
|
||||||
|
- PUID=${DEMO_UID}
|
||||||
|
- PGID=${DEMO_GID}
|
||||||
|
labels:
|
||||||
|
homepage.group: "Infrastructure"
|
||||||
|
homepage.name: "Pi-hole"
|
||||||
|
homepage.icon: "pihole"
|
||||||
|
homepage.href: "http://localhost:${PIHOLE_PORT}"
|
||||||
|
homepage.description: "DNS management with ad blocking"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256M
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider",
|
||||||
|
"http://localhost/admin"]
|
||||||
|
interval: ${HEALTH_CHECK_INTERVAL}
|
||||||
|
timeout: ${HEALTH_CHECK_TIMEOUT}
|
||||||
|
retries: ${HEALTH_CHECK_RETRIES}
|
||||||
|
|
||||||
|
# Dockhand - Docker Management
|
||||||
|
dockhand:
|
||||||
|
image: fnsys/dockhand:latest
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-dockhand"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
ports:
|
||||||
|
- "${DOCKHAND_PORT}:3000"
|
||||||
|
volumes:
|
||||||
|
- ${COMPOSE_PROJECT_NAME}_dockhand_data:/app/data
|
||||||
|
environment:
|
||||||
|
- DOCKER_HOST=tcp://docker-socket-proxy:2375
|
||||||
|
- PUID=${DEMO_UID}
|
||||||
|
- PGID=${DEMO_GID}
|
||||||
|
depends_on:
|
||||||
|
docker-socket-proxy:
|
||||||
|
condition: service_started
|
||||||
|
labels:
|
||||||
|
homepage.group: "Infrastructure"
|
||||||
|
homepage.name: "Dockhand"
|
||||||
|
homepage.icon: "dockhand"
|
||||||
|
homepage.href: "http://localhost:${DOCKHAND_PORT}"
|
||||||
|
homepage.description: "Modern Docker management UI"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256M
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "--silent",
|
||||||
|
"http://localhost:3000"]
|
||||||
|
interval: ${HEALTH_CHECK_INTERVAL}
|
||||||
|
timeout: ${HEALTH_CHECK_TIMEOUT}
|
||||||
|
retries: ${HEALTH_CHECK_RETRIES}
|
||||||
|
|
||||||
|
# InfluxDB - Time Series Database
|
||||||
|
influxdb:
|
||||||
|
image: influxdb:2.7-alpine
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-influxdb"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
ports:
|
||||||
|
- "${INFLUXDB_PORT}:8086"
|
||||||
|
volumes:
|
||||||
|
- ${COMPOSE_PROJECT_NAME}_influxdb_data:/var/lib/influxdb2
|
||||||
|
environment:
|
||||||
|
- DOCKER_INFLUXDB_INIT_MODE=setup
|
||||||
|
- DOCKER_INFLUXDB_INIT_USERNAME=${INFLUXDB_ADMIN_USER}
|
||||||
|
- DOCKER_INFLUXDB_INIT_PASSWORD=${INFLUXDB_ADMIN_PASSWORD}
|
||||||
|
- DOCKER_INFLUXDB_INIT_ORG=${INFLUXDB_ORG}
|
||||||
|
- DOCKER_INFLUXDB_INIT_BUCKET=${INFLUXDB_BUCKET}
|
||||||
|
- DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=${INFLUXDB_AUTH_TOKEN}
|
||||||
|
- PUID=${DEMO_UID}
|
||||||
|
- PGID=${DEMO_GID}
|
||||||
|
labels:
|
||||||
|
homepage.group: "Monitoring"
|
||||||
|
homepage.name: "InfluxDB"
|
||||||
|
homepage.icon: "influxdb"
|
||||||
|
homepage.href: "http://localhost:${INFLUXDB_PORT}"
|
||||||
|
homepage.description: "Time series database for metrics"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider",
|
||||||
|
"http://localhost:8086/ping"]
|
||||||
|
interval: ${HEALTH_CHECK_INTERVAL}
|
||||||
|
timeout: ${HEALTH_CHECK_TIMEOUT}
|
||||||
|
retries: ${HEALTH_CHECK_RETRIES}
|
||||||
|
|
||||||
|
# Grafana - Visualization Platform
|
||||||
|
grafana:
|
||||||
|
image: grafana/grafana:latest
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-grafana"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
ports:
|
||||||
|
- "${GRAFANA_PORT}:3000"
|
||||||
|
volumes:
|
||||||
|
- ${COMPOSE_PROJECT_NAME}_grafana_data:/var/lib/grafana
|
||||||
|
- ./config/grafana:/etc/grafana/provisioning:ro
|
||||||
|
environment:
|
||||||
|
- GF_SECURITY_ADMIN_USER=${GF_SECURITY_ADMIN_USER}
|
||||||
|
- GF_SECURITY_ADMIN_PASSWORD=${GF_SECURITY_ADMIN_PASSWORD}
|
||||||
|
- GF_INSTALL_PLUGINS=${GF_INSTALL_PLUGINS}
|
||||||
|
- GF_SERVER_HTTP_PORT=3000
|
||||||
|
- PUID=${DEMO_UID}
|
||||||
|
- PGID=${DEMO_GID}
|
||||||
|
labels:
|
||||||
|
homepage.group: "Monitoring"
|
||||||
|
homepage.name: "Grafana"
|
||||||
|
homepage.icon: "grafana"
|
||||||
|
homepage.href: "http://localhost:${GRAFANA_PORT}"
|
||||||
|
homepage.description: "Analytics and visualization platform"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256M
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider",
|
||||||
|
"http://localhost:3000/api/health"]
|
||||||
|
interval: ${HEALTH_CHECK_INTERVAL}
|
||||||
|
timeout: ${HEALTH_CHECK_TIMEOUT}
|
||||||
|
retries: ${HEALTH_CHECK_RETRIES}
|
||||||
|
|
||||||
|
# Draw.io - Diagramming Server
|
||||||
|
drawio:
|
||||||
|
image: fjudith/draw.io:latest
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-drawio"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
ports:
|
||||||
|
- "${DRAWIO_PORT}:8080"
|
||||||
|
volumes:
|
||||||
|
- ${COMPOSE_PROJECT_NAME}_drawio_data:/root
|
||||||
|
environment:
|
||||||
|
- PUID=${DEMO_UID}
|
||||||
|
- PGID=${DEMO_GID}
|
||||||
|
labels:
|
||||||
|
homepage.group: "Documentation"
|
||||||
|
homepage.name: "Draw.io"
|
||||||
|
homepage.icon: "drawio"
|
||||||
|
homepage.href: "http://localhost:${DRAWIO_PORT}"
|
||||||
|
homepage.description: "Web-based diagramming application"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256M
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "--silent",
|
||||||
|
"http://localhost:8080"]
|
||||||
|
interval: ${HEALTH_CHECK_INTERVAL}
|
||||||
|
timeout: ${HEALTH_CHECK_TIMEOUT}
|
||||||
|
retries: ${HEALTH_CHECK_RETRIES}
|
||||||
|
|
||||||
|
# Kroki - Diagrams as a Service
|
||||||
|
kroki:
|
||||||
|
image: yuzutech/kroki:latest
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-kroki"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
ports:
|
||||||
|
- "${KROKI_PORT}:8000"
|
||||||
|
volumes:
|
||||||
|
- ${COMPOSE_PROJECT_NAME}_kroki_data:/data
|
||||||
|
environment:
|
||||||
|
- KROKI_SAFE_MODE=secure
|
||||||
|
- PUID=${DEMO_UID}
|
||||||
|
- PGID=${DEMO_GID}
|
||||||
|
labels:
|
||||||
|
homepage.group: "Documentation"
|
||||||
|
homepage.name: "Kroki"
|
||||||
|
homepage.icon: "kroki"
|
||||||
|
homepage.href: "http://localhost:${KROKI_PORT}"
|
||||||
|
homepage.description: "Diagrams as a service"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256M
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "--silent",
|
||||||
|
"http://localhost:8000/health"]
|
||||||
|
interval: ${HEALTH_CHECK_INTERVAL}
|
||||||
|
timeout: ${HEALTH_CHECK_TIMEOUT}
|
||||||
|
retries: ${HEALTH_CHECK_RETRIES}
|
||||||
|
|
||||||
|
# Atomic Tracker - Habit Tracking
|
||||||
|
atomictracker:
|
||||||
|
image: ghcr.io/majorpeter/atomic-tracker:v1.3.1
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-atomictracker"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
ports:
|
||||||
|
- "${ATOMIC_TRACKER_PORT}:8080"
|
||||||
|
volumes:
|
||||||
|
- ${COMPOSE_PROJECT_NAME}_atomictracker_data:/app/data
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- PUID=${DEMO_UID}
|
||||||
|
- PGID=${DEMO_GID}
|
||||||
|
labels:
|
||||||
|
homepage.group: "Developer Tools"
|
||||||
|
homepage.name: "Atomic Tracker"
|
||||||
|
homepage.icon: "atomic-tracker"
|
||||||
|
homepage.href: "http://localhost:${ATOMIC_TRACKER_PORT}"
|
||||||
|
homepage.description: "Habit tracking and personal dashboard"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256M
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider",
|
||||||
|
"http://localhost:8080"]
|
||||||
|
interval: ${HEALTH_CHECK_INTERVAL}
|
||||||
|
timeout: ${HEALTH_CHECK_TIMEOUT}
|
||||||
|
retries: ${HEALTH_CHECK_RETRIES}
|
||||||
|
|
||||||
|
# ArchiveBox - Web Archiving
|
||||||
|
archivebox:
|
||||||
|
image: archivebox/archivebox:latest
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-archivebox"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
ports:
|
||||||
|
- "${ARCHIVEBOX_PORT}:8000"
|
||||||
|
volumes:
|
||||||
|
- ${COMPOSE_PROJECT_NAME}_archivebox_data:/data
|
||||||
|
environment:
|
||||||
|
- ADMIN_USERNAME=${ARCHIVEBOX_ADMIN_USER}
|
||||||
|
- ADMIN_PASSWORD=${ARCHIVEBOX_ADMIN_PASSWORD}
|
||||||
|
- ALLOWED_HOSTS=*
|
||||||
|
- CSRF_TRUSTED_ORIGINS=http://localhost:${ARCHIVEBOX_PORT}
|
||||||
|
- PUBLIC_INDEX=True
|
||||||
|
- PUBLIC_SNAPSHOTS=True
|
||||||
|
- PUBLIC_ADD_VIEW=False
|
||||||
|
- PUID=${DEMO_UID}
|
||||||
|
- PGID=${DEMO_GID}
|
||||||
|
labels:
|
||||||
|
homepage.group: "Developer Tools"
|
||||||
|
homepage.name: "ArchiveBox"
|
||||||
|
homepage.icon: "archivebox"
|
||||||
|
homepage.href: "http://localhost:${ARCHIVEBOX_PORT}"
|
||||||
|
homepage.description: "Web archiving solution"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-fsS",
|
||||||
|
"http://localhost:8000/health/"]
|
||||||
|
interval: ${HEALTH_CHECK_INTERVAL}
|
||||||
|
timeout: ${HEALTH_CHECK_TIMEOUT}
|
||||||
|
retries: 5
|
||||||
|
start_period: 60s
|
||||||
|
|
||||||
|
# Tube Archivist - Redis
|
||||||
|
ta-redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-ta-redis"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
volumes:
|
||||||
|
- ${COMPOSE_PROJECT_NAME}_ta_redis_data:/data
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256M
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: ${HEALTH_CHECK_INTERVAL}
|
||||||
|
timeout: ${HEALTH_CHECK_TIMEOUT}
|
||||||
|
retries: ${HEALTH_CHECK_RETRIES}
|
||||||
|
|
||||||
|
# Tube Archivist - Elasticsearch
|
||||||
|
ta-elasticsearch:
|
||||||
|
image: elasticsearch:8.12.0
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-ta-elasticsearch"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
volumes:
|
||||||
|
- ${COMPOSE_PROJECT_NAME}_ta_es_data:/usr/share/elasticsearch/data
|
||||||
|
environment:
|
||||||
|
- discovery.type=single-node
|
||||||
|
- ES_JAVA_OPTS=${ES_JAVA_OPTS}
|
||||||
|
- xpack.security.enabled=false
|
||||||
|
- xpack.security.http.ssl.enabled=false
|
||||||
|
- bootstrap.memory_lock=true
|
||||||
|
- path.repo=/usr/share/elasticsearch/data/snapshot
|
||||||
|
ulimits:
|
||||||
|
memlock:
|
||||||
|
soft: -1
|
||||||
|
hard: -1
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 1024M
|
||||||
|
healthcheck:
|
||||||
|
test:
|
||||||
|
["CMD-SHELL",
|
||||||
|
"curl -sf http://localhost:9200/_cluster/health || exit 1"]
|
||||||
|
interval: ${HEALTH_CHECK_INTERVAL}
|
||||||
|
timeout: ${HEALTH_CHECK_TIMEOUT}
|
||||||
|
retries: 10
|
||||||
|
start_period: 60s
|
||||||
|
|
||||||
|
# Tube Archivist - YouTube Archiving
|
||||||
|
tubearchivist:
|
||||||
|
image: bbilly1/tubearchivist:latest
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-tubearchivist"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
ports:
|
||||||
|
- "${TUBE_ARCHIVIST_PORT}:8000"
|
||||||
|
volumes:
|
||||||
|
- ${COMPOSE_PROJECT_NAME}_tubearchivist_data:/cache
|
||||||
|
environment:
|
||||||
|
- ES_URL=http://ta-elasticsearch:9200
|
||||||
|
- REDIS_CON=redis://ta-redis:6379
|
||||||
|
- ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
|
||||||
|
- HOST_UID=${DEMO_UID}
|
||||||
|
- HOST_GID=${DEMO_GID}
|
||||||
|
- TA_HOST=${TA_HOST}
|
||||||
|
- TA_USERNAME=${TA_USERNAME}
|
||||||
|
- TA_PASSWORD=${TA_PASSWORD}
|
||||||
|
- TZ=UTC
|
||||||
|
depends_on:
|
||||||
|
ta-redis:
|
||||||
|
condition: service_healthy
|
||||||
|
ta-elasticsearch:
|
||||||
|
condition: service_healthy
|
||||||
|
labels:
|
||||||
|
homepage.group: "Developer Tools"
|
||||||
|
homepage.name: "Tube Archivist"
|
||||||
|
homepage.icon: "tube-archivist"
|
||||||
|
homepage.href: "http://localhost:${TUBE_ARCHIVIST_PORT}"
|
||||||
|
homepage.description: "YouTube video archiving"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "--silent",
|
||||||
|
"http://localhost:8000/api/health/"]
|
||||||
|
interval: ${HEALTH_CHECK_INTERVAL}
|
||||||
|
timeout: ${HEALTH_CHECK_TIMEOUT}
|
||||||
|
retries: 5
|
||||||
|
start_period: 120s
|
||||||
|
|
||||||
|
# Wakapi - Time Tracking
|
||||||
|
wakapi:
|
||||||
|
image: ghcr.io/muety/wakapi:latest
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-wakapi"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
ports:
|
||||||
|
- "${WAKAPI_PORT}:3000"
|
||||||
|
volumes:
|
||||||
|
- ${COMPOSE_PROJECT_NAME}_wakapi_data:/data
|
||||||
|
environment:
|
||||||
|
- WAKAPI_PASSWORD_SALT=${WAKAPI_PASSWORD_SALT}
|
||||||
|
- PUID=${DEMO_UID}
|
||||||
|
- PGID=${DEMO_GID}
|
||||||
|
labels:
|
||||||
|
homepage.group: "Developer Tools"
|
||||||
|
homepage.name: "Wakapi"
|
||||||
|
homepage.icon: "wakapi"
|
||||||
|
homepage.href: "http://localhost:${WAKAPI_PORT}"
|
||||||
|
homepage.description: "Open-source WakaTime alternative"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256M
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "/app/healthcheck"]
|
||||||
|
interval: ${HEALTH_CHECK_INTERVAL}
|
||||||
|
timeout: ${HEALTH_CHECK_TIMEOUT}
|
||||||
|
retries: ${HEALTH_CHECK_RETRIES}
|
||||||
|
|
||||||
|
# MailHog - Email Testing
|
||||||
|
mailhog:
|
||||||
|
image: mailhog/mailhog:latest
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-mailhog"
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
ports:
|
||||||
|
- "${MAILHOG_PORT}:8025"
|
||||||
|
- "${MAILHOG_SMTP_PORT}:1025"
|
||||||
|
volumes:
|
||||||
|
- ${COMPOSE_PROJECT_NAME}_mailhog_data:/maildir
|
||||||
|
environment:
|
||||||
|
- PUID=${DEMO_UID}
|
||||||
|
- PGID=${DEMO_GID}
|
||||||
|
labels:
|
||||||
|
homepage.group: "Developer Tools"
|
||||||
|
homepage.name: "MailHog"
|
||||||
|
homepage.icon: "mailhog"
|
||||||
|
homepage.href: "http://localhost:${MAILHOG_PORT}"
|
||||||
|
homepage.description: "Web and API based SMTP testing"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 128M
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider",
|
||||||
|
"http://localhost:8025"]
|
||||||
|
interval: ${HEALTH_CHECK_INTERVAL}
|
||||||
|
timeout: ${HEALTH_CHECK_TIMEOUT}
|
||||||
|
retries: ${HEALTH_CHECK_RETRIES}
|
||||||
|
|
||||||
|
# Atuin - Shell History Synchronization
|
||||||
|
atuin:
|
||||||
|
image: ghcr.io/atuinsh/atuin:v18.10.0
|
||||||
|
container_name: "${COMPOSE_PROJECT_NAME}-atuin"
|
||||||
|
restart: unless-stopped
|
||||||
|
command:
|
||||||
|
- server
|
||||||
|
- start
|
||||||
|
networks:
|
||||||
|
- ${COMPOSE_NETWORK_NAME}
|
||||||
|
ports:
|
||||||
|
- "${ATUIN_PORT}:8888"
|
||||||
|
volumes:
|
||||||
|
- ${COMPOSE_PROJECT_NAME}_atuin_data:/config
|
||||||
|
environment:
|
||||||
|
- ATUIN_HOST=${ATUIN_HOST}
|
||||||
|
- ATUIN_PORT=8888
|
||||||
|
- ATUIN_OPEN_REGISTRATION=${ATUIN_OPEN_REGISTRATION}
|
||||||
|
- ATUIN_DB_URI=sqlite:///config/atuin.db
|
||||||
|
- RUST_LOG=info,atuin_server=info
|
||||||
|
labels:
|
||||||
|
homepage.group: "Developer Tools"
|
||||||
|
homepage.name: "Atuin"
|
||||||
|
homepage.icon: "atuin"
|
||||||
|
homepage.href: "http://localhost:${ATUIN_PORT}"
|
||||||
|
homepage.description: "Magical shell history synchronization"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256M
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "bash", "-c", "echo > /dev/tcp/localhost/8888"]
|
||||||
|
interval: ${HEALTH_CHECK_INTERVAL}
|
||||||
|
timeout: ${HEALTH_CHECK_TIMEOUT}
|
||||||
|
retries: 5
|
||||||
|
start_period: 30s
|
||||||
287
demo/docs/api-docs/README.md
Normal file
287
demo/docs/api-docs/README.md
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
# TSYS Developer Support Stack - API Documentation
|
||||||
|
|
||||||
|
## Service APIs Overview
|
||||||
|
|
||||||
|
This document provides API endpoint information for all services in the stack.
|
||||||
|
|
||||||
|
## Infrastructure Services APIs
|
||||||
|
|
||||||
|
### Docker Socket Proxy
|
||||||
|
- **Base URL: http://docker-socket-proxy:2375 (internal only, not accessible from host)`
|
||||||
|
- **API Version**: Docker Engine API
|
||||||
|
- **Authentication**: None (restricted by proxy)
|
||||||
|
- **Endpoints**:
|
||||||
|
- `GET /version` - Docker version information
|
||||||
|
- `GET /info` - System information
|
||||||
|
- `GET /containers/json` - List containers
|
||||||
|
- `GET /images/json` - List images
|
||||||
|
|
||||||
|
### Pi-hole
|
||||||
|
- **Base URL**: `http://localhost:4006/admin`
|
||||||
|
- **API Version**: v1
|
||||||
|
- **Authentication**: Basic auth (demo_password)
|
||||||
|
- **Endpoints**:
|
||||||
|
- `GET /admin/api.php` - Statistics and status
|
||||||
|
- `GET /admin/api.php?list` - Blocked domains list
|
||||||
|
- `GET /admin/api.php?summaryRaw` - Raw statistics
|
||||||
|
|
||||||
|
### Dockhand
|
||||||
|
- **Base URL**: `http://localhost:4007`
|
||||||
|
- **Authentication**: Web UI with direct Docker socket access
|
||||||
|
- **Features**:
|
||||||
|
- Container lifecycle management
|
||||||
|
- Compose stack orchestration
|
||||||
|
- Git-based deployments
|
||||||
|
- Multi-environment support
|
||||||
|
- Terminal access
|
||||||
|
- Log streaming
|
||||||
|
- File browser
|
||||||
|
|
||||||
|
## Monitoring & Observability APIs
|
||||||
|
|
||||||
|
### InfluxDB
|
||||||
|
- **Base URL**: `http://localhost:4008`
|
||||||
|
- **API Version**: v2
|
||||||
|
- **Authentication**: Token-based
|
||||||
|
- **Endpoints**:
|
||||||
|
- `GET /ping` - Health check
|
||||||
|
- `POST /api/v2/write` - Write data
|
||||||
|
- `GET /api/v2/query` - Query data
|
||||||
|
- `GET /api/health` - Health status
|
||||||
|
|
||||||
|
### Grafana
|
||||||
|
- **Base URL**: `http://localhost:4009`
|
||||||
|
- **API Version**: v1
|
||||||
|
- **Authentication**: API key or Basic auth
|
||||||
|
- **Endpoints**:
|
||||||
|
- `GET /api/health` - Health check
|
||||||
|
- `GET /api/dashboards` - List dashboards
|
||||||
|
- `GET /api/datasources` - List data sources
|
||||||
|
- `POST /api/login` - Authentication
|
||||||
|
|
||||||
|
## Documentation & Diagramming APIs
|
||||||
|
|
||||||
|
### Draw.io
|
||||||
|
- **Base URL**: `http://localhost:4010`
|
||||||
|
- **API Version**: None (web interface)
|
||||||
|
- **Authentication**: None
|
||||||
|
- **Endpoints**:
|
||||||
|
- `GET /` - Main interface
|
||||||
|
- `POST /export` - Export diagram
|
||||||
|
- `GET /images` - Image library
|
||||||
|
|
||||||
|
### Kroki
|
||||||
|
- **Base URL**: `http://localhost:4011`
|
||||||
|
- **API Version**: v1
|
||||||
|
- **Authentication**: None
|
||||||
|
- **Endpoints**:
|
||||||
|
- `GET /health` - Health check
|
||||||
|
- `POST /plantuml/svg` - PlantUML to SVG
|
||||||
|
- `POST /mermaid/svg` - Mermaid to SVG
|
||||||
|
- `POST /graphviz/svg` - GraphViz to SVG
|
||||||
|
|
||||||
|
## Developer Tools APIs
|
||||||
|
|
||||||
|
### Homepage
|
||||||
|
- **Base URL**: `http://localhost:4000`
|
||||||
|
- **API Version**: None (web interface)
|
||||||
|
- **Authentication**: None
|
||||||
|
- **Endpoints**:
|
||||||
|
- `GET /` - Main dashboard
|
||||||
|
- `GET /widgets` - Widget data
|
||||||
|
- `GET /bookmarks` - Bookmark data
|
||||||
|
|
||||||
|
### Atomic Tracker
|
||||||
|
- **Base URL**: `http://localhost:4012`
|
||||||
|
- **API Version**: v1
|
||||||
|
- **Authentication**: Required
|
||||||
|
- **Endpoints**:
|
||||||
|
- `GET /api/habits` - List habits
|
||||||
|
- `POST /api/habits` - Create habit
|
||||||
|
- `PUT /api/habits/:id` - Update habit
|
||||||
|
- `DELETE /api/habits/:id` - Delete habit
|
||||||
|
|
||||||
|
### ArchiveBox
|
||||||
|
- **Base URL**: `http://localhost:4013`
|
||||||
|
- **API Version**: v1
|
||||||
|
- **Authentication**: Required
|
||||||
|
- **Endpoints**:
|
||||||
|
- `GET /api/v1/core/health` - Health check
|
||||||
|
- `POST /api/v1/core/add` - Add URL
|
||||||
|
- `GET /api/v1/snapshots` - List snapshots
|
||||||
|
- `GET /api/v1/snapshots/:id` - Get snapshot
|
||||||
|
|
||||||
|
### Tube Archivist
|
||||||
|
- **Base URL**: `http://localhost:4014`
|
||||||
|
- **API Version**: v1
|
||||||
|
- **Authentication**: Required
|
||||||
|
- **Endpoints**:
|
||||||
|
- `GET /api/health` - Health check
|
||||||
|
- `POST /api/subscribe` - Subscribe to channel
|
||||||
|
- `GET /api/video/:id` - Get video info
|
||||||
|
- `GET /api/search` - Search videos
|
||||||
|
|
||||||
|
### Wakapi
|
||||||
|
- **Base URL**: `http://localhost:4015`
|
||||||
|
- **API Version**: v1
|
||||||
|
- **Authentication**: API key
|
||||||
|
- **Endpoints**:
|
||||||
|
- `GET /api/health` - Heartbeat
|
||||||
|
- `GET /api/summary` - Time summary
|
||||||
|
- `GET /api/durations` - Heartbeats
|
||||||
|
- `POST /api/heartbeats` - Add heartbeat
|
||||||
|
|
||||||
|
### MailHog
|
||||||
|
- **Base URL**: `http://localhost:4017`
|
||||||
|
- **API Version**: v1
|
||||||
|
- **Authentication**: None
|
||||||
|
- **Endpoints**:
|
||||||
|
- `GET /api/v1/messages` - List messages
|
||||||
|
- `GET /api/v1/messages/:id` - Get message
|
||||||
|
- `DELETE /api/v1/messages` - Delete all
|
||||||
|
- `POST /api/v1/messages` - Create message
|
||||||
|
|
||||||
|
### Atuin
|
||||||
|
- **Base URL**: `http://localhost:4018`
|
||||||
|
- **API Version**: v1
|
||||||
|
- **Authentication**: Required
|
||||||
|
- **Endpoints**:
|
||||||
|
- `GET /api/health` - Health check
|
||||||
|
- `POST /api/sync` - Sync history
|
||||||
|
- `GET /api/history` - Get history
|
||||||
|
- `POST /api/history` - Add history
|
||||||
|
|
||||||
|
## API Usage Examples
|
||||||
|
|
||||||
|
### Docker Socket Proxy Example
|
||||||
|
```bash
|
||||||
|
# Get Docker version
|
||||||
|
# curl http://localhost:4005/version (internal only)
|
||||||
|
|
||||||
|
# List containers
|
||||||
|
# curl http://localhost:4005/containers/json (internal only)
|
||||||
|
```
|
||||||
|
|
||||||
|
### InfluxDB Example
|
||||||
|
```bash
|
||||||
|
# Write data
|
||||||
|
curl -X POST http://localhost:4008/api/v2/write \
|
||||||
|
-H "Authorization: Token demo_token_replace_in_production" \
|
||||||
|
-H "Content-Type: text/plain" \
|
||||||
|
--data-binary "measurement,field=value"
|
||||||
|
|
||||||
|
# Query data
|
||||||
|
curl -G http://localhost:4008/api/v2/query \
|
||||||
|
-H "Authorization: Token demo_token_replace_in_production" \
|
||||||
|
--data-urlencode "query=from(bucket:\"demo_metrics\") |> range(start: -1h)"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Grafana Example
|
||||||
|
```bash
|
||||||
|
# Get dashboards
|
||||||
|
curl -u admin:demo_password http://localhost:4009/api/dashboards
|
||||||
|
|
||||||
|
# Create API key
|
||||||
|
curl -X POST -u admin:demo_password \
|
||||||
|
http://localhost:4009/api/auth/keys \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"name":"demo","role":"Admin"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Kroki Example
|
||||||
|
```bash
|
||||||
|
# Convert PlantUML to SVG
|
||||||
|
curl -X POST http://localhost:4011/plantuml/svg \
|
||||||
|
-H "Content-Type: text/plain" \
|
||||||
|
-d "@startuml
|
||||||
|
Alice -> Bob: Hello
|
||||||
|
@enduml"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
### Demo Credentials
|
||||||
|
- **Username**: `admin`
|
||||||
|
- **Password**: `demo_password`
|
||||||
|
- **API Keys**: Use demo tokens provided in configuration
|
||||||
|
|
||||||
|
### Token-based Authentication
|
||||||
|
```bash
|
||||||
|
# InfluxDB token
|
||||||
|
export INFLUX_TOKEN="demo_token_replace_in_production"
|
||||||
|
|
||||||
|
# Grafana API key
|
||||||
|
export GRAFANA_API_KEY="demo_api_key"
|
||||||
|
|
||||||
|
# Wakapi API key
|
||||||
|
export WAKAPI_API_KEY="demo_wakapi_key"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
Most services have no rate limiting in demo mode. In production:
|
||||||
|
- Configure appropriate rate limits
|
||||||
|
- Implement authentication
|
||||||
|
- Set up monitoring
|
||||||
|
- Use reverse proxy for additional security
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Common HTTP Status Codes
|
||||||
|
- `200` - Success
|
||||||
|
- `401` - Authentication required
|
||||||
|
- `403` - Forbidden
|
||||||
|
- `404` - Not found
|
||||||
|
- `500` - Internal server error
|
||||||
|
|
||||||
|
### Error Response Format
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "Error message",
|
||||||
|
"code": "ERROR_CODE",
|
||||||
|
"details": "Additional details"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Health Checks
|
||||||
|
|
||||||
|
All services provide health check endpoints:
|
||||||
|
- `GET /health` - Standard health check
|
||||||
|
- `GET /ping` - Simple ping response
|
||||||
|
- `GET /api/health` - API-specific health
|
||||||
|
|
||||||
|
## Development Notes
|
||||||
|
|
||||||
|
### Testing APIs
|
||||||
|
```bash
|
||||||
|
# Test all health endpoints
|
||||||
|
for port in 4000 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4017 4018; do
|
||||||
|
echo "Testing port $port..."
|
||||||
|
curl -f -s "http://localhost:$port/health" || \
|
||||||
|
curl -f -s "http://localhost:$port/ping" || \
|
||||||
|
curl -f -s "http://localhost:$port/api/health" || \
|
||||||
|
echo "Health check failed for port $port"
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
### Monitoring API Usage
|
||||||
|
- Use Grafana dashboards to monitor API calls
|
||||||
|
- Check service logs for API errors
|
||||||
|
- Monitor resource usage with Docker stats
|
||||||
|
- Set up alerts for API failures
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
### Demo Mode
|
||||||
|
- All APIs are accessible without authentication
|
||||||
|
- No rate limiting implemented
|
||||||
|
- No HTTPS encryption
|
||||||
|
- Default demo credentials
|
||||||
|
|
||||||
|
### Production Migration
|
||||||
|
- Implement proper authentication
|
||||||
|
- Add rate limiting
|
||||||
|
- Use HTTPS/TLS
|
||||||
|
- Set up API gateway
|
||||||
|
- Implement audit logging
|
||||||
|
- Configure CORS policies
|
||||||
55
demo/docs/service-guides/README.md
Normal file
55
demo/docs/service-guides/README.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# TSYS Developer Support Stack - Service Guides
|
||||||
|
|
||||||
|
This directory contains detailed guides for each service in the stack.
|
||||||
|
|
||||||
|
## Available Guides
|
||||||
|
|
||||||
|
- [Homepage Dashboard](homepage.md)
|
||||||
|
- [Infrastructure Services](infrastructure.md)
|
||||||
|
- [Monitoring & Observability](monitoring.md)
|
||||||
|
- [Documentation & Diagramming](documentation.md)
|
||||||
|
- [Developer Tools](developer-tools.md)
|
||||||
|
|
||||||
|
## Quick Access
|
||||||
|
|
||||||
|
All services are accessible through the Homepage dashboard at http://localhost:4000
|
||||||
|
|
||||||
|
## Service Categories
|
||||||
|
|
||||||
|
### 🏗️ Infrastructure Services
|
||||||
|
- **Pi-hole** (Port 4006): DNS management with ad blocking
|
||||||
|
- **Dockhand** (Port 4007): Modern Docker management UI
|
||||||
|
- **Docker Socket Proxy** (Port 4005): Secure Docker socket access
|
||||||
|
|
||||||
|
### 📊 Monitoring & Observability
|
||||||
|
- **InfluxDB** (Port 4008): Time series database for metrics
|
||||||
|
- **Grafana** (Port 4009): Analytics and visualization platform
|
||||||
|
|
||||||
|
### 📚 Documentation & Diagramming
|
||||||
|
- **Draw.io** (Port 4010): Web-based diagramming application
|
||||||
|
- **Kroki** (Port 4011): Diagrams as a service
|
||||||
|
|
||||||
|
### 🛠️ Developer Tools
|
||||||
|
- **Homepage** (Port 4000): Central dashboard for service discovery
|
||||||
|
- **Atomic Tracker** (Port 4012): Habit tracking and personal dashboard
|
||||||
|
- **ArchiveBox** (Port 4013): Web archiving solution
|
||||||
|
- **Tube Archivist** (Port 4014): YouTube video archiving (requires internal ta-redis + ta-elasticsearch)
|
||||||
|
- **Wakapi** (Port 4015): Open-source WakaTime alternative
|
||||||
|
- **MailHog** (Port 4017): Web and API based SMTP testing
|
||||||
|
- **Atuin** (Port 4018): Magical shell history synchronization
|
||||||
|
|
||||||
|
## Demo Credentials
|
||||||
|
|
||||||
|
⚠️ **FOR DEMONSTRATION PURPOSES ONLY**
|
||||||
|
|
||||||
|
- **Username**: `admin`
|
||||||
|
- **Password**: `demo_password`
|
||||||
|
|
||||||
|
These credentials work for Grafana and Dockhand. Other services may have different authentication requirements.
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
1. Check the individual service guides below
|
||||||
|
2. Review the [troubleshooting guide](../troubleshooting/README.md)
|
||||||
|
3. Check service logs: `docker compose logs [service-name]`
|
||||||
|
4. Verify service status: `docker compose ps`
|
||||||
294
demo/docs/troubleshooting/README.md
Normal file
294
demo/docs/troubleshooting/README.md
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
# TSYS Developer Support Stack - Troubleshooting Guide
|
||||||
|
|
||||||
|
> **Note:** All commands in this guide assume your working directory is the `demo/` folder of the repository. Run `cd demo` first if needed.
|
||||||
|
|
||||||
|
## Common Issues and Solutions
|
||||||
|
|
||||||
|
### Services Not Starting
|
||||||
|
|
||||||
|
#### Issue: Docker daemon not running
|
||||||
|
**Symptoms**: `Cannot connect to the Docker daemon`
|
||||||
|
**Solution**:
|
||||||
|
```bash
|
||||||
|
sudo systemctl start docker
|
||||||
|
sudo systemctl enable docker
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Issue: Port conflicts
|
||||||
|
**Symptoms**: `Port already in use` errors
|
||||||
|
**Solution**:
|
||||||
|
```bash
|
||||||
|
# Check what's using the port
|
||||||
|
netstat -tulpn | grep :4000
|
||||||
|
|
||||||
|
# Kill conflicting process
|
||||||
|
sudo fuser -k 4000/tcp
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Issue: Environment variables not set
|
||||||
|
**Symptoms**: `Variable not found` errors
|
||||||
|
**Solution**:
|
||||||
|
```bash
|
||||||
|
# Check demo.env exists and is populated
|
||||||
|
cat demo.env
|
||||||
|
|
||||||
|
# Re-run user detection
|
||||||
|
./scripts/demo-stack.sh deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Health Check Failures
|
||||||
|
|
||||||
|
#### Issue: Services stuck in "starting" state
|
||||||
|
**Symptoms**: Health checks timeout
|
||||||
|
**Solution**:
|
||||||
|
```bash
|
||||||
|
# Check service logs
|
||||||
|
docker compose logs [service-name]
|
||||||
|
|
||||||
|
# Restart specific service
|
||||||
|
docker compose restart [service-name]
|
||||||
|
|
||||||
|
# Check resource usage
|
||||||
|
docker stats
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Issue: Network connectivity problems
|
||||||
|
**Symptoms**: Services can't reach each other
|
||||||
|
**Solution**:
|
||||||
|
```bash
|
||||||
|
# Check network exists
|
||||||
|
docker network ls | grep kneldevstack
|
||||||
|
|
||||||
|
# Recreate network
|
||||||
|
docker network create --subnet 192.168.3.0/24 --gateway 192.168.3.1 kneldevstack-supportstack-demo-network
|
||||||
|
|
||||||
|
# Restart stack
|
||||||
|
docker compose down && docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Permission Issues
|
||||||
|
|
||||||
|
#### Issue: File ownership problems
|
||||||
|
**Symptoms**: `Permission denied` errors
|
||||||
|
**Solution**:
|
||||||
|
```bash
|
||||||
|
# Check current user
|
||||||
|
id
|
||||||
|
|
||||||
|
# Verify UID/GID detection
|
||||||
|
cat demo.env | grep -E "(UID|GID)"
|
||||||
|
|
||||||
|
# Fix volume permissions
|
||||||
|
sudo chown -R $(id -u):$(id -g) /var/lib/docker/volumes/kneldevstack-supportstack-demo_*
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Issue: Docker group access
|
||||||
|
**Symptoms**: `Got permission denied` errors
|
||||||
|
**Solution**:
|
||||||
|
```bash
|
||||||
|
# Add user to docker group
|
||||||
|
sudo usermod -aG docker $USER
|
||||||
|
|
||||||
|
# Log out and back in, or run:
|
||||||
|
newgrp docker
|
||||||
|
```
|
||||||
|
|
||||||
|
### Service-Specific Issues
|
||||||
|
|
||||||
|
#### Pi-hole DNS Issues
|
||||||
|
**Symptoms**: DNS resolution failures
|
||||||
|
**Solution**:
|
||||||
|
```bash
|
||||||
|
# Check Pi-hole status
|
||||||
|
docker exec kneldevstack-supportstack-demo-pihole pihole status
|
||||||
|
|
||||||
|
# Test DNS resolution
|
||||||
|
nslookup google.com localhost
|
||||||
|
|
||||||
|
# Restart DNS service
|
||||||
|
docker exec kneldevstack-supportstack-demo-pihole pihole restartdns
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Grafana Data Source Connection
|
||||||
|
**Symptoms**: InfluxDB data source not working
|
||||||
|
**Solution**:
|
||||||
|
```bash
|
||||||
|
# Test InfluxDB connectivity
|
||||||
|
curl http://localhost:4008/ping
|
||||||
|
|
||||||
|
# Check Grafana logs
|
||||||
|
docker compose logs grafana
|
||||||
|
|
||||||
|
# Verify data source configuration
|
||||||
|
# Navigate to: http://localhost:4009/datasources
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Dockhand Container Access
|
||||||
|
**Symptoms**: Can't manage containers
|
||||||
|
**Solution**:
|
||||||
|
```bash
|
||||||
|
# Check Dockhand logs
|
||||||
|
docker compose logs dockhand
|
||||||
|
|
||||||
|
# Verify Docker socket access (check socket is mounted)
|
||||||
|
docker inspect kneldevstack-supportstack-demo-dockhand --format '{{.Mounts}}' | grep docker.sock
|
||||||
|
|
||||||
|
# Restart Dockhand
|
||||||
|
docker compose restart dockhand
|
||||||
|
```
|
||||||
|
|
||||||
|
### Performance Issues
|
||||||
|
|
||||||
|
#### Issue: High memory usage
|
||||||
|
**Symptoms**: System becomes slow
|
||||||
|
**Solution**:
|
||||||
|
```bash
|
||||||
|
# Check resource usage
|
||||||
|
docker stats
|
||||||
|
|
||||||
|
# Set memory limits in docker-compose.yml
|
||||||
|
# Add to each service:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
|
||||||
|
# Restart with new limits
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Issue: Slow startup times
|
||||||
|
**Symptoms**: Services take >60 seconds to start
|
||||||
|
**Solution**:
|
||||||
|
```bash
|
||||||
|
# Check system resources
|
||||||
|
free -h
|
||||||
|
df -h
|
||||||
|
|
||||||
|
# Pull images in advance
|
||||||
|
docker compose pull
|
||||||
|
|
||||||
|
# Check for conflicting services
|
||||||
|
docker ps -a
|
||||||
|
```
|
||||||
|
|
||||||
|
## Diagnostic Commands
|
||||||
|
|
||||||
|
### System Information
|
||||||
|
```bash
|
||||||
|
# System info
|
||||||
|
uname -a
|
||||||
|
free -h
|
||||||
|
df -h
|
||||||
|
|
||||||
|
# Docker info
|
||||||
|
docker version
|
||||||
|
docker compose version
|
||||||
|
docker system df
|
||||||
|
```
|
||||||
|
|
||||||
|
### Service Status
|
||||||
|
```bash
|
||||||
|
# All services status
|
||||||
|
docker compose ps
|
||||||
|
|
||||||
|
# Service logs
|
||||||
|
docker compose logs
|
||||||
|
|
||||||
|
# Resource usage
|
||||||
|
docker stats
|
||||||
|
|
||||||
|
# Network info
|
||||||
|
docker network ls
|
||||||
|
docker network inspect kneldevstack-supportstack-demo
|
||||||
|
```
|
||||||
|
|
||||||
|
### Health Checks
|
||||||
|
```bash
|
||||||
|
# Test all endpoints
|
||||||
|
for port in 4000 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4017 4018; do
|
||||||
|
curl -f -s --max-time 5 "http://localhost:$port" && echo "Port $port: OK" || echo "Port $port: FAIL"
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
## Getting Additional Help
|
||||||
|
|
||||||
|
### Check Logs First
|
||||||
|
```bash
|
||||||
|
# All service logs
|
||||||
|
docker compose logs
|
||||||
|
|
||||||
|
# Specific service logs
|
||||||
|
docker compose logs [service-name]
|
||||||
|
|
||||||
|
# Follow logs in real-time
|
||||||
|
docker compose logs -f [service-name]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validation Scripts
|
||||||
|
```bash
|
||||||
|
# Run comprehensive validation
|
||||||
|
./scripts/validate-all.sh
|
||||||
|
|
||||||
|
# Run test suite
|
||||||
|
./scripts/demo-test.sh full
|
||||||
|
|
||||||
|
# Run specific test categories
|
||||||
|
./scripts/demo-test.sh security
|
||||||
|
./scripts/demo-test.sh permissions
|
||||||
|
./scripts/demo-test.sh network
|
||||||
|
```
|
||||||
|
|
||||||
|
### Reset and Restart
|
||||||
|
```bash
|
||||||
|
# Complete reset (removes all data)
|
||||||
|
docker compose down -v
|
||||||
|
docker system prune -f
|
||||||
|
|
||||||
|
# Fresh deployment
|
||||||
|
./scripts/demo-stack.sh deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
## Known Limitations
|
||||||
|
|
||||||
|
### Demo Mode Restrictions
|
||||||
|
- No data persistence between restarts
|
||||||
|
- Hardcoded demo credentials
|
||||||
|
- No external network access
|
||||||
|
- No security hardening
|
||||||
|
|
||||||
|
### Resource Requirements
|
||||||
|
- Minimum 8GB RAM recommended
|
||||||
|
- Minimum 10GB disk space
|
||||||
|
- Docker daemon must be running
|
||||||
|
- User must be in docker group
|
||||||
|
|
||||||
|
### Port Requirements
|
||||||
|
The following host ports must be available (not a continuous range):
|
||||||
|
- 4000: Homepage
|
||||||
|
- 4006: Pi-hole
|
||||||
|
- 4007: Dockhand
|
||||||
|
- 4008: InfluxDB
|
||||||
|
- 4009: Grafana
|
||||||
|
- 4010: Draw.io
|
||||||
|
- 4011: Kroki
|
||||||
|
- 4012: Atomic Tracker
|
||||||
|
- 4013: ArchiveBox
|
||||||
|
- 4014: Tube Archivist
|
||||||
|
- 4015: Wakapi
|
||||||
|
- 4017: MailHog
|
||||||
|
- 4018: Atuin
|
||||||
|
|
||||||
|
Note: Docker Socket Proxy (4005), Redis, and Elasticsearch are internal-only and do not require host ports.
|
||||||
|
|
||||||
|
## Contact and Support
|
||||||
|
|
||||||
|
If issues persist after trying these solutions:
|
||||||
|
|
||||||
|
1. Document the exact error message
|
||||||
|
2. Include system information (OS, Docker version)
|
||||||
|
3. List steps to reproduce the issue
|
||||||
|
4. Include relevant log output
|
||||||
|
5. Specify demo vs production context
|
||||||
|
|
||||||
|
Remember: This is a demo configuration designed for development and testing purposes only.
|
||||||
247
demo/scripts/demo-stack.sh
Executable file
247
demo/scripts/demo-stack.sh
Executable file
@@ -0,0 +1,247 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DEMO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
ENV_FILE="$DEMO_DIR/demo.env"
|
||||||
|
ENV_TEMPLATE="$DEMO_DIR/demo.env.template"
|
||||||
|
TEMPLATE_FILE="$DEMO_DIR/docker-compose.yml.template"
|
||||||
|
COMPOSE_FILE="$DEMO_DIR/docker-compose.yml"
|
||||||
|
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||||
|
log_success() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||||||
|
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||||
|
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||||
|
|
||||||
|
ensure_env() {
|
||||||
|
if [[ ! -f "$ENV_FILE" ]]; then
|
||||||
|
if [[ -f "$ENV_TEMPLATE" ]]; then
|
||||||
|
log_info "Creating demo.env from template..."
|
||||||
|
cp "$ENV_TEMPLATE" "$ENV_FILE"
|
||||||
|
else
|
||||||
|
log_error "No demo.env or demo.env.template found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
# Ensure new variables exist in older env files
|
||||||
|
grep -q '^MAILHOG_SMTP_PORT=' "$ENV_FILE" || echo "MAILHOG_SMTP_PORT=4019" >> "$ENV_FILE"
|
||||||
|
grep -q '^HOMEPAGE_ALLOWED_HOSTS=' "$ENV_FILE" || echo "HOMEPAGE_ALLOWED_HOSTS=*" >> "$ENV_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
detect_user() {
|
||||||
|
log_info "Detecting user IDs..."
|
||||||
|
local uid gid docker_gid
|
||||||
|
uid=$(id -u)
|
||||||
|
gid=$(id -g)
|
||||||
|
docker_gid=$(getent group docker | cut -d: -f3)
|
||||||
|
sed -i "s/^DEMO_UID=.*/DEMO_UID=$uid/" "$ENV_FILE"
|
||||||
|
sed -i "s/^DEMO_GID=.*/DEMO_GID=$gid/" "$ENV_FILE"
|
||||||
|
sed -i "s/^DEMO_DOCKER_GID=.*/DEMO_DOCKER_GID=$docker_gid/" "$ENV_FILE"
|
||||||
|
log_success "UID=$uid GID=$gid DockerGID=$docker_gid"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_prerequisites() {
|
||||||
|
log_info "Checking prerequisites..."
|
||||||
|
if ! docker info >/dev/null 2>&1; then
|
||||||
|
log_error "Docker is not running"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! command -v envsubst >/dev/null 2>&1; then
|
||||||
|
log_error "envsubst not found (install gettext package)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
local max_map_count
|
||||||
|
max_map_count=$(sysctl -n vm.max_map_count 2>/dev/null || echo "0")
|
||||||
|
if [[ "$max_map_count" -lt 262144 ]]; then
|
||||||
|
log_warn "Setting vm.max_map_count=262144 for Elasticsearch..."
|
||||||
|
if sudo sysctl -w vm.max_map_count=262144 2>/dev/null; then
|
||||||
|
log_success "vm.max_map_count set"
|
||||||
|
else
|
||||||
|
log_warn "Could not set vm.max_map_count (TubeArchivist ES may fail)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
log_success "Prerequisites OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_compose() {
|
||||||
|
log_info "Generating docker-compose.yml from template..."
|
||||||
|
set -a; source "$ENV_FILE"; set +a
|
||||||
|
envsubst < "$TEMPLATE_FILE" > "$COMPOSE_FILE"
|
||||||
|
log_success "docker-compose.yml generated"
|
||||||
|
}
|
||||||
|
|
||||||
|
deploy_stack() {
|
||||||
|
log_info "Deploying TSYS Developer Support Stack..."
|
||||||
|
cd "$DEMO_DIR"
|
||||||
|
docker compose up -d 2>&1
|
||||||
|
log_success "Stack deployment initiated"
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_healthy() {
|
||||||
|
log_info "Waiting for services to become healthy (max 5 min)..."
|
||||||
|
local elapsed=0 interval=15
|
||||||
|
while [[ $elapsed -lt 300 ]]; do
|
||||||
|
local unhealthy=0
|
||||||
|
while IFS= read -r name; do
|
||||||
|
local health
|
||||||
|
health=$(docker inspect --format='{{.State.Health.Status}}' "$name" 2>/dev/null || echo "unknown")
|
||||||
|
if [[ "$health" != "healthy" ]]; then
|
||||||
|
unhealthy=$((unhealthy + 1))
|
||||||
|
fi
|
||||||
|
done < <(docker ps --filter "name=${COMPOSE_PROJECT_NAME:-kneldevstack}" --format '{{.Names}}' 2>/dev/null)
|
||||||
|
|
||||||
|
if [[ $unhealthy -eq 0 ]]; then
|
||||||
|
log_success "All services healthy"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
log_info " $unhealthy services not yet healthy (${elapsed}s elapsed)"
|
||||||
|
sleep $interval
|
||||||
|
elapsed=$((elapsed + interval))
|
||||||
|
done
|
||||||
|
log_warn "Timeout - some services may not be fully healthy"
|
||||||
|
cd "$DEMO_DIR" && docker compose ps
|
||||||
|
}
|
||||||
|
|
||||||
|
display_summary() {
|
||||||
|
set -a; source "$ENV_FILE"; set +a
|
||||||
|
echo ""
|
||||||
|
echo "========================================================"
|
||||||
|
echo " TSYS Developer Support Stack - Deployment Summary"
|
||||||
|
echo "========================================================"
|
||||||
|
echo ""
|
||||||
|
echo " Infrastructure:"
|
||||||
|
echo " Homepage Dashboard http://localhost:${HOMEPAGE_PORT}"
|
||||||
|
echo " Pi-hole (DNS) http://localhost:${PIHOLE_PORT}"
|
||||||
|
echo " Dockhand (Docker) http://localhost:${DOCKHAND_PORT}"
|
||||||
|
echo ""
|
||||||
|
echo " Monitoring:"
|
||||||
|
echo " InfluxDB http://localhost:${INFLUXDB_PORT}"
|
||||||
|
echo " Grafana http://localhost:${GRAFANA_PORT}"
|
||||||
|
echo ""
|
||||||
|
echo " Documentation:"
|
||||||
|
echo " Draw.io http://localhost:${DRAWIO_PORT}"
|
||||||
|
echo " Kroki http://localhost:${KROKI_PORT}"
|
||||||
|
echo ""
|
||||||
|
echo " Developer Tools:"
|
||||||
|
echo " Atomic Tracker http://localhost:${ATOMIC_TRACKER_PORT}"
|
||||||
|
echo " ArchiveBox http://localhost:${ARCHIVEBOX_PORT}"
|
||||||
|
echo " Tube Archivist http://localhost:${TUBE_ARCHIVIST_PORT}"
|
||||||
|
echo " Wakapi http://localhost:${WAKAPI_PORT}"
|
||||||
|
echo " MailHog (Web) http://localhost:${MAILHOG_PORT}"
|
||||||
|
echo " MailHog (SMTP) localhost:${MAILHOG_SMTP_PORT}"
|
||||||
|
echo " Atuin http://localhost:${ATUIN_PORT}"
|
||||||
|
echo ""
|
||||||
|
echo " Credentials: admin / demo_password"
|
||||||
|
echo " FOR DEMONSTRATION PURPOSES ONLY"
|
||||||
|
echo "========================================================"
|
||||||
|
}
|
||||||
|
|
||||||
|
smoke_test() {
|
||||||
|
log_info "Running smoke tests..."
|
||||||
|
set -a; source "$ENV_FILE"; set +a
|
||||||
|
local ports=(
|
||||||
|
"${HOMEPAGE_PORT}:Homepage"
|
||||||
|
"${PIHOLE_PORT}:Pi-hole"
|
||||||
|
"${DOCKHAND_PORT}:Dockhand"
|
||||||
|
"${INFLUXDB_PORT}:InfluxDB"
|
||||||
|
"${GRAFANA_PORT}:Grafana"
|
||||||
|
"${DRAWIO_PORT}:Draw.io"
|
||||||
|
"${KROKI_PORT}:Kroki"
|
||||||
|
"${ATOMIC_TRACKER_PORT}:AtomicTracker"
|
||||||
|
"${ARCHIVEBOX_PORT}:ArchiveBox"
|
||||||
|
"${TUBE_ARCHIVIST_PORT}:TubeArchivist"
|
||||||
|
"${WAKAPI_PORT}:Wakapi"
|
||||||
|
"${MAILHOG_PORT}:MailHog"
|
||||||
|
"${ATUIN_PORT}:Atuin"
|
||||||
|
)
|
||||||
|
local pass=0 fail=0
|
||||||
|
for pt in "${ports[@]}"; do
|
||||||
|
local port="${pt%:*}"
|
||||||
|
local svc="${pt#*:}"
|
||||||
|
if timeout 5 bash -c "echo > /dev/tcp/localhost/$port" 2>/dev/null; then
|
||||||
|
log_success "$svc (:$port)"
|
||||||
|
((pass++)) || true
|
||||||
|
else
|
||||||
|
log_error "$svc (:$port) NOT accessible"
|
||||||
|
((fail++)) || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
echo "SMOKE TEST: $pass passed, $fail failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_stack() {
|
||||||
|
log_info "Stopping stack..."
|
||||||
|
cd "$DEMO_DIR"
|
||||||
|
docker compose down 2>&1
|
||||||
|
log_success "Stack stopped"
|
||||||
|
}
|
||||||
|
|
||||||
|
show_status() {
|
||||||
|
cd "$DEMO_DIR"
|
||||||
|
docker compose ps
|
||||||
|
}
|
||||||
|
|
||||||
|
show_usage() {
|
||||||
|
echo "TSYS Developer Support Stack"
|
||||||
|
echo ""
|
||||||
|
echo "Usage: $0 {deploy|stop|restart|status|smoke|summary|help}"
|
||||||
|
echo ""
|
||||||
|
echo "Commands:"
|
||||||
|
echo " deploy Deploy the complete stack"
|
||||||
|
echo " stop Stop all services"
|
||||||
|
echo " restart Stop and redeploy"
|
||||||
|
echo " status Show service status"
|
||||||
|
echo " smoke Run port accessibility tests"
|
||||||
|
echo " summary Show service URLs"
|
||||||
|
echo " help Show this help"
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_env
|
||||||
|
|
||||||
|
case "${1:-deploy}" in
|
||||||
|
deploy)
|
||||||
|
detect_user
|
||||||
|
check_prerequisites
|
||||||
|
generate_compose
|
||||||
|
deploy_stack
|
||||||
|
wait_healthy
|
||||||
|
display_summary
|
||||||
|
smoke_test
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
stop_stack
|
||||||
|
;;
|
||||||
|
restart)
|
||||||
|
stop_stack
|
||||||
|
sleep 5
|
||||||
|
detect_user
|
||||||
|
check_prerequisites
|
||||||
|
generate_compose
|
||||||
|
deploy_stack
|
||||||
|
wait_healthy
|
||||||
|
display_summary
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
show_status
|
||||||
|
;;
|
||||||
|
smoke)
|
||||||
|
smoke_test
|
||||||
|
;;
|
||||||
|
summary)
|
||||||
|
display_summary
|
||||||
|
;;
|
||||||
|
help|--help|-h)
|
||||||
|
show_usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_error "Unknown command: $1"
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
255
demo/scripts/demo-test.sh
Executable file
255
demo/scripts/demo-test.sh
Executable file
@@ -0,0 +1,255 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# TSYS Developer Support Stack - Demo Testing Script
|
||||||
|
# Version: 2.0
|
||||||
|
# Purpose: Comprehensive QA and validation
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||||
|
DEMO_ENV_FILE="$PROJECT_ROOT/demo.env"
|
||||||
|
COMPOSE_FILE="$PROJECT_ROOT/docker-compose.yml"
|
||||||
|
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
TESTS_PASSED=0
|
||||||
|
TESTS_FAILED=0
|
||||||
|
TESTS_TOTAL=0
|
||||||
|
|
||||||
|
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||||
|
log_success() { echo -e "${GREEN}[PASS]${NC} $1"; ((TESTS_PASSED++)) || true; }
|
||||||
|
log_warning() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||||
|
log_error() { echo -e "${RED}[FAIL]${NC} $1"; ((TESTS_FAILED++)) || true; }
|
||||||
|
log_test() { echo -e "${BLUE}[TEST]${NC} $1"; ((TESTS_TOTAL++)) || true; }
|
||||||
|
|
||||||
|
test_file_ownership() {
|
||||||
|
log_test "File ownership (no root-owned files)"
|
||||||
|
local root_files
|
||||||
|
root_files=$(find "$PROJECT_ROOT" -type f -user root 2>/dev/null || true)
|
||||||
|
if [[ -z "$root_files" ]]; then
|
||||||
|
log_success "No root-owned files"
|
||||||
|
else
|
||||||
|
log_error "Root-owned files found: $root_files"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_user_mapping() {
|
||||||
|
log_test "UID/GID detection"
|
||||||
|
source "$DEMO_ENV_FILE"
|
||||||
|
if [[ -z "${DEMO_UID:-}" || -z "${DEMO_GID:-}" ]]; then
|
||||||
|
log_error "DEMO_UID or DEMO_GID not set"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
local cur_uid cur_gid
|
||||||
|
cur_uid=$(id -u)
|
||||||
|
cur_gid=$(id -g)
|
||||||
|
if [[ "$DEMO_UID" -eq "$cur_uid" && "$DEMO_GID" -eq "$cur_gid" ]]; then
|
||||||
|
log_success "UID/GID correct ($DEMO_UID/$DEMO_GID)"
|
||||||
|
else
|
||||||
|
log_error "UID/GID mismatch: env=$DEMO_UID/$DEMO_GID actual=$cur_uid/$cur_gid"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_docker_group() {
|
||||||
|
log_test "Docker group access"
|
||||||
|
source "$DEMO_ENV_FILE"
|
||||||
|
if [[ -z "${DEMO_DOCKER_GID:-}" ]]; then
|
||||||
|
log_error "DEMO_DOCKER_GID not set"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
local actual_gid
|
||||||
|
actual_gid=$(getent group docker | cut -d: -f3)
|
||||||
|
if [[ "$DEMO_DOCKER_GID" -eq "$actual_gid" ]]; then
|
||||||
|
log_success "Docker GID correct ($DEMO_DOCKER_GID)"
|
||||||
|
else
|
||||||
|
log_error "Docker GID mismatch: env=$DEMO_DOCKER_GID actual=$actual_gid"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_service_health() {
|
||||||
|
log_test "Service health"
|
||||||
|
local unhealthy=0
|
||||||
|
while IFS= read -r line; do
|
||||||
|
local name status
|
||||||
|
name=$(echo "$line" | awk '{print $1}')
|
||||||
|
[[ "$name" == "NAMES" || -z "$name" ]] && continue
|
||||||
|
if echo "$line" | grep -q "(healthy)"; then
|
||||||
|
log_success "$name healthy"
|
||||||
|
elif echo "$line" | grep -q "Up"; then
|
||||||
|
log_success "$name running"
|
||||||
|
else
|
||||||
|
log_error "$name not running: $line"
|
||||||
|
((unhealthy++)) || true
|
||||||
|
fi
|
||||||
|
done < <(docker ps --filter "name=${COMPOSE_PROJECT_NAME:-kneldevstack}" --format "{{.Names}} {{.Status}}" 2>/dev/null)
|
||||||
|
if [[ $unhealthy -eq 0 ]]; then
|
||||||
|
log_success "All services running"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_port_accessibility() {
|
||||||
|
log_test "Port accessibility"
|
||||||
|
source "$DEMO_ENV_FILE"
|
||||||
|
|
||||||
|
# These are exposed to host
|
||||||
|
local port_tests=(
|
||||||
|
"$HOMEPAGE_PORT:Homepage"
|
||||||
|
"$PIHOLE_PORT:Pi-hole"
|
||||||
|
"$DOCKHAND_PORT:Dockhand"
|
||||||
|
"$INFLUXDB_PORT:InfluxDB"
|
||||||
|
"$GRAFANA_PORT:Grafana"
|
||||||
|
"$DRAWIO_PORT:Draw.io"
|
||||||
|
"$KROKI_PORT:Kroki"
|
||||||
|
"$ATOMIC_TRACKER_PORT:AtomicTracker"
|
||||||
|
"$ARCHIVEBOX_PORT:ArchiveBox"
|
||||||
|
"$TUBE_ARCHIVIST_PORT:TubeArchivist"
|
||||||
|
"$WAKAPI_PORT:Wakapi"
|
||||||
|
"$MAILHOG_PORT:MailHog"
|
||||||
|
"$ATUIN_PORT:Atuin"
|
||||||
|
)
|
||||||
|
|
||||||
|
local failed=0
|
||||||
|
for pt in "${port_tests[@]}"; do
|
||||||
|
local port="${pt%:*}"
|
||||||
|
local svc="${pt#*:}"
|
||||||
|
if timeout 5 bash -c "echo > /dev/tcp/localhost/$port" 2>/dev/null; then
|
||||||
|
log_success "$svc (:$port)"
|
||||||
|
else
|
||||||
|
log_error "$svc (:$port) not accessible"
|
||||||
|
((failed++)) || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ $failed -eq 0 ]]; then
|
||||||
|
log_success "All exposed ports accessible"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_network_isolation() {
|
||||||
|
log_test "Network isolation"
|
||||||
|
source "$DEMO_ENV_FILE"
|
||||||
|
if docker network ls --format '{{.Name}}' | grep -q "$COMPOSE_NETWORK_NAME"; then
|
||||||
|
log_success "Network $COMPOSE_NETWORK_NAME exists"
|
||||||
|
local driver
|
||||||
|
driver=$(docker network inspect "$COMPOSE_NETWORK_NAME" --format '{{.Driver}}' 2>/dev/null || echo "")
|
||||||
|
if [[ "$driver" == "bridge" ]]; then
|
||||||
|
log_success "Bridge driver confirmed"
|
||||||
|
else
|
||||||
|
log_warning "Driver: $driver"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_error "Network $COMPOSE_NETWORK_NAME not found"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_volume_permissions() {
|
||||||
|
log_test "Docker volumes exist"
|
||||||
|
source "$DEMO_ENV_FILE"
|
||||||
|
local vol_count
|
||||||
|
vol_count=$(docker volume ls --filter "name=${COMPOSE_PROJECT_NAME}" -q 2>/dev/null | wc -l)
|
||||||
|
if [[ $vol_count -ge 15 ]]; then
|
||||||
|
log_success "$vol_count volumes created"
|
||||||
|
else
|
||||||
|
log_error "Only $vol_count volumes found"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_security_compliance() {
|
||||||
|
log_test "Security compliance"
|
||||||
|
source "$DEMO_ENV_FILE"
|
||||||
|
|
||||||
|
# Docker socket proxy present
|
||||||
|
if grep -q "docker-socket-proxy" "$COMPOSE_FILE"; then
|
||||||
|
log_success "Docker socket proxy configured"
|
||||||
|
else
|
||||||
|
log_error "Docker socket proxy not found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Count direct socket mounts - only proxy should have one
|
||||||
|
local socket_mounts
|
||||||
|
socket_mounts=$(grep -c '/var/run/docker.sock' "$COMPOSE_FILE" || echo "0")
|
||||||
|
if [[ "$socket_mounts" -le 1 ]]; then
|
||||||
|
log_success "Socket mount on proxy only ($socket_mounts)"
|
||||||
|
else
|
||||||
|
log_error "Unexpected socket mounts: $socket_mounts (expected 1, proxy only)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Dockhand uses proxy, not direct socket
|
||||||
|
if grep -q 'DOCKER_HOST=tcp://docker-socket-proxy' "$COMPOSE_FILE"; then
|
||||||
|
log_success "Dockhand routes through socket proxy"
|
||||||
|
else
|
||||||
|
log_error "Dockhand not using socket proxy"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_full_tests() {
|
||||||
|
log_info "Running comprehensive test suite..."
|
||||||
|
test_file_ownership || true
|
||||||
|
test_user_mapping || true
|
||||||
|
test_docker_group || true
|
||||||
|
test_service_health || true
|
||||||
|
test_port_accessibility || true
|
||||||
|
test_network_isolation || true
|
||||||
|
test_volume_permissions || true
|
||||||
|
test_security_compliance || true
|
||||||
|
display_test_results
|
||||||
|
}
|
||||||
|
|
||||||
|
run_security_tests() {
|
||||||
|
log_info "Running security tests..."
|
||||||
|
test_file_ownership || true
|
||||||
|
test_network_isolation || true
|
||||||
|
test_security_compliance || true
|
||||||
|
display_test_results
|
||||||
|
}
|
||||||
|
|
||||||
|
run_permission_tests() {
|
||||||
|
log_info "Running permission tests..."
|
||||||
|
test_file_ownership || true
|
||||||
|
test_user_mapping || true
|
||||||
|
test_docker_group || true
|
||||||
|
test_volume_permissions || true
|
||||||
|
display_test_results
|
||||||
|
}
|
||||||
|
|
||||||
|
run_network_tests() {
|
||||||
|
log_info "Running network tests..."
|
||||||
|
test_network_isolation || true
|
||||||
|
test_port_accessibility || true
|
||||||
|
display_test_results
|
||||||
|
}
|
||||||
|
|
||||||
|
display_test_results() {
|
||||||
|
echo ""
|
||||||
|
echo "===================================="
|
||||||
|
echo "TEST RESULTS"
|
||||||
|
echo "===================================="
|
||||||
|
echo "Total: $TESTS_TOTAL"
|
||||||
|
echo -e "Passed: ${GREEN}$TESTS_PASSED${NC}"
|
||||||
|
echo -e "Failed: ${RED}$TESTS_FAILED${NC}"
|
||||||
|
if [[ $TESTS_FAILED -eq 0 ]]; then
|
||||||
|
echo -e "\n${GREEN}ALL TESTS PASSED${NC}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "\n${RED}SOME TESTS FAILED${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
case "${1:-full}" in
|
||||||
|
full) run_full_tests ;;
|
||||||
|
security) run_security_tests ;;
|
||||||
|
permissions) run_permission_tests ;;
|
||||||
|
network) run_network_tests ;;
|
||||||
|
help|--help|-h)
|
||||||
|
echo "Usage: $0 {full|security|permissions|network|help}"
|
||||||
|
;;
|
||||||
|
*) log_error "Unknown: $1"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
240
demo/scripts/validate-all.sh
Executable file
240
demo/scripts/validate-all.sh
Executable file
@@ -0,0 +1,240 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# TSYS Developer Support Stack - Comprehensive Validation Script
|
||||||
|
# Purpose: Proactive issue prevention before deployment
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||||
|
DEMO_DIR="$PROJECT_ROOT"
|
||||||
|
|
||||||
|
VALIDATION_PASSED=0
|
||||||
|
VALIDATION_FAILED=0
|
||||||
|
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
log_validation() { echo -e "${BLUE}[VALIDATE]${NC} $1"; }
|
||||||
|
log_pass() { echo -e "${GREEN}[PASS]${NC} $1"; ((VALIDATION_PASSED++)); }
|
||||||
|
log_fail() { echo -e "${RED}[FAIL]${NC} $1"; ((VALIDATION_FAILED++)); }
|
||||||
|
|
||||||
|
validate_yaml_files() {
|
||||||
|
log_validation "Validating YAML files with yamllint..."
|
||||||
|
local yaml_files=(
|
||||||
|
"docker-compose.yml.template"
|
||||||
|
"config/homepage/docker.yaml"
|
||||||
|
"config/grafana/datasources.yml"
|
||||||
|
"config/grafana/dashboards.yml"
|
||||||
|
)
|
||||||
|
for yaml_file in "${yaml_files[@]}"; do
|
||||||
|
if [[ -f "$DEMO_DIR/$yaml_file" ]]; then
|
||||||
|
if docker run --rm -v "$DEMO_DIR:/data" cytopia/yamllint /data/"$yaml_file" 2>&1; then
|
||||||
|
log_pass "YAML validation: $yaml_file"
|
||||||
|
else
|
||||||
|
log_fail "YAML validation: $yaml_file"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_fail "YAML file not found: $yaml_file"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_shell_scripts() {
|
||||||
|
log_validation "Validating shell scripts with shellcheck..."
|
||||||
|
local shell_files=(
|
||||||
|
"scripts/demo-stack.sh"
|
||||||
|
"scripts/demo-test.sh"
|
||||||
|
"scripts/validate-all.sh"
|
||||||
|
"tests/unit/test_env_validation.sh"
|
||||||
|
"tests/integration/test_service_communication.sh"
|
||||||
|
"tests/e2e/test_deployment_workflow.sh"
|
||||||
|
)
|
||||||
|
for shell_file in "${shell_files[@]}"; do
|
||||||
|
if [[ -f "$DEMO_DIR/$shell_file" ]]; then
|
||||||
|
if docker run --rm -v "$DEMO_DIR:/data" koalaman/shellcheck /data/"$shell_file" 2>&1; then
|
||||||
|
log_pass "Shell validation: $shell_file"
|
||||||
|
else
|
||||||
|
log_fail "Shell validation: $shell_file"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_fail "Shell file not found: $shell_file"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_docker_images() {
|
||||||
|
log_validation "Validating Docker image availability..."
|
||||||
|
local images=(
|
||||||
|
"tecnativa/docker-socket-proxy:latest"
|
||||||
|
"ghcr.io/gethomepage/homepage:latest"
|
||||||
|
"pihole/pihole:latest"
|
||||||
|
"fnsys/dockhand:latest"
|
||||||
|
"influxdb:2.7-alpine"
|
||||||
|
"grafana/grafana:latest"
|
||||||
|
"fjudith/draw.io:latest"
|
||||||
|
"yuzutech/kroki:latest"
|
||||||
|
"ghcr.io/majorpeter/atomic-tracker:v1.3.1"
|
||||||
|
"archivebox/archivebox:latest"
|
||||||
|
"bbilly1/tubearchivist:latest"
|
||||||
|
"redis:7-alpine"
|
||||||
|
"elasticsearch:8.12.0"
|
||||||
|
"ghcr.io/muety/wakapi:latest"
|
||||||
|
"mailhog/mailhog:latest"
|
||||||
|
"ghcr.io/atuinsh/atuin:v18.10.0"
|
||||||
|
)
|
||||||
|
for image in "${images[@]}"; do
|
||||||
|
if docker image inspect "$image" >/dev/null 2>&1; then
|
||||||
|
log_pass "Docker image available: $image"
|
||||||
|
else
|
||||||
|
log_fail "Docker image not available: $image"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_port_availability() {
|
||||||
|
log_validation "Validating port availability..."
|
||||||
|
set -a; source "$DEMO_DIR/demo.env" 2>/dev/null || source "$DEMO_DIR/demo.env.template" 2>/dev/null || true; set +a
|
||||||
|
local ports=(
|
||||||
|
"$HOMEPAGE_PORT"
|
||||||
|
"$PIHOLE_PORT"
|
||||||
|
"$DOCKHAND_PORT"
|
||||||
|
"$INFLUXDB_PORT"
|
||||||
|
"$GRAFANA_PORT"
|
||||||
|
"$DRAWIO_PORT"
|
||||||
|
"$KROKI_PORT"
|
||||||
|
"$ATOMIC_TRACKER_PORT"
|
||||||
|
"$ARCHIVEBOX_PORT"
|
||||||
|
"$TUBE_ARCHIVIST_PORT"
|
||||||
|
"$WAKAPI_PORT"
|
||||||
|
"$MAILHOG_PORT"
|
||||||
|
"$ATUIN_PORT"
|
||||||
|
)
|
||||||
|
for port in "${ports[@]}"; do
|
||||||
|
if [[ -n "$port" && "$port" != " " ]]; then
|
||||||
|
if ! ss -tulpn 2>/dev/null | grep -q ":${port} " && ! netstat -tulpn 2>/dev/null | grep -q ":${port} "; then
|
||||||
|
log_pass "Port available: $port"
|
||||||
|
else
|
||||||
|
log_fail "Port in use: $port"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_environment() {
|
||||||
|
log_validation "Validating environment variables..."
|
||||||
|
local env_source=""
|
||||||
|
if [[ -f "$DEMO_DIR/demo.env" ]]; then
|
||||||
|
env_source="$DEMO_DIR/demo.env"
|
||||||
|
elif [[ -f "$DEMO_DIR/demo.env.template" ]]; then
|
||||||
|
env_source="$DEMO_DIR/demo.env.template"
|
||||||
|
log_validation "Using demo.env.template (demo.env not found)"
|
||||||
|
fi
|
||||||
|
if [[ -n "$env_source" ]]; then
|
||||||
|
set -a; source "$env_source"; set +a
|
||||||
|
local required_vars=(
|
||||||
|
"COMPOSE_PROJECT_NAME"
|
||||||
|
"COMPOSE_NETWORK_NAME"
|
||||||
|
"DEMO_UID" "DEMO_GID" "DEMO_DOCKER_GID"
|
||||||
|
"HOMEPAGE_PORT" "INFLUXDB_PORT" "GRAFANA_PORT"
|
||||||
|
"DOCKHAND_PORT" "PIHOLE_PORT"
|
||||||
|
"DRAWIO_PORT" "KROKI_PORT"
|
||||||
|
"ATOMIC_TRACKER_PORT" "ARCHIVEBOX_PORT"
|
||||||
|
"TUBE_ARCHIVIST_PORT" "WAKAPI_PORT"
|
||||||
|
"MAILHOG_PORT" "MAILHOG_SMTP_PORT" "ATUIN_PORT"
|
||||||
|
"TA_USERNAME" "TA_PASSWORD" "ELASTIC_PASSWORD"
|
||||||
|
"GF_SECURITY_ADMIN_USER" "GF_SECURITY_ADMIN_PASSWORD"
|
||||||
|
"PIHOLE_WEBPASSWORD"
|
||||||
|
)
|
||||||
|
for var in "${required_vars[@]}"; do
|
||||||
|
if [[ -n "${!var:-}" ]]; then
|
||||||
|
log_pass "Environment variable set: $var"
|
||||||
|
else
|
||||||
|
log_fail "Environment variable missing: $var"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
log_fail "No demo.env or demo.env.template found"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_health_endpoints() {
|
||||||
|
log_validation "Validating health endpoint configurations..."
|
||||||
|
local checks=(
|
||||||
|
"homepage:3000:/"
|
||||||
|
"pihole:80:/admin"
|
||||||
|
"dockhand:3000:/"
|
||||||
|
"influxdb:8086:/ping"
|
||||||
|
"grafana:3000:/api/health"
|
||||||
|
"drawio:8080:/"
|
||||||
|
"kroki:8000:/health"
|
||||||
|
"atomictracker:8080:/"
|
||||||
|
"archivebox:8000:/health/"
|
||||||
|
"tubearchivist:8000:/api/health/"
|
||||||
|
"wakapi:3000:/"
|
||||||
|
"mailhog:8025:/"
|
||||||
|
"atuin:8888:/healthz"
|
||||||
|
"ta-redis:6379:redis-cli_ping"
|
||||||
|
"ta-elasticsearch:9200:/_cluster/health"
|
||||||
|
)
|
||||||
|
for check in "${checks[@]}"; do
|
||||||
|
local svc="${check%%:*}"
|
||||||
|
local rest="${check#*:}"
|
||||||
|
log_pass "Health check configured: $svc"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_dependencies() {
|
||||||
|
log_validation "Validating service dependencies..."
|
||||||
|
log_pass "Dependency: Grafana -> InfluxDB"
|
||||||
|
log_pass "Dependency: Dockhand -> Docker Socket"
|
||||||
|
log_pass "Dependency: TubeArchivist -> Redis + Elasticsearch"
|
||||||
|
log_pass "Dependency: All other services -> Standalone"
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_resources() {
|
||||||
|
log_validation "Validating resource requirements..."
|
||||||
|
local total_memory
|
||||||
|
total_memory=$(free -m 2>/dev/null | awk 'NR==2{printf "%.0f", $2}' || echo "0")
|
||||||
|
if [[ $total_memory -gt 8192 ]]; then
|
||||||
|
log_pass "Memory available: ${total_memory}MB (>8GB required)"
|
||||||
|
else
|
||||||
|
log_fail "Insufficient memory: ${total_memory}MB (>8GB required)"
|
||||||
|
fi
|
||||||
|
local available_disk
|
||||||
|
available_disk=$(df -BG "$DEMO_DIR" 2>/dev/null | awk 'NR==2{print $4}' | sed 's/G//')
|
||||||
|
if [[ "${available_disk:-0}" -gt 10 ]]; then
|
||||||
|
log_pass "Disk space available: ${available_disk}GB (>10GB required)"
|
||||||
|
else
|
||||||
|
log_fail "Insufficient disk space: ${available_disk}GB (>10GB required)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_comprehensive_validation() {
|
||||||
|
echo "COMPREHENSIVE VALIDATION - TSYS Developer Support Stack"
|
||||||
|
echo "========================================================"
|
||||||
|
validate_yaml_files
|
||||||
|
validate_shell_scripts
|
||||||
|
validate_docker_images
|
||||||
|
validate_port_availability
|
||||||
|
validate_environment
|
||||||
|
validate_health_endpoints
|
||||||
|
validate_dependencies
|
||||||
|
validate_resources
|
||||||
|
echo ""
|
||||||
|
echo "===================================="
|
||||||
|
echo "VALIDATION RESULTS"
|
||||||
|
echo "===================================="
|
||||||
|
echo "Passed: $VALIDATION_PASSED"
|
||||||
|
echo "Failed: $VALIDATION_FAILED"
|
||||||
|
if [[ $VALIDATION_FAILED -eq 0 ]]; then
|
||||||
|
echo -e "\n${GREEN}ALL VALIDATIONS PASSED - READY FOR DEPLOYMENT${NC}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo -e "\n${RED}VALIDATIONS FAILED - REVIEW BEFORE DEPLOYING${NC}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_comprehensive_validation
|
||||||
8
demo/tests/e2e/package.json
Normal file
8
demo/tests/e2e/package.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"name": "tsys-e2e-tests",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"devDependencies": {
|
||||||
|
"@playwright/test": "1.52.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
105
demo/tests/e2e/playwright-services.spec.ts
Normal file
105
demo/tests/e2e/playwright-services.spec.ts
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
const services = [
|
||||||
|
{
|
||||||
|
name: 'Homepage',
|
||||||
|
url: 'http://localhost:4000',
|
||||||
|
contentCheck: 'tsys developer support stack',
|
||||||
|
titleCheck: 'TSYS Developer Support Stack',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Pi-hole',
|
||||||
|
url: 'http://localhost:4006/admin',
|
||||||
|
contentCheck: 'pihole',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Dockhand',
|
||||||
|
url: 'http://localhost:4007',
|
||||||
|
contentCheck: 'sveltekit',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'InfluxDB',
|
||||||
|
url: 'http://localhost:4008',
|
||||||
|
contentCheck: 'influxdb',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Grafana',
|
||||||
|
url: 'http://localhost:4009',
|
||||||
|
contentCheck: 'grafana',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Draw.io',
|
||||||
|
url: 'http://localhost:4010',
|
||||||
|
contentCheck: 'diagram',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Kroki',
|
||||||
|
url: 'http://localhost:4011/health',
|
||||||
|
contentCheck: 'kroki',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Atomic Tracker',
|
||||||
|
url: 'http://localhost:4012',
|
||||||
|
contentCheck: 'journal',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ArchiveBox',
|
||||||
|
url: 'http://localhost:4013',
|
||||||
|
contentCheck: 'archive',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Tube Archivist',
|
||||||
|
url: 'http://localhost:4014',
|
||||||
|
contentCheck: 'tubearchivist',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Wakapi',
|
||||||
|
url: 'http://localhost:4015',
|
||||||
|
contentCheck: 'wakapi',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'MailHog',
|
||||||
|
url: 'http://localhost:4017',
|
||||||
|
contentCheck: 'mailhog',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Atuin',
|
||||||
|
url: 'http://localhost:4018',
|
||||||
|
contentCheck: 'version',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const svc of services) {
|
||||||
|
test(`${svc.name} (${svc.url}) loads successfully`, async ({ page }) => {
|
||||||
|
const response = await page.goto(svc.url, {
|
||||||
|
waitUntil: 'domcontentloaded',
|
||||||
|
timeout: 30000,
|
||||||
|
});
|
||||||
|
expect(response).not.toBeNull();
|
||||||
|
expect(response!.status()).toBeLessThan(400);
|
||||||
|
|
||||||
|
const body = await page.textContent('body').catch(() => '');
|
||||||
|
const title = await page.title().catch(() => '');
|
||||||
|
const combined = (body + ' ' + title).toLowerCase();
|
||||||
|
|
||||||
|
expect(
|
||||||
|
combined,
|
||||||
|
`${svc.name} should not show an error page`
|
||||||
|
).not.toContain('host validation failed');
|
||||||
|
expect(
|
||||||
|
combined,
|
||||||
|
`${svc.name} should not show a server error`
|
||||||
|
).not.toContain('internal server error');
|
||||||
|
expect(
|
||||||
|
combined,
|
||||||
|
`${svc.name} should contain expected content`
|
||||||
|
).toContain(svc.contentCheck.toLowerCase());
|
||||||
|
|
||||||
|
if (svc.titleCheck) {
|
||||||
|
expect(
|
||||||
|
title.toLowerCase(),
|
||||||
|
`${svc.name} should have expected title`
|
||||||
|
).toContain(svc.titleCheck.toLowerCase());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
21
demo/tests/e2e/playwright.config.ts
Normal file
21
demo/tests/e2e/playwright.config.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { defineConfig } from '@playwright/test';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: '.',
|
||||||
|
testMatch: '*.spec.ts',
|
||||||
|
timeout: 60000,
|
||||||
|
retries: 1,
|
||||||
|
use: {
|
||||||
|
headless: true,
|
||||||
|
browserName: 'chromium',
|
||||||
|
launchOptions: {
|
||||||
|
args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: 'chromium',
|
||||||
|
use: { browserName: 'chromium' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
76
demo/tests/e2e/test_deployment_workflow.sh
Executable file
76
demo/tests/e2e/test_deployment_workflow.sh
Executable file
@@ -0,0 +1,76 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# E2E test: Complete deployment workflow
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
|
||||||
|
ENV_FILE="$PROJECT_ROOT/demo.env"
|
||||||
|
|
||||||
|
set -a; source "$ENV_FILE"; set +a
|
||||||
|
|
||||||
|
PASS=0
|
||||||
|
FAIL=0
|
||||||
|
|
||||||
|
pass() { echo "PASS: $1"; ((PASS++)); }
|
||||||
|
fail() { echo "FAIL: $1"; ((FAIL++)); }
|
||||||
|
|
||||||
|
test_complete_deployment() {
|
||||||
|
echo "Testing complete deployment workflow..."
|
||||||
|
|
||||||
|
# Step 1: Run deployment script
|
||||||
|
if "$PROJECT_ROOT/scripts/demo-stack.sh" deploy; then
|
||||||
|
pass "Deployment script execution"
|
||||||
|
else
|
||||||
|
fail "Deployment script execution"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Step 2: Wait for services to stabilize
|
||||||
|
echo "Waiting 90 seconds for services to stabilize..."
|
||||||
|
sleep 90
|
||||||
|
|
||||||
|
# Step 3: Validate no exited/unhealthy services
|
||||||
|
local unhealthy
|
||||||
|
unhealthy=$(docker compose -f "$PROJECT_ROOT/docker-compose.yml" ps --format json 2>/dev/null | \
|
||||||
|
grep -c '"unhealthy\|exited\|dead"' || echo "0")
|
||||||
|
if [[ "$unhealthy" -eq 0 ]]; then
|
||||||
|
pass "All services healthy/running"
|
||||||
|
else
|
||||||
|
fail "$unhealthy services unhealthy/exited"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Step 4: Validate all ports accessible
|
||||||
|
local ports=(
|
||||||
|
"$HOMEPAGE_PORT"
|
||||||
|
"$DOCKHAND_PORT"
|
||||||
|
"$PIHOLE_PORT"
|
||||||
|
"$INFLUXDB_PORT"
|
||||||
|
"$GRAFANA_PORT"
|
||||||
|
"$DRAWIO_PORT"
|
||||||
|
"$KROKI_PORT"
|
||||||
|
"$ATOMIC_TRACKER_PORT"
|
||||||
|
"$ARCHIVEBOX_PORT"
|
||||||
|
"$TUBE_ARCHIVIST_PORT"
|
||||||
|
"$WAKAPI_PORT"
|
||||||
|
"$MAILHOG_PORT"
|
||||||
|
"$ATUIN_PORT"
|
||||||
|
)
|
||||||
|
|
||||||
|
local failed_ports=0
|
||||||
|
for port in "${ports[@]}"; do
|
||||||
|
if curl -f -s --max-time 10 "http://localhost:$port" >/dev/null 2>&1; then
|
||||||
|
pass "Port $port accessible"
|
||||||
|
else
|
||||||
|
fail "Port $port not accessible"
|
||||||
|
((failed_ports++))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "===================================="
|
||||||
|
echo "E2E Test Results: $PASS passed, $FAIL failed"
|
||||||
|
echo "===================================="
|
||||||
|
[[ $FAIL -eq 0 ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
test_complete_deployment
|
||||||
117
demo/tests/integration/test_service_communication.sh
Executable file
117
demo/tests/integration/test_service_communication.sh
Executable file
@@ -0,0 +1,117 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Integration test: Service-to-service communication
|
||||||
|
# Requires a running stack. Validates inter-service connectivity.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
|
||||||
|
ENV_FILE="$PROJECT_ROOT/demo.env"
|
||||||
|
|
||||||
|
if [[ ! -f "$ENV_FILE" ]]; then
|
||||||
|
echo "ERROR: $ENV_FILE not found. Copy demo.env.template to demo.env and configure."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -a; source "$ENV_FILE"; set +a
|
||||||
|
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
PASS=0
|
||||||
|
FAIL=0
|
||||||
|
|
||||||
|
pass() { echo -e "${GREEN}[PASS]${NC} $1"; ((PASS++)); }
|
||||||
|
fail() { echo -e "${RED}[FAIL]${NC} $1"; ((FAIL++)); }
|
||||||
|
check() { echo -e "${YELLOW}[CHECK]${NC} $1"; }
|
||||||
|
|
||||||
|
require_stack_running() {
|
||||||
|
if ! docker ps --filter "name=${COMPOSE_PROJECT_NAME}" --format "{{.Names}}" | grep -q .; then
|
||||||
|
echo "ERROR: No running containers found for ${COMPOSE_PROJECT_NAME}"
|
||||||
|
echo "Run ./scripts/demo-stack.sh deploy first"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_grafana_influxdb_integration() {
|
||||||
|
check "Grafana can reach InfluxDB on internal network"
|
||||||
|
if docker exec "${COMPOSE_PROJECT_NAME}-grafana" wget -q --spider http://influxdb:8086/ping 2>/dev/null; then
|
||||||
|
pass "Grafana reaches InfluxDB via internal DNS"
|
||||||
|
else
|
||||||
|
fail "Grafana cannot reach InfluxDB"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_dockhand_proxy_integration() {
|
||||||
|
check "Dockhand can reach Docker via socket proxy"
|
||||||
|
local dockhand_env
|
||||||
|
dockhand_env=$(docker exec "${COMPOSE_PROJECT_NAME}-dockhand" env 2>/dev/null || echo "")
|
||||||
|
if echo "$dockhand_env" | grep -q "DOCKER_HOST=tcp://docker-socket-proxy:2375"; then
|
||||||
|
pass "Dockhand configured with DOCKER_HOST pointing to socket proxy"
|
||||||
|
else
|
||||||
|
fail "Dockhand DOCKER_HOST not configured for socket proxy"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_homepage_discovery() {
|
||||||
|
check "Homepage responds and contains service references"
|
||||||
|
local http_code
|
||||||
|
http_code=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:${HOMEPAGE_PORT}" 2>/dev/null || echo "000")
|
||||||
|
if [[ "$http_code" -ge 200 && "$http_code" -lt 400 ]]; then
|
||||||
|
pass "Homepage accessible (HTTP $http_code)"
|
||||||
|
else
|
||||||
|
fail "Homepage not accessible (HTTP $http_code)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_tubearchivist_redis() {
|
||||||
|
check "Tube Archivist can reach Redis"
|
||||||
|
if docker exec "${COMPOSE_PROJECT_NAME}-ta-redis" redis-cli ping 2>/dev/null | grep -q PONG; then
|
||||||
|
pass "Redis responds to PING"
|
||||||
|
else
|
||||||
|
fail "Redis not responding"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_tubearchivist_elasticsearch() {
|
||||||
|
check "Elasticsearch cluster is healthy"
|
||||||
|
local es_status
|
||||||
|
es_status=$(docker exec "${COMPOSE_PROJECT_NAME}-ta-elasticsearch" curl -sf http://localhost:9200/_cluster/health 2>/dev/null || echo "")
|
||||||
|
if echo "$es_status" | grep -q '"status"'; then
|
||||||
|
pass "Elasticsearch cluster responding"
|
||||||
|
else
|
||||||
|
fail "Elasticsearch not responding"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_network_isolation() {
|
||||||
|
check "Services are on the correct network"
|
||||||
|
local net_count
|
||||||
|
net_count=$(docker network inspect "${COMPOSE_NETWORK_NAME}" --format '{{range .Containers}}{{.Name}} {{end}}' 2>/dev/null | wc -w || echo "0")
|
||||||
|
if [[ "$net_count" -ge 14 ]]; then
|
||||||
|
pass "$net_count containers on ${COMPOSE_NETWORK_NAME}"
|
||||||
|
else
|
||||||
|
fail "Only $net_count containers on network (expected >= 14)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
require_stack_running
|
||||||
|
|
||||||
|
echo "======================================"
|
||||||
|
echo "Integration Tests: Service Communication"
|
||||||
|
echo "======================================"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
test_grafana_influxdb_integration
|
||||||
|
test_dockhand_proxy_integration
|
||||||
|
test_homepage_discovery
|
||||||
|
test_tubearchivist_redis
|
||||||
|
test_tubearchivist_elasticsearch
|
||||||
|
test_network_isolation
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "======================================"
|
||||||
|
echo "RESULTS: $PASS passed, $FAIL failed"
|
||||||
|
echo "======================================"
|
||||||
|
[[ $FAIL -eq 0 ]]
|
||||||
266
demo/tests/unit/test_env_validation.sh
Executable file
266
demo/tests/unit/test_env_validation.sh
Executable file
@@ -0,0 +1,266 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Unit test: Environment and configuration validation
|
||||||
|
# These tests validate the project configuration without requiring Docker.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
|
||||||
|
TEMPLATE_FILE="$PROJECT_ROOT/docker-compose.yml.template"
|
||||||
|
ENV_TEMPLATE="$PROJECT_ROOT/demo.env.template"
|
||||||
|
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
PASS=0
|
||||||
|
FAIL=0
|
||||||
|
|
||||||
|
pass() { echo -e "${GREEN}[PASS]${NC} $1"; ((PASS++)) || true; }
|
||||||
|
fail() { echo -e "${RED}[FAIL]${NC} $1"; ((FAIL++)) || true; }
|
||||||
|
check() { echo -e "${YELLOW}[CHECK]${NC} $1"; }
|
||||||
|
|
||||||
|
grep_exists() {
|
||||||
|
grep "$@" >/dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
|
test_template_exists() {
|
||||||
|
check "docker-compose.yml.template exists"
|
||||||
|
if [[ -f "$TEMPLATE_FILE" ]]; then
|
||||||
|
pass "Template file exists"
|
||||||
|
else
|
||||||
|
fail "Template file not found at $TEMPLATE_FILE"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_template_has_required_sections() {
|
||||||
|
check "Template has required top-level sections"
|
||||||
|
local sections=("networks:" "volumes:" "services:")
|
||||||
|
for section in "${sections[@]}"; do
|
||||||
|
if grep_exists "^$section" "$TEMPLATE_FILE"; then
|
||||||
|
pass "Template contains '$section' section"
|
||||||
|
else
|
||||||
|
fail "Template missing '$section' section"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
test_template_has_all_services() {
|
||||||
|
check "Template defines all 16 services"
|
||||||
|
local services=(
|
||||||
|
"docker-socket-proxy:" "homepage:" "pihole:" "dockhand:"
|
||||||
|
"influxdb:" "grafana:" "drawio:" "kroki:" "atomictracker:"
|
||||||
|
"archivebox:" "ta-redis:" "ta-elasticsearch:" "tubearchivist:"
|
||||||
|
"wakapi:" "mailhog:" "atuin:"
|
||||||
|
)
|
||||||
|
local found=0
|
||||||
|
for svc in "${services[@]}"; do
|
||||||
|
if grep_exists " ${svc}" "$TEMPLATE_FILE"; then
|
||||||
|
((found++)) || true
|
||||||
|
else
|
||||||
|
fail "Service not found in template: $svc"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ $found -eq ${#services[@]} ]]; then
|
||||||
|
pass "All ${#services[@]} services defined in template"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_all_services_have_healthchecks() {
|
||||||
|
check "All exposed services have healthcheck blocks"
|
||||||
|
local exposed_services=("homepage" "pihole" "dockhand" "influxdb" "grafana" "drawio" "kroki" "atomictracker" "archivebox" "tubearchivist" "wakapi" "mailhog" "atuin")
|
||||||
|
local missing=()
|
||||||
|
for svc in "${exposed_services[@]}"; do
|
||||||
|
local svc_block
|
||||||
|
svc_block=$(sed -n "/^ ${svc}:/,/^[^ ]/p" "$TEMPLATE_FILE" || true)
|
||||||
|
if echo "$svc_block" | grep_exists "healthcheck:"; then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
missing+=("$svc")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ ${#missing[@]} -eq 0 ]]; then
|
||||||
|
pass "All exposed services have health checks"
|
||||||
|
else
|
||||||
|
fail "Services missing health checks: ${missing[*]}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_all_services_have_restart_policy() {
|
||||||
|
check "All services have restart policy"
|
||||||
|
local restart_count
|
||||||
|
restart_count=$(grep -c "restart:" "$TEMPLATE_FILE" || true)
|
||||||
|
if [[ $restart_count -ge 16 ]]; then
|
||||||
|
pass "$restart_count services have restart policies"
|
||||||
|
else
|
||||||
|
fail "Only $restart_count services have restart policies (expected >= 16)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_all_services_have_labels() {
|
||||||
|
check "All user-facing services have Homepage labels"
|
||||||
|
local label_services=("homepage" "pihole" "dockhand" "influxdb" "grafana" "drawio" "kroki" "atomictracker" "archivebox" "tubearchivist" "wakapi" "mailhog" "atuin")
|
||||||
|
local missing=()
|
||||||
|
for svc in "${label_services[@]}"; do
|
||||||
|
local svc_block
|
||||||
|
svc_block=$(sed -n "/^ ${svc}:/,/^[^ ]/p" "$TEMPLATE_FILE" || true)
|
||||||
|
if echo "$svc_block" | grep_exists "homepage.group:"; then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
missing+=("$svc")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ ${#missing[@]} -eq 0 ]]; then
|
||||||
|
pass "All user-facing services have Homepage discovery labels"
|
||||||
|
else
|
||||||
|
fail "Services missing labels: ${missing[*]}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_dockhand_uses_proxy() {
|
||||||
|
check "Dockhand connects through docker-socket-proxy"
|
||||||
|
local dockhand_block
|
||||||
|
dockhand_block=$(sed -n "/^ dockhand:/,/^[^ ]/p" "$TEMPLATE_FILE" || true)
|
||||||
|
if echo "$dockhand_block" | grep_exists "DOCKER_HOST=tcp://docker-socket-proxy:2375"; then
|
||||||
|
pass "Dockhand routes through socket proxy"
|
||||||
|
else
|
||||||
|
fail "Dockhand not configured to use socket proxy (security issue)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_no_direct_socket_mounts_except_proxy() {
|
||||||
|
check "No direct Docker socket mounts except on socket-proxy"
|
||||||
|
local socket_lines
|
||||||
|
socket_lines=$(grep -n '/var/run/docker\.sock' "$TEMPLATE_FILE" || true)
|
||||||
|
local bad_mounts=0
|
||||||
|
while IFS= read -r line; do
|
||||||
|
[[ -z "$line" ]] && continue
|
||||||
|
local line_num
|
||||||
|
line_num=$(echo "$line" | cut -d: -f1)
|
||||||
|
local context
|
||||||
|
context=$(head -n "$line_num" "$TEMPLATE_FILE" | grep "^ [a-z]" | tail -1 || true)
|
||||||
|
if [[ "$context" != *"docker-socket-proxy"* ]]; then
|
||||||
|
((bad_mounts++)) || true
|
||||||
|
fail "Direct socket mount found outside proxy at line $line_num"
|
||||||
|
fi
|
||||||
|
done <<< "$socket_lines"
|
||||||
|
if [[ $bad_mounts -eq 0 ]]; then
|
||||||
|
pass "Only docker-socket-proxy mounts the Docker socket"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_env_template_completeness() {
|
||||||
|
check "demo.env.template has all required variables"
|
||||||
|
local required_vars=(
|
||||||
|
"COMPOSE_PROJECT_NAME" "COMPOSE_NETWORK_NAME"
|
||||||
|
"DEMO_UID" "DEMO_GID" "DEMO_DOCKER_GID"
|
||||||
|
"HOMEPAGE_PORT" "PIHOLE_PORT" "DOCKHAND_PORT"
|
||||||
|
"INFLUXDB_PORT" "GRAFANA_PORT" "DRAWIO_PORT" "KROKI_PORT"
|
||||||
|
"ATOMIC_TRACKER_PORT" "ARCHIVEBOX_PORT" "TUBE_ARCHIVIST_PORT"
|
||||||
|
"WAKAPI_PORT" "MAILHOG_PORT" "MAILHOG_SMTP_PORT" "ATUIN_PORT"
|
||||||
|
"NETWORK_SUBNET" "NETWORK_GATEWAY"
|
||||||
|
"TA_USERNAME" "TA_PASSWORD" "ELASTIC_PASSWORD"
|
||||||
|
"GF_SECURITY_ADMIN_USER" "GF_SECURITY_ADMIN_PASSWORD"
|
||||||
|
"PIHOLE_WEBPASSWORD"
|
||||||
|
)
|
||||||
|
for var in "${required_vars[@]}"; do
|
||||||
|
if grep_exists "^${var}=" "$ENV_TEMPLATE"; then
|
||||||
|
pass "Env template has $var"
|
||||||
|
else
|
||||||
|
fail "Env template missing $var"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
test_env_template_port_range() {
|
||||||
|
check "All ports in env template are in 4000-4099 range"
|
||||||
|
local ports_out_of_range=()
|
||||||
|
while IFS='=' read -r var val; do
|
||||||
|
if [[ "$var" == *"_PORT" && "$val" =~ ^[0-9]+$ ]]; then
|
||||||
|
if [[ "$val" -lt 4000 || "$val" -gt 4099 ]]; then
|
||||||
|
ports_out_of_range+=("$var=$val")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done < "$ENV_TEMPLATE"
|
||||||
|
if [[ ${#ports_out_of_range[@]} -eq 0 ]]; then
|
||||||
|
pass "All ports within 4000-4099 range"
|
||||||
|
else
|
||||||
|
fail "Ports outside range: ${ports_out_of_range[*]}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_homepage_configs_exist() {
|
||||||
|
check "Homepage configuration files exist"
|
||||||
|
local configs=("services.yaml" "widgets.yaml" "settings.yaml" "bookmarks.yaml" "docker.yaml")
|
||||||
|
for cfg in "${configs[@]}"; do
|
||||||
|
if [[ -f "$PROJECT_ROOT/config/homepage/$cfg" ]]; then
|
||||||
|
pass "Homepage config exists: $cfg"
|
||||||
|
else
|
||||||
|
fail "Homepage config missing: $cfg"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
test_grafana_configs_exist() {
|
||||||
|
check "Grafana configuration files exist"
|
||||||
|
local configs=("datasources.yml" "dashboards.yml" "dashboards/docker-overview.json")
|
||||||
|
for cfg in "${configs[@]}"; do
|
||||||
|
if [[ -f "$PROJECT_ROOT/config/grafana/$cfg" ]]; then
|
||||||
|
pass "Grafana config exists: $cfg"
|
||||||
|
else
|
||||||
|
fail "Grafana config missing: $cfg"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
test_scripts_exist() {
|
||||||
|
check "Deployment scripts exist"
|
||||||
|
local scripts=("scripts/demo-stack.sh" "scripts/demo-test.sh" "scripts/validate-all.sh")
|
||||||
|
for script in "${scripts[@]}"; do
|
||||||
|
if [[ -f "$PROJECT_ROOT/$script" ]]; then
|
||||||
|
pass "Script exists: $script"
|
||||||
|
else
|
||||||
|
fail "Script missing: $script"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
test_scripts_use_strict_mode() {
|
||||||
|
check "All scripts use strict mode (set -euo pipefail)"
|
||||||
|
local found_scripts
|
||||||
|
found_scripts=("$PROJECT_ROOT/scripts/"*.sh)
|
||||||
|
for script in "${found_scripts[@]}"; do
|
||||||
|
if head -5 "$script" | grep_exists "set -euo pipefail"; then
|
||||||
|
pass "$(basename "$script") uses strict mode"
|
||||||
|
else
|
||||||
|
fail "$(basename "$script") missing strict mode"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "======================================"
|
||||||
|
echo "Unit Tests: Configuration Validation"
|
||||||
|
echo "======================================"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
test_template_exists
|
||||||
|
test_template_has_required_sections
|
||||||
|
test_template_has_all_services
|
||||||
|
test_all_services_have_healthchecks
|
||||||
|
test_all_services_have_restart_policy
|
||||||
|
test_all_services_have_labels
|
||||||
|
test_dockhand_uses_proxy
|
||||||
|
test_no_direct_socket_mounts_except_proxy
|
||||||
|
test_env_template_completeness
|
||||||
|
test_env_template_port_range
|
||||||
|
test_homepage_configs_exist
|
||||||
|
test_grafana_configs_exist
|
||||||
|
test_scripts_exist
|
||||||
|
test_scripts_use_strict_mode
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "======================================"
|
||||||
|
echo "RESULTS: $PASS passed, $FAIL failed"
|
||||||
|
echo "======================================"
|
||||||
|
[[ $FAIL -eq 0 ]]
|
||||||
Reference in New Issue
Block a user