diff --git a/DOCKER.md b/.docker/README.md
similarity index 56%
rename from DOCKER.md
rename to .docker/README.md
index c904d85e..ae05f2d0 100644
--- a/DOCKER.md
+++ b/.docker/README.md
@@ -2,6 +2,20 @@
Charon is designed for Docker-first deployment, making it easy for home users to run Caddy without learning Caddyfile syntax.
+## Directory Structure
+
+```text
+.docker/
+├── compose/ # Docker Compose files
+│ ├── docker-compose.yml # Main production compose
+│ ├── docker-compose.dev.yml # Development overrides
+│ ├── docker-compose.local.yml # Local development
+│ ├── docker-compose.remote.yml # Remote deployment
+│ └── docker-compose.override.yml # Personal overrides (gitignored)
+├── docker-entrypoint.sh # Container entrypoint script
+└── README.md # This file
+```
+
## Quick Start
```bash
@@ -9,13 +23,31 @@ Charon is designed for Docker-first deployment, making it easy for home users to
git clone https://github.com/Wikid82/charon.git
cd charon
-# Start the stack
-docker-compose up -d
+# Start the stack (using new location)
+docker compose -f .docker/compose/docker-compose.yml up -d
# Access the UI
open http://localhost:8080
```
+## Usage
+
+When running docker-compose commands, specify the compose file location:
+
+```bash
+# Production
+docker compose -f .docker/compose/docker-compose.yml up -d
+
+# Development
+docker compose -f .docker/compose/docker-compose.yml -f .docker/compose/docker-compose.dev.yml up -d
+
+# Local development
+docker compose -f .docker/compose/docker-compose.local.yml up -d
+
+# With personal overrides
+docker compose -f .docker/compose/docker-compose.yml -f .docker/compose/docker-compose.override.yml up -d
+```
+
## Architecture
Charon runs as a **single container** that includes:
@@ -26,7 +58,7 @@ Charon runs as a **single container** that includes:
This unified architecture simplifies deployment, updates, and data management.
-```
+```text
┌──────────────────────────────────────────┐
│ Container (charon / cpmp) │
│ │
@@ -59,8 +91,8 @@ Configure the application via `docker-compose.yml`:
| Variable | Default | Description |
|----------|---------|-------------|
- | `CHARON_ENV` | `production` | Set to `development` for verbose logging (`CPM_ENV` supported for backward compatibility). |
- | `CHARON_HTTP_PORT` | `8080` | Port for the Web UI (`CPM_HTTP_PORT` supported for backward compatibility). |
+| `CHARON_ENV` | `production` | Set to `development` for verbose logging (`CPM_ENV` supported for backward compatibility). |
+| `CHARON_HTTP_PORT` | `8080` | Port for the Web UI (`CPM_HTTP_PORT` supported for backward compatibility). |
| `CHARON_DB_PATH` | `/app/data/charon.db` | Path to the SQLite database (`CPM_DB_PATH` supported for backward compatibility). |
| `CHARON_CADDY_ADMIN_API` | `http://localhost:2019` | Internal URL for Caddy API (`CPM_CADDY_ADMIN_API` supported for backward compatibility). |
@@ -71,31 +103,31 @@ Configure the application via `docker-compose.yml`:
1. **Prepare Folders**: Create a folder `docker/charon` (or `docker/cpmp` for backward compatibility) and subfolders `data`, `caddy_data`, and `caddy_config`.
2. **Download Image**: Search for `ghcr.io/wikid82/charon` in the Registry and download the `latest` tag.
3. **Launch Container**:
- * **Network**: Use `Host` mode (recommended for Caddy to see real client IPs) OR bridge mode mapping ports `80:80`, `443:443`, and `8080:8080`.
- * **Volume Settings**:
- * `/docker/charon/data` -> `/app/data` (or `/docker/cpmp/data` -> `/app/data` for backward compatibility)
- * `/docker/charon/caddy_data` -> `/data` (or `/docker/cpmp/caddy_data` -> `/data` for backward compatibility)
- * `/docker/charon/caddy_config` -> `/config` (or `/docker/cpmp/caddy_config` -> `/config` for backward compatibility)
- * **Environment**: Add `CHARON_ENV=production` (or `CPM_ENV=production` for backward compatibility).
+ - **Network**: Use `Host` mode (recommended for Caddy to see real client IPs) OR bridge mode mapping ports `80:80`, `443:443`, and `8080:8080`.
+ - **Volume Settings**:
+ - `/docker/charon/data` -> `/app/data` (or `/docker/cpmp/data` -> `/app/data` for backward compatibility)
+ - `/docker/charon/caddy_data` -> `/data` (or `/docker/cpmp/caddy_data` -> `/data` for backward compatibility)
+ - `/docker/charon/caddy_config` -> `/config` (or `/docker/cpmp/caddy_config` -> `/config` for backward compatibility)
+ - **Environment**: Add `CHARON_ENV=production` (or `CPM_ENV=production` for backward compatibility).
4. **Finish**: Start the container and access `http://YOUR_NAS_IP:8080`.
### Unraid
1. **Community Apps**: (Coming Soon) Search for "charon".
2. **Manual Install**:
- * Click **Add Container**.
- * **Name**: Charon
- * **Repository**: `ghcr.io/wikid82/charon:latest`
- * **Network Type**: Bridge
- * **WebUI**: `http://[IP]:[PORT:8080]`
- * **Port mappings**:
- * Container Port: `80` -> Host Port: `80`
- * Container Port: `443` -> Host Port: `443`
- * Container Port: `8080` -> Host Port: `8080`
- * **Paths**:
- * `/mnt/user/appdata/charon/data` -> `/app/data` (or `/mnt/user/appdata/cpmp/data` -> `/app/data` for backward compatibility)
- * `/mnt/user/appdata/charon/caddy_data` -> `/data` (or `/mnt/user/appdata/cpmp/caddy_data` -> `/data` for backward compatibility)
- * `/mnt/user/appdata/charon/caddy_config` -> `/config` (or `/mnt/user/appdata/cpmp/caddy_config` -> `/config` for backward compatibility)
+ - Click **Add Container**.
+ - **Name**: Charon
+ - **Repository**: `ghcr.io/wikid82/charon:latest`
+ - **Network Type**: Bridge
+ - **WebUI**: `http://[IP]:[PORT:8080]`
+ - **Port mappings**:
+ - Container Port: `80` -> Host Port: `80`
+ - Container Port: `443` -> Host Port: `443`
+ - Container Port: `8080` -> Host Port: `8080`
+ - **Paths**:
+ - `/mnt/user/appdata/charon/data` -> `/app/data` (or `/mnt/user/appdata/cpmp/data` -> `/app/data` for backward compatibility)
+ - `/mnt/user/appdata/charon/caddy_data` -> `/data` (or `/mnt/user/appdata/cpmp/caddy_data` -> `/data` for backward compatibility)
+ - `/mnt/user/appdata/charon/caddy_config` -> `/config` (or `/mnt/user/appdata/cpmp/caddy_config` -> `/config` for backward compatibility)
3. **Apply**: Click Done to pull and start.
## Troubleshooting
@@ -107,7 +139,7 @@ Configure the application via `docker-compose.yml`:
**Solution**: Since both run in the same container, this usually means Caddy failed to start. Check logs:
```bash
-docker-compose logs app
+docker compose -f .docker/compose/docker-compose.yml logs app
```
### Certificates not working
@@ -118,7 +150,7 @@ docker-compose logs app
1. Port 80/443 are accessible from the internet
2. DNS points to your server
-3. Caddy logs: `docker-compose logs app | grep -i acme`
+3. Caddy logs: `docker compose -f .docker/compose/docker-compose.yml logs app | grep -i acme`
### Config changes not applied
@@ -131,7 +163,7 @@ docker-compose logs app
curl http://localhost:2019/config/ | jq
# Check Charon logs
-docker-compose logs app
+docker compose -f .docker/compose/docker-compose.yml logs app
# Manual config reload
curl -X POST http://localhost:8080/api/v1/caddy/reload
@@ -142,8 +174,8 @@ curl -X POST http://localhost:8080/api/v1/caddy/reload
Pull the latest images and restart:
```bash
-docker-compose pull
-docker-compose up -d
+docker compose -f .docker/compose/docker-compose.yml pull
+docker compose -f .docker/compose/docker-compose.yml up -d
```
For specific versions:
@@ -152,7 +184,7 @@ For specific versions:
# Edit docker-compose.yml to pin version
image: ghcr.io/wikid82/charon:v1.0.0
-docker-compose up -d
+docker compose -f .docker/compose/docker-compose.yml up -d
```
## Building from Source
@@ -199,9 +231,16 @@ services:
memory: 256M
```
+## Important Notes
+
+- **Override Location Change**: The `docker-compose.override.yml` file has moved from
+ the project root to `.docker/compose/`. Update your local workflows accordingly.
+- Personal override files (`.docker/compose/docker-compose.override.yml`) are gitignored
+ and should contain machine-specific configurations only.
+
## Next Steps
-* Configure your first proxy host via UI
-* Enable automatic HTTPS (happens automatically)
-* Add authentication (Issue #7)
-* Integrate CrowdSec (Issue #15)
+- Configure your first proxy host via UI
+- Enable automatic HTTPS (happens automatically)
+- Add authentication (Issue #7)
+- Integrate CrowdSec (Issue #15)
diff --git a/.docker/compose/README.md b/.docker/compose/README.md
new file mode 100644
index 00000000..fcb7a990
--- /dev/null
+++ b/.docker/compose/README.md
@@ -0,0 +1,50 @@
+# Docker Compose Files
+
+This directory contains all Docker Compose configuration variants for Charon.
+
+## File Descriptions
+
+| File | Purpose |
+|------|---------|
+| `docker-compose.yml` | Main production compose configuration. Base services and production settings. |
+| `docker-compose.dev.yml` | Development overrides. Enables hot-reload, debug logging, and development tools. |
+| `docker-compose.local.yml` | Local development configuration. Standalone setup for local testing. |
+| `docker-compose.remote.yml` | Remote deployment configuration. Settings for deploying to remote servers. |
+| `docker-compose.override.yml` | Personal local overrides. **Gitignored** - use for machine-specific settings. |
+
+## Usage Patterns
+
+### Production Deployment
+
+```bash
+docker compose -f .docker/compose/docker-compose.yml up -d
+```
+
+### Development Mode
+
+```bash
+docker compose -f .docker/compose/docker-compose.yml \
+ -f .docker/compose/docker-compose.dev.yml up -d
+```
+
+### Local Testing
+
+```bash
+docker compose -f .docker/compose/docker-compose.local.yml up -d
+```
+
+### With Personal Overrides
+
+Create your own `docker-compose.override.yml` in this directory for personal
+configurations (port mappings, volume paths, etc.). This file is gitignored.
+
+```bash
+docker compose -f .docker/compose/docker-compose.yml \
+ -f .docker/compose/docker-compose.override.yml up -d
+```
+
+## Notes
+
+- Always use the `-f` flag to specify compose file paths from the project root
+- The override file is automatically ignored by git - do not commit personal settings
+- See project tasks in VS Code for convenient pre-configured commands
diff --git a/docker-compose.dev.yml b/.docker/compose/docker-compose.dev.yml
similarity index 100%
rename from docker-compose.dev.yml
rename to .docker/compose/docker-compose.dev.yml
diff --git a/docker-compose.local.yml b/.docker/compose/docker-compose.local.yml
similarity index 100%
rename from docker-compose.local.yml
rename to .docker/compose/docker-compose.local.yml
diff --git a/docker-compose.remote.yml b/.docker/compose/docker-compose.remote.yml
similarity index 100%
rename from docker-compose.remote.yml
rename to .docker/compose/docker-compose.remote.yml
diff --git a/docker-compose.yml b/.docker/compose/docker-compose.yml
similarity index 100%
rename from docker-compose.yml
rename to .docker/compose/docker-compose.yml
diff --git a/docker-entrypoint.sh b/.docker/docker-entrypoint.sh
similarity index 100%
rename from docker-entrypoint.sh
rename to .docker/docker-entrypoint.sh
diff --git a/.dockerignore b/.dockerignore
index 6e504097..c3be57d0 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -138,6 +138,8 @@ docs/
# -----------------------------------------------------------------------------
docker-compose*.yml
**/Dockerfile.*
+.docker/compose/
+docs/implementation/
# -----------------------------------------------------------------------------
# GoReleaser & dist artifacts
diff --git a/.github/instructions/structure.instructions.md b/.github/instructions/structure.instructions.md
new file mode 100644
index 00000000..777f4bf7
--- /dev/null
+++ b/.github/instructions/structure.instructions.md
@@ -0,0 +1,94 @@
+---
+applyTo: '*'
+description: 'Repository structure guidelines to maintain organized file placement'
+---
+
+# Repository Structure Guidelines
+
+## Root Level Rules
+
+The repository root should contain ONLY:
+
+- Essential config files (`.gitignore`, `.pre-commit-config.yaml`, `Makefile`, etc.)
+- Standard project files (`README.md`, `CONTRIBUTING.md`, `LICENSE`, `CHANGELOG.md`)
+- Go workspace files (`go.work`, `go.work.sum`)
+- VS Code workspace (`Chiron.code-workspace`)
+- Primary `Dockerfile` (entrypoint and compose files live in `.docker/`)
+
+## File Placement Rules
+
+### Implementation/Feature Documentation
+
+- **Location**: `docs/implementation/`
+- **Pattern**: `*_SUMMARY.md`, `*_IMPLEMENTATION.md`, `*_COMPLETE.md`, `*_FEATURE.md`
+- **Never** place implementation docs at root
+
+### Docker Compose Files
+
+- **Location**: `.docker/compose/`
+- **Files**: `docker-compose.yml`, `docker-compose.*.yml`
+- **Override**: Local overrides go in `.docker/compose/docker-compose.override.yml` (gitignored)
+- **Exception**: `docker-compose.override.yml` at root is allowed for backward compatibility
+
+### Docker Support Files
+
+- **Location**: `.docker/`
+- **Files**: `docker-entrypoint.sh`, Docker documentation (`README.md`)
+
+### Test Artifacts
+
+- **Never commit**: `*.sarif`, `*_test.txt`, `*.cover` files at root
+- **Location**: Test outputs should go to `test-results/` or be gitignored
+
+### Debug/Temp Config Files
+
+- **Never commit**: Temporary JSON configs like `caddy_*.json` at root
+- **Location**: Use `configs/` for persistent configs, gitignore temp files
+
+### Scripts
+
+- **Location**: `scripts/` for general scripts
+- **Location**: `.github/skills/scripts/` for agent skill scripts
+
+## Before Creating New Files
+
+Ask yourself:
+
+1. Is this a standard project file? → Root is OK
+2. Is this implementation documentation? → `docs/implementation/`
+3. Is this Docker-related? → `.docker/` or `.docker/compose/`
+4. Is this a test artifact? → `test-results/` or gitignore
+5. Is this a script? → `scripts/`
+6. Is this runtime config? → `configs/`
+
+## Directory Structure Reference
+
+```
+/
+├── .docker/ # Docker configuration
+│ ├── compose/ # All docker-compose files
+│ └── docker-entrypoint.sh # Container entrypoint
+├── .github/ # GitHub workflows, agents, instructions
+├── .vscode/ # VS Code settings and tasks
+├── backend/ # Go backend source
+├── configs/ # Runtime configurations
+├── docs/ # Documentation
+│ ├── implementation/ # Implementation/feature docs archive
+│ ├── plans/ # Planning documents
+│ └── ... # User-facing documentation
+├── frontend/ # React frontend source
+├── scripts/ # Build/test scripts
+├── test-results/ # Test outputs (gitignored)
+├── tools/ # Development tools
+└── [standard files] # README, LICENSE, Makefile, etc.
+```
+
+## Enforcement
+
+This structure is enforced by:
+
+- `.gitignore` patterns preventing commits of artifacts at root
+- Code review guidelines
+- These instructions for AI assistants
+
+When reviewing PRs or generating code, ensure new files follow these placement rules.
diff --git a/.github/skills/docker-start-dev-scripts/run.sh b/.github/skills/docker-start-dev-scripts/run.sh
index a524f285..b1ff27ac 100755
--- a/.github/skills/docker-start-dev-scripts/run.sh
+++ b/.github/skills/docker-start-dev-scripts/run.sh
@@ -18,4 +18,4 @@ REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
cd "$REPO_ROOT"
# Start development environment with Docker Compose
-exec docker compose -f docker-compose.dev.yml up -d
+exec docker compose -f .docker/compose/docker-compose.dev.yml up -d
diff --git a/.github/skills/docker-start-dev.SKILL.md b/.github/skills/docker-start-dev.SKILL.md
index afe391f5..98e07e96 100644
--- a/.github/skills/docker-start-dev.SKILL.md
+++ b/.github/skills/docker-start-dev.SKILL.md
@@ -41,13 +41,13 @@ metadata:
## Overview
-Starts the Charon development Docker Compose environment in detached mode. This brings up all required services including the application, database, CrowdSec, and any other dependencies defined in `docker-compose.dev.yml`.
+Starts the Charon development Docker Compose environment in detached mode. This brings up all required services including the application, database, CrowdSec, and any other dependencies defined in `.docker/compose/docker-compose.dev.yml`.
## Prerequisites
- Docker Engine installed and running
- Docker Compose V2 installed
-- `docker-compose.dev.yml` file in repository root
+- `.docker/compose/docker-compose.dev.yml` file in repository
- Network access (for pulling images)
- Sufficient system resources (CPU, memory, disk)
@@ -71,13 +71,13 @@ Use the task: **Docker: Start Dev Environment**
## Parameters
-This skill accepts no parameters. Services are configured in `docker-compose.dev.yml`.
+This skill accepts no parameters. Services are configured in `.docker/compose/docker-compose.dev.yml`.
## Environment Variables
This skill uses environment variables defined in:
- `.env` (if present)
-- `docker-compose.dev.yml` environment section
+- `.docker/compose/docker-compose.dev.yml` environment section
- Shell environment
## Outputs
@@ -99,7 +99,7 @@ This skill uses environment variables defined in:
## What Gets Started
-Services defined in `docker-compose.dev.yml`:
+Services defined in `.docker/compose/docker-compose.dev.yml`:
1. **charon-app**: Main application container
2. **charon-db**: SQLite or PostgreSQL database
3. **crowdsec**: Security bouncer
@@ -123,7 +123,7 @@ Docker Compose respects `depends_on` directives:
.github/skills/docker-start-dev-scripts/run.sh
# Verify services are running
-docker compose -f docker-compose.dev.yml ps
+docker compose -f .docker/compose/docker-compose.dev.yml ps
```
### Example 2: Start and View Logs
@@ -133,7 +133,7 @@ docker compose -f docker-compose.dev.yml ps
.github/skills/docker-start-dev-scripts/run.sh
# Follow logs from all services
-docker compose -f docker-compose.dev.yml logs -f
+docker compose -f .docker/compose/docker-compose.dev.yml logs -f
```
### Example 3: Start and Test Application
@@ -155,18 +155,18 @@ After starting, verify services are healthy:
```bash
# Check service status
-docker compose -f docker-compose.dev.yml ps
+docker compose -f .docker/compose/docker-compose.dev.yml ps
# Check specific service logs
-docker compose -f docker-compose.dev.yml logs app
+docker compose -f .docker/compose/docker-compose.dev.yml logs app
# Execute command in running container
-docker compose -f docker-compose.dev.yml exec app /bin/sh
+docker compose -f .docker/compose/docker-compose.dev.yml exec app /bin/sh
```
## Port Mappings
-Default development ports (check `docker-compose.dev.yml`):
+Default development ports (check `.docker/compose/docker-compose.dev.yml`):
- **8080**: Application HTTP
- **8443**: Application HTTPS (if configured)
- **9000**: Admin panel (if configured)
@@ -213,7 +213,7 @@ After starting, verify:
1. **All Services Running**:
```bash
- docker compose -f docker-compose.dev.yml ps
+ docker compose -f .docker/compose/docker-compose.dev.yml ps
```
2. **Application Accessible**:
@@ -223,7 +223,7 @@ After starting, verify:
3. **No Error Logs**:
```bash
- docker compose -f docker-compose.dev.yml logs --tail=50
+ docker compose -f .docker/compose/docker-compose.dev.yml logs --tail=50
```
## Related Skills
@@ -246,9 +246,9 @@ After starting, verify:
### Services Won't Start
1. Check Docker daemon: `docker info`
-2. Validate compose file: `docker compose -f docker-compose.dev.yml config`
+2. Validate compose file: `docker compose -f .docker/compose/docker-compose.dev.yml config`
3. Check available resources: `docker stats`
-4. Review logs: `docker compose -f docker-compose.dev.yml logs`
+4. Review logs: `docker compose -f .docker/compose/docker-compose.dev.yml logs`
### Slow Startup
@@ -266,4 +266,4 @@ After starting, verify:
**Last Updated**: 2025-12-20
**Maintained by**: Charon Project
-**Compose File**: `docker-compose.dev.yml`
+**Compose File**: `.docker/compose/docker-compose.dev.yml`
diff --git a/.github/skills/docker-stop-dev-scripts/run.sh b/.github/skills/docker-stop-dev-scripts/run.sh
index d7fd029f..beb9ac19 100755
--- a/.github/skills/docker-stop-dev-scripts/run.sh
+++ b/.github/skills/docker-stop-dev-scripts/run.sh
@@ -18,4 +18,4 @@ REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
cd "$REPO_ROOT"
# Stop development environment with Docker Compose
-exec docker compose -f docker-compose.dev.yml down
+exec docker compose -f .docker/compose/docker-compose.dev.yml down
diff --git a/.github/skills/docker-stop-dev.SKILL.md b/.github/skills/docker-stop-dev.SKILL.md
index 39fd754b..ca5e3314 100644
--- a/.github/skills/docker-stop-dev.SKILL.md
+++ b/.github/skills/docker-stop-dev.SKILL.md
@@ -49,7 +49,7 @@ Stops and removes all containers defined in the Charon development Docker Compos
- Docker Engine installed and running
- Docker Compose V2 installed
- Development environment previously started
-- `docker-compose.dev.yml` file in repository root
+- `.docker/compose/docker-compose.dev.yml` file in repository
## Usage
@@ -96,7 +96,7 @@ This skill requires no environment variables.
## What Gets Stopped
-Services defined in `docker-compose.dev.yml`:
+Services defined in `.docker/compose/docker-compose.dev.yml`:
1. **Application Containers**: Charon main app
2. **Database Containers**: SQLite/PostgreSQL services
3. **Security Services**: CrowdSec bouncer
@@ -110,7 +110,7 @@ The `down` command preserves:
- **Images**: Docker images remain cached
- **Configs**: Configuration files unchanged
-To remove volumes, use `docker compose -f docker-compose.dev.yml down -v`
+To remove volumes, use `docker compose -f .docker/compose/docker-compose.dev.yml down -v`
## Shutdown Order
@@ -129,14 +129,14 @@ Docker Compose stops services in reverse dependency order:
.github/skills/docker-stop-dev-scripts/run.sh
# Verify services are stopped
-docker compose -f docker-compose.dev.yml ps
+docker compose -f .docker/compose/docker-compose.dev.yml ps
```
### Example 2: Stop and Remove Volumes
```bash
# Stop services and remove data volumes
-docker compose -f docker-compose.dev.yml down -v
+docker compose -f .docker/compose/docker-compose.dev.yml down -v
```
### Example 3: Stop and Verify Cleanup
@@ -269,4 +269,4 @@ docker rmi $(docker images -q "*charon*")
**Last Updated**: 2025-12-20
**Maintained by**: Charon Project
-**Compose File**: `docker-compose.dev.yml`
+**Compose File**: `.docker/compose/docker-compose.dev.yml`
diff --git a/.gitignore b/.gitignore
index 063c2c57..96576515 100644
--- a/.gitignore
+++ b/.gitignore
@@ -212,5 +212,24 @@ import/
test-results/charon.hatfieldhosted.com.har
test-results/local.har
.cache
-trivy-scan-output.txt
-trivy-image-scan.txt
+
+# -----------------------------------------------------------------------------
+# Test artifacts at root
+# -----------------------------------------------------------------------------
+/block*.txt
+/final_block_test.txt
+
+# -----------------------------------------------------------------------------
+# Debug/temp config files at root
+# -----------------------------------------------------------------------------
+/caddy_*.json
+
+# -----------------------------------------------------------------------------
+# Trivy scan outputs at root
+# -----------------------------------------------------------------------------
+/trivy-*.txt
+
+# -----------------------------------------------------------------------------
+# Docker Overrides (new location)
+# -----------------------------------------------------------------------------
+.docker/compose/docker-compose.override.yml
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index e406942d..229618bd 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -173,21 +173,21 @@
{
"label": "Docker: Start Local Environment",
"type": "shell",
- "command": "docker compose -f docker-compose.local.yml up -d",
+ "command": "docker compose -f .docker/compose/docker-compose.local.yml up -d",
"group": "none",
"problemMatcher": []
},
{
"label": "Docker: Stop Local Environment",
"type": "shell",
- "command": "docker compose -f docker-compose.local.yml down",
+ "command": "docker compose -f .docker/compose/docker-compose.local.yml down",
"group": "none",
"problemMatcher": []
},
{
"label": "Docker: View Logs",
"type": "shell",
- "command": "docker compose logs -f",
+ "command": "docker compose -f .docker/compose/docker-compose.yml logs -f",
"group": "none",
"problemMatcher": [],
"isBackground": true
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7d65ad23..1e1e2ad1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+### Changed
+
+- **Repository Structure Reorganization**: Cleaned up root directory for better navigation
+ - Moved docker-compose files to `.docker/compose/`
+ - Moved `docker-entrypoint.sh` to `.docker/`
+ - Moved 16 implementation docs to `docs/implementation/`
+ - Deleted test artifacts (`block_test.txt`, `caddy_*.json`, etc.)
+ - Added `.github/instructions/structure.instructions.md` for ongoing structure enforcement
+
### Added
- **Bulk Apply Security Header Profiles**: Apply or remove security header profiles from multiple proxy hosts simultaneously via the Bulk Apply modal
diff --git a/Dockerfile b/Dockerfile
index 7d6bfa93..2bffcc14 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -308,7 +308,7 @@ COPY --from=backend-builder /go/bin/dlv /usr/local/bin/dlv
COPY --from=frontend-builder /app/frontend/dist /app/frontend/dist
# Copy startup script
-COPY docker-entrypoint.sh /docker-entrypoint.sh
+COPY .docker/docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
# Copy utility scripts (used for DB recovery and maintenance)
diff --git a/Makefile b/Makefile
index 7db14981..633f4564 100644
--- a/Makefile
+++ b/Makefile
@@ -82,7 +82,7 @@ clean:
# Build Docker image
docker-build:
- docker-compose build
+ docker compose -f .docker/compose/docker-compose.yml build
# Build Docker image with version
docker-build-versioned:
@@ -99,19 +99,19 @@ docker-build-versioned:
# Run Docker containers (production)
docker-run:
- docker-compose up -d
+ docker compose -f .docker/compose/docker-compose.yml up -d
# Run Docker containers (development)
docker-dev:
- docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
+ docker compose -f .docker/compose/docker-compose.yml -f .docker/compose/docker-compose.dev.yml up
# Stop Docker containers
docker-stop:
- docker-compose down
+ docker compose -f .docker/compose/docker-compose.yml down
# View Docker logs
docker-logs:
- docker-compose logs -f
+ docker compose -f .docker/compose/docker-compose.yml logs -f
# Development mode (requires tmux)
dev:
diff --git a/block_test.txt b/block_test.txt
deleted file mode 100644
index 0982cdcd..00000000
--- a/block_test.txt
+++ /dev/null
@@ -1,103 +0,0 @@
-* Host localhost:80 was resolved.
-* IPv6: ::1
-* IPv4: 127.0.0.1
- % Total % Received % Xferd Average Speed Time Time Time Current
- Dload Upload Total Spent Left Speed
-
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying [::1]:80...
-* Connected to localhost (::1) port 80
-> GET / HTTP/1.1
-> Host: localhost
-> User-Agent: curl/8.5.0
-> Accept: */*
-> X-Forwarded-For: 10.255.255.254
->
-< HTTP/1.1 200 OK
-< Accept-Ranges: bytes
-< Alt-Svc: h3=":443"; ma=2592000
-< Content-Length: 2367
-< Content-Type: text/html; charset=utf-8
-< Etag: "deyx3i1v4dks1tr"
-< Last-Modified: Mon, 15 Dec 2025 16:06:17 GMT
-< Server: Caddy
-< Vary: Accept-Encoding
-< Date: Mon, 15 Dec 2025 17:40:48 GMT
-<
-{ [2367 bytes data]
-
100 2367 100 2367 0 0 828k 0 --:--:-- --:--:-- --:--:-- 1155k
-* Connection #0 to host localhost left intact
-
-
-
-
-
- Site Not Configured | Charon
-
-
-
-
-
🛡️
-
Site Not Configured
-
- The domain you are trying to access is pointing to this server, but no proxy host has been configured for it yet.
-
-
- If you are the administrator, please log in to the Charon dashboard to configure this host.
-
-
Go to Dashboard
-
-
-
-
-
diff --git a/blocking_test.txt b/blocking_test.txt
deleted file mode 100644
index ac344be8..00000000
--- a/blocking_test.txt
+++ /dev/null
@@ -1,102 +0,0 @@
-* Host localhost:80 was resolved.
-* IPv6: ::1
-* IPv4: 127.0.0.1
- % Total % Received % Xferd Average Speed Time Time Time Current
- Dload Upload Total Spent Left Speed
-
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying [::1]:80...
-* Connected to localhost (::1) port 80
-> GET / HTTP/1.1
-> Host: localhost
-> User-Agent: curl/8.5.0
-> Accept: */*
-> X-Forwarded-For: 10.50.50.50
->
-< HTTP/1.1 200 OK
-< Accept-Ranges: bytes
-< Content-Length: 2367
-< Content-Type: text/html; charset=utf-8
-< Etag: "deyz8cxzfqbt1tr"
-< Last-Modified: Mon, 15 Dec 2025 17:46:40 GMT
-< Server: Caddy
-< Vary: Accept-Encoding
-< Date: Mon, 15 Dec 2025 19:50:03 GMT
-<
-{ [2367 bytes data]
-
100 2367 100 2367 0 0 320k 0 --:--:-- --:--:-- --:--:-- 330k
-* Connection #0 to host localhost left intact
-
-
-
-
-
- Site Not Configured | Charon
-
-
-
-
-
🛡️
-
Site Not Configured
-
- The domain you are trying to access is pointing to this server, but no proxy host has been configured for it yet.
-
-
- If you are the administrator, please log in to the Charon dashboard to configure this host.
-
-
Go to Dashboard
-
-
-
-
-
diff --git a/caddy_config_qa.json b/caddy_config_qa.json
deleted file mode 100644
index 80c24a1c..00000000
--- a/caddy_config_qa.json
+++ /dev/null
@@ -1 +0,0 @@
-{"admin":{"listen":"0.0.0.0:2019"},"apps":{"http":{"servers":{"charon_server":{"automatic_https":{},"listen":[":80",":443"],"logs":{"default_logger_name":"access_log"},"routes":[{"handle":[{"handler":"headers","response":{"set":{"Strict-Transport-Security":["max-age=31536000; includeSubDomains"]}}},{"handler":"vars"},{"handler":"headers","request":{"set":{"X-Forwarded-Host":["{http.request.host}"],"X-Plex-Client-Identifier":["{http.request.header.X-Plex-Client-Identifier}"],"X-Real-IP":["{http.request.remote.host}"]}}},{"flush_interval":-1,"handler":"reverse_proxy","headers":{"request":{"set":{"Connection":["{http.request.header.Connection}"],"Upgrade":["{http.request.header.Upgrade}"],"X-Forwarded-Host":["{http.request.host}"],"X-Plex-Client-Identifier":["{http.request.header.X-Plex-Client-Identifier}"],"X-Plex-Device":["{http.request.header.X-Plex-Device}"],"X-Plex-Device-Name":["{http.request.header.X-Plex-Device-Name}"],"X-Plex-Platform":["{http.request.header.X-Plex-Platform}"],"X-Plex-Platform-Version":["{http.request.header.X-Plex-Platform-Version}"],"X-Plex-Product":["{http.request.header.X-Plex-Product}"],"X-Plex-Token":["{http.request.header.X-Plex-Token}"],"X-Plex-Version":["{http.request.header.X-Plex-Version}"],"X-Real-IP":["{http.request.remote.host}"]}}},"upstreams":[{"dial":"100.99.23.57:32400"}]}],"match":[{"host":["plex.hatfieldhosted.com"]}],"terminal":true},{"handle":[{"handler":"headers","response":{"set":{"Strict-Transport-Security":["max-age=31536000; includeSubDomains"]}}},{"handler":"vars"},{"flush_interval":-1,"handler":"reverse_proxy","headers":{"request":{"set":{"Connection":["{http.request.header.Connection}"],"Upgrade":["{http.request.header.Upgrade}"]}}},"upstreams":[{"dial":"100.98.12.109:5055"}]}],"match":[{"host":["seerr.hatfieldhosted.com"]}],"terminal":true},{"handle":[{"handler":"headers","response":{"set":{"Strict-Transport-Security":["max-age=31536000; includeSubDomains"]}}},{"handler":"vars"},{"flush_interval":-1,"handler":"reverse_proxy","headers":{"request":{"set":{"Connection":["{http.request.header.Connection}"],"Upgrade":["{http.request.header.Upgrade}"]}}},"upstreams":[{"dial":"100.99.23.57:8989"}]}],"match":[{"host":["sonarr.hatfieldhosted.com"]}],"terminal":true},{"handle":[{"handler":"headers","response":{"set":{"Strict-Transport-Security":["max-age=31536000; includeSubDomains"]}}},{"handler":"vars"},{"flush_interval":-1,"handler":"reverse_proxy","headers":{"request":{"set":{"Connection":["{http.request.header.Connection}"],"Upgrade":["{http.request.header.Upgrade}"]}}},"upstreams":[{"dial":"100.99.23.57:7878"}]}],"match":[{"host":["radarr.hatfieldhosted.com"]}],"terminal":true},{"handle":[{"handler":"headers","response":{"set":{"Strict-Transport-Security":["max-age=31536000; includeSubDomains"]}}},{"handler":"vars"},{"flush_interval":-1,"handler":"reverse_proxy","headers":{"request":{"set":{"Connection":["{http.request.header.Connection}"],"Upgrade":["{http.request.header.Upgrade}"]}}},"upstreams":[{"dial":"100.99.23.57:6789"}]}],"match":[{"host":["nzbget.hatfieldhosted.com"]}],"terminal":true},{"handle":[{"handler":"headers","response":{"set":{"Strict-Transport-Security":["max-age=31536000; includeSubDomains"]}}},{"handler":"vars"},{"flush_interval":-1,"handler":"reverse_proxy","headers":{"request":{"set":{"Connection":["{http.request.header.Connection}"],"Upgrade":["{http.request.header.Upgrade}"]}}},"upstreams":[{"dial":"100.98.12.109:9925"}]}],"match":[{"host":["mealie.hatfieldhosted.com"]}],"terminal":true},{"handle":[{"handler":"headers","response":{"set":{"Strict-Transport-Security":["max-age=31536000; includeSubDomains"]}}},{"handler":"vars"},{"flush_interval":-1,"handler":"reverse_proxy","headers":{"request":{"set":{"Connection":["{http.request.header.Connection}"],"Upgrade":["{http.request.header.Upgrade}"]}}},"upstreams":[{"dial":"100.99.23.57:6767"}]}],"match":[{"host":["bazarr.hatfieldhosted.com"]}],"terminal":true},{"handle":[{"handler":"headers","response":{"set":{"Strict-Transport-Security":["max-age=31536000; includeSubDomains"]}}},{"handler":"vars"},{"flush_interval":-1,"handler":"reverse_proxy","headers":{"request":{"set":{"Connection":["{http.request.header.Connection}"],"Upgrade":["{http.request.header.Upgrade}"]}}},"upstreams":[{"dial":"100.99.23.57:4848"}]}],"match":[{"host":["tubesync.hatfieldhosted.com"]}],"terminal":true},{"handle":[{"handler":"headers","response":{"set":{"Strict-Transport-Security":["max-age=31536000; includeSubDomains"]}}},{"handler":"vars"},{"flush_interval":-1,"handler":"reverse_proxy","headers":{"request":{"set":{"Connection":["{http.request.header.Connection}"],"Upgrade":["{http.request.header.Upgrade}"]}}},"upstreams":[{"dial":"100.98.12.109:8181"}]}],"match":[{"host":["tautulli.hatfieldhosted.com"]}],"terminal":true},{"handle":[{"handler":"headers","response":{"set":{"Strict-Transport-Security":["max-age=31536000; includeSubDomains"]}}},{"handler":"vars"},{"flush_interval":-1,"handler":"reverse_proxy","headers":{"request":{"set":{"Connection":["{http.request.header.Connection}"],"Upgrade":["{http.request.header.Upgrade}"]}}},"upstreams":[{"dial":"100.98.12.109:9696"}]}],"match":[{"host":["prowlarr.hatfieldhosted.com"]}],"terminal":true},{"handle":[{"handler":"headers","response":{"set":{"Strict-Transport-Security":["max-age=31536000; includeSubDomains"]}}},{"handler":"vars"},{"flush_interval":-1,"handler":"reverse_proxy","headers":{"request":{"set":{"Connection":["{http.request.header.Connection}"],"Upgrade":["{http.request.header.Upgrade}"]}}},"upstreams":[{"dial":"100.98.12.109:3000"}]}],"match":[{"host":["homepage.hatfieldhosted.com"]}],"terminal":true},{"handle":[{"handler":"headers","response":{"set":{"Strict-Transport-Security":["max-age=31536000; includeSubDomains"]}}},{"handler":"vars"},{"flush_interval":-1,"handler":"reverse_proxy","headers":{"request":{"set":{"Connection":["{http.request.header.Connection}"],"Upgrade":["{http.request.header.Upgrade}"]}}},"upstreams":[{"dial":"100.98.12.109:6868"}]}],"match":[{"host":["profilarr.hatfieldhosted.com"]}],"terminal":true},{"handle":[{"handler":"headers","response":{"set":{"Strict-Transport-Security":["max-age=31536000; includeSubDomains"]}}},{"handler":"vars"},{"flush_interval":-1,"handler":"reverse_proxy","headers":{"request":{"set":{"Connection":["{http.request.header.Connection}"],"Upgrade":["{http.request.header.Upgrade}"]}}},"upstreams":[{"dial":"100.99.23.57:19200"}]}],"match":[{"host":["fileflows.hatfieldhosted.com"]}],"terminal":true},{"handle":[{"handler":"headers","response":{"set":{"Strict-Transport-Security":["max-age=31536000; includeSubDomains"]}}},{"handler":"vars"},{"flush_interval":-1,"handler":"reverse_proxy","headers":{"request":{"set":{"Connection":["{http.request.header.Connection}"],"Upgrade":["{http.request.header.Upgrade}"]}}},"upstreams":[{"dial":"100.99.23.57:9999"}]}],"match":[{"host":["dockwatch.hatfieldhosted.com"]}],"terminal":true},{"handle":[{"handler":"rewrite","uri":"/unknown.html"},{"handler":"file_server","root":"/app/frontend/dist"}],"terminal":true}]}}},"tls":{"automation":{"policies":[{"issuers":[{"email":"jhatfield82@proton.me","module":"acme"},{"module":"zerossl"}]}]}}},"logging":{"logs":{"access":{"encoder":{"format":"json"},"include":["http.log.access.access_log"],"level":"INFO","writer":{"filename":"/var/log/caddy/access.log","output":"file","roll":true,"roll_keep":5,"roll_keep_days":7,"roll_size_mb":10}}}},"storage":{"module":"file_system","root":"/app/data/caddy/data"}}
diff --git a/caddy_crowdsec_config.json b/caddy_crowdsec_config.json
deleted file mode 100644
index 19765bd5..00000000
--- a/caddy_crowdsec_config.json
+++ /dev/null
@@ -1 +0,0 @@
-null
diff --git a/AGENT_SKILLS_MIGRATION_SUMMARY.md b/docs/implementation/AGENT_SKILLS_MIGRATION_SUMMARY.md
similarity index 100%
rename from AGENT_SKILLS_MIGRATION_SUMMARY.md
rename to docs/implementation/AGENT_SKILLS_MIGRATION_SUMMARY.md
diff --git a/BULK_ACL_FEATURE.md b/docs/implementation/BULK_ACL_FEATURE.md
similarity index 100%
rename from BULK_ACL_FEATURE.md
rename to docs/implementation/BULK_ACL_FEATURE.md
diff --git a/I18N_IMPLEMENTATION_SUMMARY.md b/docs/implementation/I18N_IMPLEMENTATION_SUMMARY.md
similarity index 100%
rename from I18N_IMPLEMENTATION_SUMMARY.md
rename to docs/implementation/I18N_IMPLEMENTATION_SUMMARY.md
diff --git a/IMPLEMENTATION_SUMMARY.md b/docs/implementation/IMPLEMENTATION_SUMMARY.md
similarity index 100%
rename from IMPLEMENTATION_SUMMARY.md
rename to docs/implementation/IMPLEMENTATION_SUMMARY.md
diff --git a/INVESTIGATION_SUMMARY.md b/docs/implementation/INVESTIGATION_SUMMARY.md
similarity index 100%
rename from INVESTIGATION_SUMMARY.md
rename to docs/implementation/INVESTIGATION_SUMMARY.md
diff --git a/PHASE_0_COMPLETE.md b/docs/implementation/PHASE_0_COMPLETE.md
similarity index 100%
rename from PHASE_0_COMPLETE.md
rename to docs/implementation/PHASE_0_COMPLETE.md
diff --git a/PHASE_3_COMPLETE.md b/docs/implementation/PHASE_3_COMPLETE.md
similarity index 100%
rename from PHASE_3_COMPLETE.md
rename to docs/implementation/PHASE_3_COMPLETE.md
diff --git a/PHASE_4_COMPLETE.md b/docs/implementation/PHASE_4_COMPLETE.md
similarity index 100%
rename from PHASE_4_COMPLETE.md
rename to docs/implementation/PHASE_4_COMPLETE.md
diff --git a/PHASE_5_COMPLETE.md b/docs/implementation/PHASE_5_COMPLETE.md
similarity index 100%
rename from PHASE_5_COMPLETE.md
rename to docs/implementation/PHASE_5_COMPLETE.md
diff --git a/QA_AUDIT_REPORT_LOADING_OVERLAYS.md b/docs/implementation/QA_AUDIT_REPORT_LOADING_OVERLAYS.md
similarity index 100%
rename from QA_AUDIT_REPORT_LOADING_OVERLAYS.md
rename to docs/implementation/QA_AUDIT_REPORT_LOADING_OVERLAYS.md
diff --git a/QA_MIGRATION_COMPLETE.md b/docs/implementation/QA_MIGRATION_COMPLETE.md
similarity index 100%
rename from QA_MIGRATION_COMPLETE.md
rename to docs/implementation/QA_MIGRATION_COMPLETE.md
diff --git a/QA_PHASE5_VERIFICATION_REPORT.md b/docs/implementation/QA_PHASE5_VERIFICATION_REPORT.md
similarity index 100%
rename from QA_PHASE5_VERIFICATION_REPORT.md
rename to docs/implementation/QA_PHASE5_VERIFICATION_REPORT.md
diff --git a/docs/implementation/README.md b/docs/implementation/README.md
new file mode 100644
index 00000000..0029323d
--- /dev/null
+++ b/docs/implementation/README.md
@@ -0,0 +1,39 @@
+# Implementation Documentation Archive
+
+This directory contains archived implementation documentation and historical records
+of feature development in Charon.
+
+## Purpose
+
+These documents serve as historical references for:
+
+- Feature implementation details and decisions
+- Migration summaries and upgrade paths
+- Investigation reports and debugging sessions
+- Phase completion records
+
+## Document Index
+
+Documents will be organized here after migration from the project root:
+
+| Document | Description |
+|----------|-------------|
+| `AGENT_SKILLS_MIGRATION_SUMMARY.md` | Agent skills system migration details |
+| `BULK_ACL_FEATURE.md` | Bulk ACL feature implementation |
+| `I18N_IMPLEMENTATION_SUMMARY.md` | Internationalization implementation |
+| `IMPLEMENTATION_SUMMARY.md` | General implementation summary |
+| `INVESTIGATION_SUMMARY.md` | Investigation and debugging records |
+| `ISSUE_16_ACL_IMPLEMENTATION.md` | Issue #16 ACL implementation details |
+| `PHASE_*_COMPLETE.md` | Phase completion documentation |
+| `QA_*.md` | QA audit and verification reports |
+| `SECURITY_*.md` | Security implementation records |
+| `WEBSOCKET_FIX_SUMMARY.md` | WebSocket fix implementation |
+
+## Note
+
+These are **historical implementation records**. For current documentation, refer to:
+
+- `/docs/` - Main documentation
+- `/README.md` - Project overview
+- `/CONTRIBUTING.md` - Contribution guidelines
+- `/CHANGELOG.md` - Version history
diff --git a/SECURITY_CONFIG_PRIORITY.md b/docs/implementation/SECURITY_CONFIG_PRIORITY.md
similarity index 100%
rename from SECURITY_CONFIG_PRIORITY.md
rename to docs/implementation/SECURITY_CONFIG_PRIORITY.md
diff --git a/SECURITY_HEADERS_IMPLEMENTATION_SUMMARY.md b/docs/implementation/SECURITY_HEADERS_IMPLEMENTATION_SUMMARY.md
similarity index 100%
rename from SECURITY_HEADERS_IMPLEMENTATION_SUMMARY.md
rename to docs/implementation/SECURITY_HEADERS_IMPLEMENTATION_SUMMARY.md
diff --git a/SECURITY_IMPLEMENTATION_PLAN.md b/docs/implementation/SECURITY_IMPLEMENTATION_PLAN.md
similarity index 100%
rename from SECURITY_IMPLEMENTATION_PLAN.md
rename to docs/implementation/SECURITY_IMPLEMENTATION_PLAN.md
diff --git a/WEBSOCKET_FIX_SUMMARY.md b/docs/implementation/WEBSOCKET_FIX_SUMMARY.md
similarity index 100%
rename from WEBSOCKET_FIX_SUMMARY.md
rename to docs/implementation/WEBSOCKET_FIX_SUMMARY.md
diff --git a/docs/plans/structure.md b/docs/plans/structure.md
index 4665eb39..74c50d32 100644
--- a/docs/plans/structure.md
+++ b/docs/plans/structure.md
@@ -1,6 +1,6 @@
# Repository Structure Reorganization Plan
-**Date**: December 15, 2025
+**Date**: December 21, 2025 (Revised)
**Status**: Proposed
**Risk Level**: Medium (requires CI/CD updates, Docker path changes)
@@ -8,7 +8,7 @@
## Executive Summary
-The repository root level currently contains **60+ items**, making it difficult to navigate and maintain. This plan proposes moving files into logical directories to achieve a cleaner, more organized structure with only **~15 essential items** at the root level.
+The repository root level currently contains **81 items**, making it difficult to navigate and maintain. This plan proposes moving files into logical directories to achieve a cleaner, more organized structure with only **~15 essential items** at the root level.
**Key Benefits**:
@@ -28,7 +28,7 @@ The repository root level currently contains **60+ items**, making it difficult
|----------|-------|----------|--------|
| **Docker Compose Files** | 5 | `docker-compose.yml`, `docker-compose.dev.yml`, etc. | 🔴 Scattered |
| **CodeQL SARIF Files** | 6 | `codeql-go.sarif`, `codeql-results-*.sarif` | 🔴 Build artifacts at root |
-| **Implementation Docs** | 9 | `BULK_ACL_FEATURE.md`, `IMPLEMENTATION_SUMMARY.md`, etc. | 🔴 Should be in docs/ |
+| **Implementation Docs** | 16 | `BULK_ACL_FEATURE.md`, `IMPLEMENTATION_SUMMARY.md`, etc. | 🔴 Should be in docs/ |
| **Config Files** | 8 | `eslint.config.js`, `.pre-commit-config.yaml`, `Makefile`, etc. | 🟡 Mixed - some stay, some move |
| **Docker Files** | 3 | `Dockerfile`, `docker-entrypoint.sh`, `DOCKER.md` | 🟡 Could group |
| **Core Docs** | 4 | `README.md`, `CONTRIBUTING.md`, `LICENSE`, `VERSION.md` | 🟢 Stay at root |
@@ -43,7 +43,7 @@ The repository root level currently contains **60+ items**, making it difficult
1. **Docker Compose Sprawl**: 5 files at root when they should be grouped
2. **SARIF Pollution**: 6 CodeQL SARIF files are build artifacts (should be .gitignored)
-3. **Documentation Chaos**: 9 implementation/feature docs scattered at root instead of `docs/`
+3. **Documentation Chaos**: 16 implementation/feature docs scattered at root instead of `docs/`
4. **Mixed Purposes**: Docker files, configs, docs, code all at same level
---
@@ -74,9 +74,10 @@ The repository root level currently contains **60+ items**, making it difficult
├── .markdownlint.json # Markdown lint config
├── .markdownlintrc # Markdown lint config
├── .pre-commit-config.yaml # Pre-commit hooks
-├── .sourcery.yml # Sourcery config
+├── CHANGELOG.md # Project changelog
├── Chiron.code-workspace # VS Code workspace
├── CONTRIBUTING.md # Contribution guidelines
+├── CONTRIBUTING_TRANSLATIONS.md # Translation guidelines
├── LICENSE # License file
├── Makefile # Build automation
├── README.md # Project readme
@@ -98,6 +99,7 @@ The repository root level currently contains **60+ items**, making it difficult
│ ├── docker-compose.dev.yml # Dev override (moved from root)
│ ├── docker-compose.local.yml # Local override (moved from root)
│ ├── docker-compose.remote.yml # Remote override (moved from root)
+│ ├── docker-compose.override.yml # Remote override (moved from root)
│ └── README.md # Compose file documentation
├── docker-entrypoint.sh # Entrypoint script (moved from root)
└── README.md # Docker documentation (DOCKER.md renamed)
@@ -145,6 +147,8 @@ docs/
**New entries** to prevent SARIF files at root:
+> **Note**: The `*.sarif` pattern may already exist in `.gitignore`. Verify before adding to avoid duplication. The explicit patterns below ensure comprehensive coverage.
+
```gitignore
# Add to "CodeQL & Security Scanning" section:
# -----------------------------------------------------------------------------
@@ -163,8 +167,42 @@ docs/
/codeql-results-go-backend.sarif
/codeql-results-go-new.sarif
/codeql-results-js.sarif
+
+# Test artifacts at root
+/block*.txt
+/final_block_test.txt
+
+# Debug/temp config files at root
+/caddy_*.json
+!package*.json
+
+# Trivy scan outputs at root
+/trivy-*.txt
```
+#### Local Override Migration
+
+**Important**: With the move to `.docker/compose/`, the standard `docker-compose.override.yml` behavior changes:
+
+- **Previous behavior**: `docker-compose.override.yml` at repository root was auto-applied by Docker Compose
+- **New behavior**: Override files at `.docker/compose/docker-compose.override.yml` must be explicitly referenced with `-f` flag
+
+**Updated .gitignore entry**:
+
+```gitignore
+# Local docker-compose override (new location)
+.docker/compose/docker-compose.override.yml
+```
+
+**Usage with new location**:
+
+```bash
+# Development with override
+docker compose -f .docker/compose/docker-compose.yml -f .docker/compose/docker-compose.override.yml up -d
+```
+
+**Note**: Users with existing `docker-compose.override.yml` at root should move it to `.docker/compose/` and update their workflow scripts accordingly.
+
---
## File Migration Table
@@ -200,6 +238,15 @@ docs/
| `/SECURITY_CONFIG_PRIORITY.md` | `/docs/implementation/SECURITY_CONFIG_PRIORITY.md` | Move |
| `/SECURITY_IMPLEMENTATION_PLAN.md` | `/docs/implementation/SECURITY_IMPLEMENTATION_PLAN.md` | Move |
| `/WEBSOCKET_FIX_SUMMARY.md` | `/docs/implementation/WEBSOCKET_FIX_SUMMARY.md` | Move |
+| `/AGENT_SKILLS_MIGRATION_SUMMARY.md` | `/docs/implementation/AGENT_SKILLS_MIGRATION_SUMMARY.md` | Move |
+| `/I18N_IMPLEMENTATION_SUMMARY.md` | `/docs/implementation/I18N_IMPLEMENTATION_SUMMARY.md` | Move |
+| `/INVESTIGATION_SUMMARY.md` | `/docs/implementation/INVESTIGATION_SUMMARY.md` | Move |
+| `/PHASE_0_COMPLETE.md` | `/docs/implementation/PHASE_0_COMPLETE.md` | Move |
+| `/PHASE_3_COMPLETE.md` | `/docs/implementation/PHASE_3_COMPLETE.md` | Move |
+| `/PHASE_4_COMPLETE.md` | `/docs/implementation/PHASE_4_COMPLETE.md` | Move |
+| `/PHASE_5_COMPLETE.md` | `/docs/implementation/PHASE_5_COMPLETE.md` | Move |
+| `/QA_PHASE5_VERIFICATION_REPORT.md` | `/docs/implementation/QA_PHASE5_VERIFICATION_REPORT.md` | Move |
+| `/SECURITY_HEADERS_IMPLEMENTATION_SUMMARY.md` | `/docs/implementation/SECURITY_HEADERS_IMPLEMENTATION_SUMMARY.md` | Move |
### CodeQL SARIF Files → Delete (Add to .gitignore)
@@ -214,6 +261,20 @@ docs/
**Note**: These are generated by CodeQL and should never be committed.
+### Test/Debug Files → Delete + Gitignore
+
+| Current Path | Action | Reason |
+|-------------|--------|--------|
+| `/block_test.txt` | Delete + gitignore | Test artifact |
+| `/blocking_test.txt` | Delete + gitignore | Test artifact |
+| `/final_block_test.txt` | Delete + gitignore | Test artifact |
+| `/caddy_config_qa.json` | Delete + gitignore | Debug config |
+| `/caddy_crowdsec_config.json` | Delete + gitignore | Debug config |
+| `/trivy-image-scan.txt` | Delete + gitignore | Scan output |
+| `/trivy-scan-output.txt` | Delete + gitignore | Scan output |
+
+**Note**: These are test/debug artifacts that should never be committed.
+
### Files Staying at Root
| File | Reason |
@@ -222,17 +283,19 @@ docs/
| `Makefile` | Build automation - standard location |
| `README.md` | Project entry point - standard location |
| `CONTRIBUTING.md` | Contributor guidelines - standard location |
+| `CONTRIBUTING_TRANSLATIONS.md` | Translation contribution guidelines - standard location |
| `LICENSE` | License file - standard location |
| `VERSION.md` | Version documentation - standard location |
+| `CHANGELOG.md` | Project changelog - standard location |
| `Chiron.code-workspace` | VS Code workspace - standard location |
-| `go.work`, `go.work.sum` | Go workspace - required at root |
+| `go.work` | Go workspace - required at root |
+| `go.work.sum` | Go workspace checksums - required at root |
| `package.json` | Root package (pre-commit, etc.) - required at root |
| `eslint.config.js` | ESLint config - required at root |
| `.codecov.yml` | Codecov config - required at root |
| `.goreleaser.yaml` | GoReleaser config - required at root |
| `.markdownlint.json` | Markdown lint config - required at root |
| `.pre-commit-config.yaml` | Pre-commit config - required at root |
-| `.sourcery.yml` | Sourcery config - required at root |
| All `.git*` files | Git configuration - required at root |
| All hidden directories | Standard locations |
@@ -461,9 +524,30 @@ docs/implementation/
git mv SECURITY_CONFIG_PRIORITY.md docs/implementation/
git mv SECURITY_IMPLEMENTATION_PLAN.md docs/implementation/
git mv WEBSOCKET_FIX_SUMMARY.md docs/implementation/
+ git mv AGENT_SKILLS_MIGRATION_SUMMARY.md docs/implementation/
+ git mv I18N_IMPLEMENTATION_SUMMARY.md docs/implementation/
+ git mv INVESTIGATION_SUMMARY.md docs/implementation/
+ git mv PHASE_0_COMPLETE.md docs/implementation/
+ git mv PHASE_3_COMPLETE.md docs/implementation/
+ git mv PHASE_4_COMPLETE.md docs/implementation/
+ git mv PHASE_5_COMPLETE.md docs/implementation/
+ git mv QA_PHASE5_VERIFICATION_REPORT.md docs/implementation/
+ git mv SECURITY_HEADERS_IMPLEMENTATION_SUMMARY.md docs/implementation/
```
-4. **Delete SARIF files**:
+4. **Delete test/debug files**:
+
+ ```bash
+ git rm block_test.txt
+ git rm blocking_test.txt
+ git rm final_block_test.txt
+ git rm caddy_config_qa.json
+ git rm caddy_crowdsec_config.json
+ git rm trivy-image-scan.txt
+ git rm trivy-scan-output.txt
+ ```
+
+5. **Delete SARIF files**:
```bash
git rm codeql-go.sarif
@@ -474,7 +558,7 @@ docs/implementation/
git rm codeql-results-js.sarif
```
-5. **Commit file moves**:
+6. **Commit file moves**:
```bash
git commit -m "chore: reorganize repository structure
@@ -484,6 +568,7 @@ docs/implementation/
- Move DOCKER.md to .docker/README.md
- Move implementation docs to docs/implementation/
- Delete committed SARIF files (should be gitignored)
+ - Delete test/debug artifacts (should be gitignored)
"
```
@@ -611,6 +696,74 @@ docs/implementation/
- Update any external documentation
- Monitor for issues in next few days
+### Phase 6: Documentation & Enforcement
+
+1. **Create structure enforcement instructions**:
+ Create `.github/instructions/structure.instructions.md` to enforce the clean structure going forward:
+
+ ```markdown
+ ---
+ applyTo: '*'
+ description: 'Repository structure guidelines to maintain organized file placement'
+ ---
+
+ # Repository Structure Guidelines
+
+ ## Root Level Rules
+
+ The repository root should contain ONLY:
+ - Essential config files (`.gitignore`, `.pre-commit-config.yaml`, `Makefile`, etc.)
+ - Standard project files (`README.md`, `CONTRIBUTING.md`, `LICENSE`, `CHANGELOG.md`)
+ - Go workspace files (`go.work`, `go.work.sum`)
+ - VS Code workspace (`Chiron.code-workspace`)
+ - Primary `Dockerfile` (entrypoint and compose files live in `.docker/`)
+
+ ## File Placement Rules
+
+ ### Implementation/Feature Documentation
+ - **Location**: `docs/implementation/`
+ - **Pattern**: `*_SUMMARY.md`, `*_IMPLEMENTATION.md`, `*_COMPLETE.md`, `*_FEATURE.md`
+ - **Never** place implementation docs at root
+
+ ### Docker Compose Files
+ - **Location**: `.docker/compose/`
+ - **Files**: `docker-compose.yml`, `docker-compose.*.yml`
+ - **Override**: Local overrides go in `.docker/compose/docker-compose.override.yml`
+
+ ### Docker Support Files
+ - **Location**: `.docker/`
+ - **Files**: `docker-entrypoint.sh`, Docker documentation
+
+ ### Test Artifacts
+ - **Never commit**: `*.sarif`, `*_test.txt`, `*.cover` files at root
+ - **Location**: Test outputs should go to `test-results/` or be gitignored
+
+ ### Debug/Temp Config Files
+ - **Never commit**: Temporary JSON configs like `caddy_*.json` at root
+ - **Location**: Use `configs/` for persistent configs, gitignore temp files
+
+ ## Before Creating New Files
+
+ Ask yourself:
+ 1. Is this a standard project file? → Root is OK
+ 2. Is this implementation documentation? → `docs/implementation/`
+ 3. Is this Docker-related? → `.docker/` or `.docker/compose/`
+ 4. Is this a test artifact? → `test-results/` or gitignore
+ 5. Is this a script? → `scripts/`
+ 6. Is this runtime config? → `configs/`
+
+ ## Enforcement
+
+ Pre-commit hooks and CI will flag files placed incorrectly at root level.
+ ```
+
+2. **Update .pre-commit-config.yaml** (optional future enhancement):
+ Consider adding a hook to detect new files at root that don't match allowed patterns.
+
+3. **Announce changes**:
+ - Update `CHANGELOG.md` with structure reorganization entry
+ - Notify contributors of new file placement guidelines
+
---
## Risk Assessment
@@ -665,6 +818,8 @@ If critical issues arise after merge:
- [ ] Pre-commit checks pass
- [ ] All VS Code tasks work
- [ ] Documentation updated
+- [ ] Structure instructions file created at `.github/instructions/structure.instructions.md`
+- [ ] Test/debug files cleaned up and gitignored
- [ ] PR reviewed by maintainers
✅ **After Merge**:
@@ -673,7 +828,7 @@ If critical issues arise after merge:
- [ ] Docker images build successfully
- [ ] No broken links in documentation
- [ ] No regressions reported
-- [ ] Root level has ~15 items (down from 60+)
+- [ ] Root level has ~15 items (down from 81)
---
diff --git a/final_block_test.txt b/final_block_test.txt
deleted file mode 100644
index 1f0db1bd..00000000
--- a/final_block_test.txt
+++ /dev/null
@@ -1,103 +0,0 @@
-* Host localhost:80 was resolved.
-* IPv6: ::1
-* IPv4: 127.0.0.1
- % Total % Received % Xferd Average Speed Time Time Time Current
- Dload Upload Total Spent Left Speed
-
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying [::1]:80...
-* Connected to localhost (::1) port 80
-> GET / HTTP/1.1
-> Host: localhost
-> User-Agent: curl/8.5.0
-> Accept: */*
-> X-Forwarded-For: 172.16.0.99
->
-< HTTP/1.1 200 OK
-< Accept-Ranges: bytes
-< Alt-Svc: h3=":443"; ma=2592000
-< Content-Length: 2367
-< Content-Type: text/html; charset=utf-8
-< Etag: "deyz8cxzfqbt1tr"
-< Last-Modified: Mon, 15 Dec 2025 17:46:40 GMT
-< Server: Caddy
-< Vary: Accept-Encoding
-< Date: Mon, 15 Dec 2025 18:02:32 GMT
-<
-{ [2367 bytes data]
-
100 2367 100 2367 0 0 1136k 0 --:--:-- --:--:-- --:--:-- 2311k
-* Connection #0 to host localhost left intact
-
-
-
-
-
- Site Not Configured | Charon
-
-
-
-
-
🛡️
-
Site Not Configured
-
- The domain you are trying to access is pointing to this server, but no proxy host has been configured for it yet.
-
-
- If you are the administrator, please log in to the Charon dashboard to configure this host.
-
-
Go to Dashboard
-
-
-
-
-
diff --git a/frontend/package.json b/frontend/package.json
index 3f2c365a..18a0b811 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -22,9 +22,9 @@
"test:coverage": "vitest --coverage --coverage.provider=istanbul --coverage.reporter=json-summary --coverage.reporter=lcov --coverage.reporter=text",
"e2e:install": "npx playwright install --with-deps",
"e2e:test": "playwright test",
- "e2e:up:block": "docker compose -f ../docker-compose.local.yml down && CHARON_SECURITY_WAF_MODE=block docker compose -f ../docker-compose.local.yml up -d",
- "e2e:up:monitor": "docker compose -f ../docker-compose.local.yml down && CHARON_SECURITY_WAF_MODE=monitor docker compose -f ../docker-compose.local.yml up -d",
- "e2e:down": "docker compose -f ../docker-compose.local.yml down"
+ "e2e:up:block": "docker compose -f ../.docker/compose/docker-compose.local.yml down && CHARON_SECURITY_WAF_MODE=block docker compose -f ../.docker/compose/docker-compose.local.yml up -d",
+ "e2e:up:monitor": "docker compose -f ../.docker/compose/docker-compose.local.yml down && CHARON_SECURITY_WAF_MODE=monitor docker compose -f ../.docker/compose/docker-compose.local.yml up -d",
+ "e2e:down": "docker compose -f ../.docker/compose/docker-compose.local.yml down"
},
"dependencies": {
"@radix-ui/react-checkbox": "^1.3.3",
diff --git a/scripts/coraza_integration.sh b/scripts/coraza_integration.sh
index b97e3e77..5c966532 100644
--- a/scripts/coraza_integration.sh
+++ b/scripts/coraza_integration.sh
@@ -13,7 +13,7 @@ sleep 1
# Brief: Integration test for Coraza WAF using Docker Compose and built image
# Steps:
# 1. Build the local image: docker build -t charon:local .
-# 2. Start docker-compose.local.yml: docker compose -f docker-compose.local.yml up -d
+# 2. Start docker-compose.local.yml: docker compose -f .docker/compose/docker-compose.local.yml up -d
# 3. Wait for API to be ready and then configure a ruleset that blocks a simple signature
# 4. Request a path containing the signature and verify 403 (or WAF block response)
@@ -129,7 +129,7 @@ fi
# NOTE: We intentionally do NOT mount $(pwd)/backend or $(pwd)/frontend/dist here.
# In CI, frontend/dist does not exist (it's built inside the Docker image).
# Mounting a non-existent directory would override the built frontend with an empty dir.
-# For local development with hot-reload, use docker-compose.local.yml instead.
+# For local development with hot-reload, use .docker/compose/docker-compose.local.yml instead.
docker run -d --name charon-debug --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --network containers_default -p 80:80 -p 443:443 -p 8080:8080 -p 2019:2019 -p 2345:2345 \
-e CHARON_ENV=development -e CHARON_DEBUG=1 -e CHARON_HTTP_PORT=8080 -e CHARON_DB_PATH=/app/data/charon.db -e CHARON_FRONTEND_DIR=/app/frontend/dist \
-e CHARON_CADDY_ADMIN_API=http://localhost:2019 -e CHARON_CADDY_CONFIG_DIR=/app/data/caddy -e CHARON_CADDY_BINARY=caddy -e CHARON_IMPORT_CADDYFILE=/import/Caddyfile \
diff --git a/scripts/crowdsec_startup_test.sh b/scripts/crowdsec_startup_test.sh
index d46ca1ea..28f29d7e 100755
--- a/scripts/crowdsec_startup_test.sh
+++ b/scripts/crowdsec_startup_test.sh
@@ -318,7 +318,7 @@ if [ "$CRITICAL_FAILURE" = "true" ]; then
echo "To fix:"
echo " 1. Ensure configs/crowdsec/acquis.yaml exists with 'source:' definition"
echo " 2. Ensure Dockerfile copies acquis.yaml to /etc/crowdsec.dist/"
- echo " 3. Ensure docker-entrypoint.sh copies configs to /etc/crowdsec/"
+ echo " 3. Ensure .docker/docker-entrypoint.sh copies configs to /etc/crowdsec/"
echo ""
exit 1
fi