Refactored.

This commit is contained in:
Bartlomiej Mika 2025-12-02 22:48:40 -05:00
parent f4a49ad4b9
commit 9dad75464b
37 changed files with 667 additions and 247 deletions

View file

@ -123,9 +123,9 @@ task dev:status
```
NAMES STATUS PORTS
maple-cassandra-1-dev Up 2 minutes (healthy) 0.0.0.0:9042->9042/tcp
maple-redis-dev Up 2 minutes (healthy) 0.0.0.0:6379->6379/tcp
maple-wordpress-dev Up 2 minutes (healthy) 0.0.0.0:8081->80/tcp
mapleopentech-cassandra-1-dev Up 2 minutes (healthy) 0.0.0.0:9042->9042/tcp
mapleopentech-redis-dev Up 2 minutes (healthy) 0.0.0.0:6379->6379/tcp
mapleopentech-wordpress-dev Up 2 minutes (healthy) 0.0.0.0:8081->80/tcp
...
```
@ -264,7 +264,7 @@ task redis
**View debug logs:**
```bash
docker exec -it maple-wordpress-dev tail -f /var/www/html/wp-content/debug.log
docker exec -it mapleopentech-wordpress-dev tail -f /var/www/html/wp-content/debug.log
```
### Working with SeaweedFS (S3 Storage)
@ -298,12 +298,12 @@ S3_SECRET_KEY=any
All data is stored in Docker volumes and survives restarts:
- `maple-cassandra-1-dev`, `maple-cassandra-2-dev`, `maple-cassandra-3-dev`
- `maple-redis-dev`
- `maple-meilisearch-dev`
- `maple-seaweedfs-dev`
- `maple-mariadb-dev`
- `maple-wordpress-dev`
- `mapleopentech-cassandra-1-dev`, `mapleopentech-cassandra-2-dev`, `mapleopentech-cassandra-3-dev`
- `mapleopentech-redis-dev`
- `mapleopentech-meilisearch-dev`
- `mapleopentech-seaweedfs-dev`
- `mapleopentech-mariadb-dev`
- `mapleopentech-wordpress-dev`
**To completely reset (deletes all data):**
```bash
@ -336,7 +336,7 @@ WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 3};
2. Configure your project's `docker-compose.dev.yml`:
```yaml
networks:
maple-dev:
mapleopentech-dev:
external: true
services:
@ -349,7 +349,7 @@ services:
- REDIS_HOST=redis
- REDIS_DB=2 # Use next available: 0=maplepress, 1=maplefile
networks:
- maple-dev
- mapleopentech-dev
```
3. Restart infrastructure:

View file

@ -1,4 +1,4 @@
version: '3'
version: "3"
# Variables for Docker Compose command detection
vars:
@ -24,7 +24,7 @@ tasks:
- echo "✅ Infrastructure ready!"
- echo ""
- echo "📊 Running Services:"
- docker ps --filter "name=maple-"
- docker ps --filter "name=mapleopentech-"
dev:wait:
desc: Wait for all services to be healthy
@ -33,7 +33,7 @@ tasks:
- |
echo "Waiting for Cassandra Node 1..."
for i in {1..30}; do
if docker exec maple-cassandra-1-dev cqlsh -e "describe cluster" >/dev/null 2>&1; then
if docker exec mapleopentech-cassandra-1-dev cqlsh -e "describe cluster" >/dev/null 2>&1; then
echo "✅ Cassandra Node 1 is ready"
break
fi
@ -43,7 +43,7 @@ tasks:
- |
echo "Waiting for Cassandra Node 2..."
for i in {1..30}; do
if docker exec maple-cassandra-2-dev cqlsh -e "describe cluster" >/dev/null 2>&1; then
if docker exec mapleopentech-cassandra-2-dev cqlsh -e "describe cluster" >/dev/null 2>&1; then
echo "✅ Cassandra Node 2 is ready"
break
fi
@ -53,7 +53,7 @@ tasks:
- |
echo "Waiting for Cassandra Node 3..."
for i in {1..30}; do
if docker exec maple-cassandra-3-dev cqlsh -e "describe cluster" >/dev/null 2>&1; then
if docker exec mapleopentech-cassandra-3-dev cqlsh -e "describe cluster" >/dev/null 2>&1; then
echo "✅ Cassandra Node 3 is ready"
break
fi
@ -63,7 +63,7 @@ tasks:
- |
echo "Waiting for Redis..."
for i in {1..10}; do
if docker exec maple-redis-dev redis-cli ping >/dev/null 2>&1; then
if docker exec mapleopentech-redis-dev redis-cli ping >/dev/null 2>&1; then
echo "✅ Redis is ready"
break
fi
@ -72,7 +72,7 @@ tasks:
- |
echo "Waiting for SeaweedFS..."
for i in {1..10}; do
if docker exec maple-seaweedfs-dev /usr/bin/wget -q --spider http://127.0.0.1:9333/cluster/status 2>/dev/null; then
if docker exec mapleopentech-seaweedfs-dev /usr/bin/wget -q --spider http://127.0.0.1:9333/cluster/status 2>/dev/null; then
echo "✅ SeaweedFS is ready"
break
fi
@ -84,7 +84,7 @@ tasks:
cmds:
- |
echo "📦 Initializing Cassandra keyspaces..."
docker exec -i maple-cassandra-1-dev cqlsh < cassandra/init-scripts/01-create-keyspaces.cql
docker exec -i mapleopentech-cassandra-1-dev cqlsh < cassandra/init-scripts/01-create-keyspaces.cql
echo "✅ Keyspaces initialized with replication_factor=3"
dev:status:
@ -92,7 +92,7 @@ tasks:
cmds:
- |
echo "📊 Infrastructure Status:"
docker ps --filter "name=maple-" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
docker ps --filter "name=mapleopentech-" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
dev:stop:
desc: Stop all infrastructure services (keeps data)
@ -130,39 +130,39 @@ tasks:
exit 1
fi
echo "🗑️ Dropping keyspace: $KEYSPACE"
docker exec maple-cassandra-1-dev cqlsh -e "DROP KEYSPACE IF EXISTS $KEYSPACE;"
docker exec mapleopentech-cassandra-1-dev cqlsh -e "DROP KEYSPACE IF EXISTS $KEYSPACE;"
echo "📦 Recreating keyspace: $KEYSPACE"
docker exec maple-cassandra-1-dev cqlsh -e "CREATE KEYSPACE IF NOT EXISTS $KEYSPACE WITH REPLICATION = {'class': 'SimpleStrategy', 'replication_factor': 3} AND DURABLE_WRITES = true;"
docker exec mapleopentech-cassandra-1-dev cqlsh -e "CREATE KEYSPACE IF NOT EXISTS $KEYSPACE WITH REPLICATION = {'class': 'SimpleStrategy', 'replication_factor': 3} AND DURABLE_WRITES = true;"
echo "✅ Keyspace $KEYSPACE cleaned and recreated"
# Cassandra-specific tasks
cql:
desc: Open Cassandra CQL shell (connects to node 1)
cmds:
- docker exec -it maple-cassandra-1-dev cqlsh
- docker exec -it mapleopentech-cassandra-1-dev cqlsh
cql:keyspaces:
desc: List all keyspaces
cmds:
- docker exec maple-cassandra-1-dev cqlsh -e "DESCRIBE KEYSPACES;"
- docker exec mapleopentech-cassandra-1-dev cqlsh -e "DESCRIBE KEYSPACES;"
cql:tables:
desc: List tables in a keyspace (usage task cql:tables -- maplepress)
cmds:
- docker exec maple-cassandra-1-dev cqlsh -e "USE {{.CLI_ARGS}}; DESCRIBE TABLES;"
- docker exec mapleopentech-cassandra-1-dev cqlsh -e "USE {{.CLI_ARGS}}; DESCRIBE TABLES;"
cql:status:
desc: Show Cassandra cluster status
cmds:
- docker exec maple-cassandra-1-dev nodetool status
- docker exec mapleopentech-cassandra-1-dev nodetool status
# Redis-specific tasks
redis:
desc: Open Redis CLI
cmds:
- docker exec -it maple-redis-dev redis-cli
- docker exec -it mapleopentech-redis-dev redis-cli
redis:info:
desc: Show Redis info
cmds:
- docker exec maple-redis-dev redis-cli INFO
- docker exec mapleopentech-redis-dev redis-cli INFO

View file

@ -453,13 +453,13 @@ docker node inspect mapleopentech-swarm-worker-10-prod --format '{{.Spec.Labels}
**Important:** Workers must access Cassandra and Redis.
```bash
# Add worker-10 to maple-private-prod network
# Add worker-10 to mapleopentech-private-prod network
# This is done automatically when services start on the worker
# But verify connectivity:
# On worker-10, test Redis connectivity
ssh root@<worker-10-ip>
docker run --rm --network maple-private-prod redis:7.0-alpine redis-cli -h redis ping
docker run --rm --network mapleopentech-private-prod redis:7.0-alpine redis-cli -h redis ping
# Should output: PONG
```

View file

@ -153,8 +153,8 @@ DNS: [Your DNS provider]
SSL: Let's Encrypt (automatic via Caddy)
Networks:
- maple-private-prod: Databases and internal services
- maple-public-prod: Public-facing services (Caddy + backends)
- mapleopentech-private-prod: Databases and internal services
- mapleopentech-public-prod: Public-facing services (Caddy + backends)
Databases:
- Cassandra: 3-node cluster, RF=3, QUORUM consistency

View file

@ -27,8 +27,8 @@ This document defines the **multi-application architecture** for Maple Open Tech
│ - Meilisearch (worker 5) │
│ │
│ Networks: │
│ - maple-private-prod (databases, cache, search) │
│ - maple-public-prod (reverse proxies + backends) │
│ - mapleopentech-private-prod (databases, cache, search) │
│ - mapleopentech-public-prod (reverse proxies + backends) │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
@ -40,7 +40,7 @@ This document defines the **multi-application architecture** for Maple Open Tech
│ Service: maplepress_backend │
│ Hostname: maplepress-backend │
│ Port: 8000 │
│ Networks: maple-private-prod + maple-public-prod │
│ Networks: mapleopentech-private-prod + mapleopentech-public-prod │
│ Connects to: Cassandra, Redis, Meilisearch, Spaces │
│ │
│ Service: maplepress_backend-caddy │
@ -66,7 +66,7 @@ This document defines the **multi-application architecture** for Maple Open Tech
│ Service: maplefile_backend │
│ Hostname: maplefile-backend │
│ Port: 8000 │
│ Networks: maple-private-prod + maple-public-prod │
│ Networks: mapleopentech-private-prod + mapleopentech-public-prod │
│ Connects to: Cassandra, Redis, Meilisearch, Spaces │
│ │
│ Service: maplefile_backend-caddy │
@ -92,7 +92,7 @@ This document defines the **multi-application architecture** for Maple Open Tech
│ Service: mapleopentech_backend │
│ Hostname: mapleopentech-backend │
│ Port: 8000 │
│ Networks: maple-private-prod + maple-public-prod │
│ Networks: mapleopentech-private-prod + mapleopentech-public-prod │
│ Connects to: Cassandra, Redis, Meilisearch, Spaces │
│ │
│ Service: mapleopentech_backend-caddy │
@ -256,7 +256,7 @@ docker config ls
## Network Topology
### maple-private-prod (Shared by ALL Apps)
### mapleopentech-private-prod (Shared by ALL Apps)
**Purpose**: Private backend services - databases, cache, search
@ -268,7 +268,7 @@ docker config ls
**Security**: No ingress ports, no internet access, internal-only
### maple-public-prod (Per-App Reverse Proxies + Backends)
### mapleopentech-public-prod (Per-App Reverse Proxies + Backends)
**Purpose**: Internet-facing services - reverse proxies and backends

View file

@ -15,7 +15,7 @@ We use a **multi-network architecture** following industry best practices for se
│ Docker Swarm Cluster │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ maple-private-prod (Overlay Network) │ │
│ │ mapleopentech-private-prod (Overlay Network) │ │
│ │ No Internet Access | Internal Services Only │ │
│ │ SHARED by ALL applications │ │
│ ├────────────────────────────────────────────────────────────┤ │
@ -31,7 +31,7 @@ We use a **multi-network architecture** following industry best practices for se
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ maple-public-prod (Overlay Network) │ │
│ │ mapleopentech-public-prod (Overlay Network) │ │
│ │ Internet-Facing | Public Services │ │
│ ├────────────────────────────────────────────────────────────┤ │
│ │ Reverse Proxies (Caddy - ports 80/443): │ │
@ -48,14 +48,14 @@ We use a **multi-network architecture** following industry best practices for se
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ Note: Application backends join BOTH networks: │
│ - Receive requests from Caddy on maple-public-prod │
│ - Access databases/cache on maple-private-prod │
│ - Receive requests from Caddy on mapleopentech-public-prod │
│ - Access databases/cache on mapleopentech-private-prod │
└─────────────────────────────────────────────────────────────────┘
```
## Networks Explained
### 1. `maple-private-prod` (Current)
### 1. `mapleopentech-private-prod` (Current)
**Purpose**: Backend services that should NEVER be exposed to the internet.
@ -86,7 +86,7 @@ cassandra-2:9042
cassandra-3:9042
```
### 2. `maple-public-prod` (Current - In Use)
### 2. `mapleopentech-public-prod` (Current - In Use)
**Purpose**: Internet-facing services that handle external traffic.
@ -110,9 +110,9 @@ cassandra-3:9042
**Routing Flow:**
```
Internet → Caddy Reverse Proxy (maple-public-prod)
→ Application Backend (maple-public-prod + maple-private-prod)
→ Databases/Cache (maple-private-prod only)
Internet → Caddy Reverse Proxy (mapleopentech-public-prod)
→ Application Backend (mapleopentech-public-prod + mapleopentech-private-prod)
→ Databases/Cache (mapleopentech-private-prod only)
Example (MaplePress):
https://getmaplepress.ca → maplepress-backend-caddy
@ -157,19 +157,19 @@ Both networks are created and in use:
docker network create \
--driver overlay \
--attachable \
maple-private-prod
mapleopentech-private-prod
# Create public network (done in 06_caddy.md - used by reverse proxies)
docker network create \
--driver overlay \
--attachable \
maple-public-prod
mapleopentech-public-prod
# Verify both exist
docker network ls | grep maple
# Should show:
# maple-private-prod
# maple-public-prod
# mapleopentech-private-prod
# mapleopentech-public-prod
```
### Multi-App Pattern
@ -183,7 +183,7 @@ docker network ls | grep maple
### Go Backend Connecting to Services
**On `maple-private-prod` network:**
**On `mapleopentech-private-prod` network:**
```go
// Redis connection
@ -206,16 +206,16 @@ services:
backend:
image: your-backend:latest
networks:
- maple-private-prod # Access to databases
- maple-public-prod # Receive HTTP requests (when deployed)
- mapleopentech-private-prod # Access to databases
- mapleopentech-public-prod # Receive HTTP requests (when deployed)
environment:
- REDIS_HOST=redis
- CASSANDRA_HOSTS=cassandra-1,cassandra-2,cassandra-3
networks:
maple-private-prod:
mapleopentech-private-prod:
external: true
maple-public-prod:
mapleopentech-public-prod:
external: true
```
@ -256,7 +256,7 @@ docker service inspect your_service --format '{{.Spec.TaskTemplate.Networks}}'
### Test Connectivity Between Networks
```bash
# From a container on maple-private-prod
# From a container on mapleopentech-private-prod
docker exec -it <container> ping redis
docker exec -it <container> nc -zv cassandra-1 9042
@ -266,19 +266,19 @@ docker exec -it <container> nc -zv cassandra-1 9042
### View All Services on a Network
```bash
docker network inspect maple-private-prod --format '{{range .Containers}}{{.Name}} {{end}}'
docker network inspect mapleopentech-private-prod --format '{{range .Containers}}{{.Name}} {{end}}'
```
## Migration Path
### Current Status
- ✅ `maple-private-prod` created
- ✅ Cassandra on `maple-private-prod`
- ✅ Redis on `maple-private-prod`
- ✅ `mapleopentech-private-prod` created
- ✅ Cassandra on `mapleopentech-private-prod`
- ✅ Redis on `mapleopentech-private-prod`
- ⏳ Backend deployment (next)
- ⏳ Public network + NGINX (future)
### When to Create `maple-public-prod`
### When to Create `mapleopentech-public-prod`
Create the public network when you're ready to:
1. Deploy NGINX reverse proxy

View file

@ -50,7 +50,7 @@ Cassandra Cluster (NEW):
### Cassandra Configuration
- **Version**: Cassandra 5.0.4
- **Cluster Name**: maple-private-prod-cluster
- **Cluster Name**: mapleopentech-private-prod-cluster
- **Replication Factor**: 3 (each data stored on all 3 nodes)
- **Data Center**: datacenter1
- **Heap Size**: 512MB (reduced for 2GB RAM constraint)
@ -358,7 +358,7 @@ Copy and paste the following:
version: '3.8'
networks:
maple-private-prod:
mapleopentech-private-prod:
external: true
volumes:
@ -371,9 +371,9 @@ services:
image: cassandra:5.0.4
hostname: cassandra-1
networks:
- maple-private-prod
- mapleopentech-private-prod
environment:
- CASSANDRA_CLUSTER_NAME=maple-private-prod-cluster
- CASSANDRA_CLUSTER_NAME=mapleopentech-private-prod-cluster
- CASSANDRA_DC=datacenter1
- CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch
- CASSANDRA_SEEDS=cassandra-1,cassandra-2,cassandra-3
@ -401,9 +401,9 @@ services:
image: cassandra:5.0.4
hostname: cassandra-2
networks:
- maple-private-prod
- mapleopentech-private-prod
environment:
- CASSANDRA_CLUSTER_NAME=maple-private-prod-cluster
- CASSANDRA_CLUSTER_NAME=mapleopentech-private-prod-cluster
- CASSANDRA_DC=datacenter1
- CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch
- CASSANDRA_SEEDS=cassandra-1,cassandra-2,cassandra-3
@ -431,9 +431,9 @@ services:
image: cassandra:5.0.4
hostname: cassandra-3
networks:
- maple-private-prod
- mapleopentech-private-prod
environment:
- CASSANDRA_CLUSTER_NAME=maple-private-prod-cluster
- CASSANDRA_CLUSTER_NAME=mapleopentech-private-prod-cluster
- CASSANDRA_DC=datacenter1
- CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch
- CASSANDRA_SEEDS=cassandra-1,cassandra-2,cassandra-3
@ -460,19 +460,19 @@ services:
### Step 4: Create Shared Overlay Network
Before deploying any services, create the shared `maple-private-prod` network that all services will use:
Before deploying any services, create the shared `mapleopentech-private-prod` network that all services will use:
```bash
# Create the maple-private-prod overlay network
# Create the mapleopentech-private-prod overlay network
docker network create \
--driver overlay \
--attachable \
maple-private-prod
mapleopentech-private-prod
# Verify it was created
docker network ls | grep maple-private-prod
docker network ls | grep mapleopentech-private-prod
# Should show:
# abc123... maple-private-prod overlay swarm
# abc123... mapleopentech-private-prod overlay swarm
```
**What is this network for?**
@ -847,7 +847,7 @@ docker exec -it $CONTAINER_ID cqlsh -e "SELECT * FROM test.users;"
```bash
# On your local machine, add:
CASSANDRA_CLUSTER_NAME=maple-private-prod-cluster
CASSANDRA_CLUSTER_NAME=mapleopentech-private-prod-cluster
CASSANDRA_DC=datacenter1
CASSANDRA_REPLICATION_FACTOR=3
@ -1132,7 +1132,7 @@ docker exec -it $(docker ps -q --filter "name=cassandra") nodetool status
```yaml
# In your application stack file:
networks:
maple-private-prod:
mapleopentech-private-prod:
external: true
```

View file

@ -7,7 +7,7 @@
**What You'll Build**:
- Single Redis instance on existing worker-1
- Password-protected with Docker secrets
- Private network communication only (maple-private-prod overlay)
- Private network communication only (mapleopentech-private-prod overlay)
- Persistent data with AOF + RDB
- Ready for Go application connections
@ -37,23 +37,23 @@ Docker Swarm Cluster:
├── mapleopentech-swarm-worker-1-prod (10.116.0.3)
│ └── Redis (single instance)
│ ├── Network: maple-private-prod (overlay, shared)
│ ├── Network: mapleopentech-private-prod (overlay, shared)
│ ├── Port: 6379 (private only)
│ ├── Auth: Password (Docker secret)
│ └── Data: Persistent volume
└── mapleopentech-swarm-worker-2,3,4-prod
└── Cassandra Cluster (3 nodes)
└── Same network: maple-private-prod
└── Same network: mapleopentech-private-prod
Shared Network (maple-private-prod):
Shared Network (mapleopentech-private-prod):
├── All services can communicate
├── Service discovery by name (redis, cassandra-1, etc.)
└── No public internet access
Future Application:
└── mapleopentech-swarm-worker-X-prod
└── Go Backend → Connects to redis:6379 and cassandra:9042 on maple-private-prod
└── Go Backend → Connects to redis:6379 and cassandra:9042 on mapleopentech-private-prod
```
### Redis Configuration
@ -164,7 +164,7 @@ Copy and paste the following:
version: '3.8'
networks:
maple-private-prod:
mapleopentech-private-prod:
external: true
volumes:
@ -179,7 +179,7 @@ services:
image: redis:7-alpine
hostname: redis
networks:
- maple-private-prod
- mapleopentech-private-prod
volumes:
- redis-data:/data
secrets:
@ -240,16 +240,16 @@ Save and exit (`:wq` in vi).
### Step 2: Verify Shared Overlay Network
**Check if the maple-private-prod network exists:**
**Check if the mapleopentech-private-prod network exists:**
```bash
docker network ls | grep maple-private-prod
docker network ls | grep mapleopentech-private-prod
```
**You should see:**
```
abc123... maple-private-prod overlay swarm
abc123... mapleopentech-private-prod overlay swarm
```
**If you completed 02_cassandra.md** (Step 4), the network already exists and you're good to go!
@ -257,14 +257,14 @@ abc123... maple-private-prod overlay swarm
**If the network doesn't exist**, create it now:
```bash
# Create the shared maple-private-prod network
# Create the shared mapleopentech-private-prod network
docker network create \
--driver overlay \
--attachable \
maple-private-prod
mapleopentech-private-prod
# Verify it was created
docker network ls | grep maple-private-prod
docker network ls | grep mapleopentech-private-prod
```
**What is this network?**
@ -436,22 +436,22 @@ docker stack deploy -c redis-stack.yml redis
### Problem: Network Not Found During Deployment
**Symptom**: `network "maple-private-prod" is declared as external, but could not be found`
**Symptom**: `network "mapleopentech-private-prod" is declared as external, but could not be found`
**Solution:**
Create the shared `maple-private-prod` network first:
Create the shared `mapleopentech-private-prod` network first:
```bash
# Create the network
docker network create \
--driver overlay \
--attachable \
maple-private-prod
mapleopentech-private-prod
# Verify it exists
docker network ls | grep maple-private-prod
# Should show: maple-private-prod overlay swarm
docker network ls | grep mapleopentech-private-prod
# Should show: mapleopentech-private-prod overlay swarm
# Then deploy Redis
docker stack deploy -c redis-stack.yml redis
@ -487,10 +487,10 @@ docker stack deploy -c redis-stack.yml redis
# Must show: map[redis:true]
```
4. **Verify maple-private-prod network exists:**
4. **Verify mapleopentech-private-prod network exists:**
```bash
docker network ls | grep maple-private-prod
# Should show: maple-private-prod overlay swarm
docker network ls | grep mapleopentech-private-prod
# Should show: mapleopentech-private-prod overlay swarm
```
### Problem: Can't Connect (Authentication Failed)
@ -548,9 +548,9 @@ docker stack deploy -c redis-stack.yml redis
1. **Verify both services on same network:**
```bash
# Check your app is on maple-private-prod network
# Check your app is on mapleopentech-private-prod network
docker service inspect your_app --format '{{.Spec.TaskTemplate.Networks}}'
# Should show maple-private-prod
# Should show mapleopentech-private-prod
```
2. **Test DNS resolution:**

View file

@ -41,7 +41,7 @@ Internet (HTTPS) → Caddy (worker-6) → Backend (worker-6) → Cassandra/Redis
- **Image**: Ubuntu 24.04 LTS x64
- **Size**: Basic shared CPU, 2 GB / 2 vCPU ($18/mo)
- **Hostname**: `mapleopentech-swarm-worker-6-prod`
- **VPC Network**: Select same VPC as your swarm (maple-vpc-prod)
- **VPC Network**: Select same VPC as your swarm (mapleopentech-vpc-prod)
- **SSH Keys**: Add your SSH key
4. Click **Create Droplet**
5. Wait 1-2 minutes for droplet to provision
@ -349,8 +349,8 @@ dig www.getmaplepress.ca +short
We need two overlay networks for our services:
1. **maple-private-prod** - Backend connects to databases (already exists from guides 02-04)
2. **maple-public-prod** - NGINX and Backend communicate (new)
1. **mapleopentech-private-prod** - Backend connects to databases (already exists from guides 02-04)
2. **mapleopentech-public-prod** - NGINX and Backend communicate (new)
**On manager:**
@ -358,11 +358,11 @@ We need two overlay networks for our services:
ssh dockeradmin@<manager-public-ip>
# Check private network exists
docker network ls | grep maple-private-prod
# Should show: maple-private-prod (created in previous guides)
docker network ls | grep mapleopentech-private-prod
# Should show: mapleopentech-private-prod (created in previous guides)
# Create public network
docker network create --driver overlay --attachable maple-public-prod
docker network create --driver overlay --attachable mapleopentech-public-prod
# Verify both exist
docker network ls | grep maple
@ -371,8 +371,8 @@ docker network ls | grep maple
**Expected output:**
```
abc123... maple-private-prod overlay swarm
def456... maple-public-prod overlay swarm
abc123... mapleopentech-private-prod overlay swarm
def456... mapleopentech-public-prod overlay swarm
```
**Why two networks?**
@ -380,7 +380,7 @@ def456... maple-public-prod overlay swarm
- **Public**: NGINX forwards requests to Backend (internet-facing)
- Backend joins BOTH networks to receive requests and access databases
**✅ Checkpoint:** Both `maple-private-prod` and `maple-public-prod` networks exist
**✅ Checkpoint:** Both `mapleopentech-private-prod` and `mapleopentech-public-prod` networks exist
---
@ -601,9 +601,9 @@ vi maplepress-stack.yml
version: '3.8'
networks:
maple-private-prod:
mapleopentech-private-prod:
external: true
maple-public-prod:
mapleopentech-public-prod:
external: true
secrets:
@ -625,8 +625,8 @@ services:
image: registry.digitalocean.com/ssp/maplepress_backend:prod
hostname: maplepress-backend
networks:
- maple-public-prod # Receives requests from Caddy
- maple-private-prod # Accesses databases
- mapleopentech-public-prod # Receives requests from Caddy
- mapleopentech-private-prod # Accesses databases
secrets:
- maplepress_jwt_secret
- maplepress_ip_encryption_key
@ -871,7 +871,7 @@ docker service logs maplepress_backend --tail 100
# 1. Can't reach databases
# - Verify Cassandra running: docker service ls | grep cassandra
# - Verify Redis running: docker service ls | grep redis
# - Check backend is on maple-private-prod network
# - Check backend is on mapleopentech-private-prod network
# 2. Secrets missing
docker secret ls
@ -1047,9 +1047,9 @@ docker service logs -f maplepress_backend
docker service ls
# Should show: cassandra_cassandra-1, cassandra_cassandra-2, cassandra_cassandra-3, redis_redis, meilisearch_meilisearch
# 2. Verify backend is on maple-private-prod network
# 2. Verify backend is on mapleopentech-private-prod network
docker service inspect maplepress_backend --format '{{range .Spec.TaskTemplate.Networks}}{{.Target}} {{end}}'
# Should include maple-private-prod
# Should include mapleopentech-private-prod
# 3. Test DNS resolution from backend container
ssh dockeradmin@<worker-6-public-ip>

View file

@ -4,7 +4,7 @@
**Time to Complete**: 20-30 minutes
**Prerequisites**:
- ✅ Completed guide **05_backend.md** (Backend deployed and running)
- ✅ Backend service accessible on `maple-public-prod` network
- ✅ Backend service accessible on `mapleopentech-public-prod` network
- ✅ Domain name pointing to worker-6 public IP
- ✅ Email address for Let's Encrypt SSL certificate notifications
@ -59,7 +59,7 @@ Backend (worker-6)
Databases (Cassandra, Redis, Meilisearch on other workers)
```
**Key concept:** Caddy and Backend are both on worker-6, connected via the `maple-public-prod` Docker overlay network. Caddy can reach Backend by the hostname `backend` - Docker's built-in DNS resolves this to the backend container's IP automatically.
**Key concept:** Caddy and Backend are both on worker-6, connected via the `mapleopentech-public-prod` Docker overlay network. Caddy can reach Backend by the hostname `backend` - Docker's built-in DNS resolves this to the backend container's IP automatically.
---
@ -328,9 +328,9 @@ vi maplepress-stack.yml
version: '3.8'
networks:
maple-private-prod:
mapleopentech-private-prod:
external: true
maple-public-prod:
mapleopentech-public-prod:
external: true
volumes:
@ -362,8 +362,8 @@ services:
image: registry.digitalocean.com/ssp/maplepress_backend:prod
hostname: maplepress-backend
networks:
- maple-public-prod
- maple-private-prod
- mapleopentech-public-prod
- mapleopentech-private-prod
secrets:
- maplepress_jwt_secret
- maplepress_ip_encryption_key
@ -431,7 +431,7 @@ services:
image: caddy:2-alpine
hostname: caddy
networks:
- maple-public-prod
- mapleopentech-public-prod
ports:
# Port 80 - HTTP (for Let's Encrypt challenges and HTTP→HTTPS redirect)
# Using mode: host to bind directly to worker-6's network interface
@ -488,7 +488,7 @@ Save: `Esc`, then `:wq`, then `Enter`
**Understanding the stack file:**
- **`maple-public-prod` network**: Shared network with backend
- **`mapleopentech-public-prod` network**: Shared network with backend
- Both Caddy and Backend are connected here
- Allows Caddy to reach Backend by hostname
- `external: true` means we created this network earlier (in 05_backend.md)
@ -542,9 +542,9 @@ Before deploying, let's make sure everything is ready:
docker service ls | grep backend
# Should show: maplepress_backend 1/1 registry.digitalocean.com/ssp/maplepress_backend:prod
# 2. Check maple-public-prod network exists
docker network ls | grep maple-public-prod
# Should show: maple-public-prod overlay swarm
# 2. Check mapleopentech-public-prod network exists
docker network ls | grep mapleopentech-public-prod
# Should show: mapleopentech-public-prod overlay swarm
# 3. Verify worker-6 has backend label
docker node inspect mapleopentech-swarm-worker-6-prod --format '{{.Spec.Labels}}'
@ -734,8 +734,8 @@ All should show `1/1` in REPLICAS column.
docker network ls | grep maple
# Should show:
# abc123... maple-private-prod overlay swarm
# def456... maple-public-prod overlay swarm
# abc123... mapleopentech-private-prod overlay swarm
# def456... mapleopentech-public-prod overlay swarm
```
### 5.3 Verify Service Connectivity
@ -978,8 +978,8 @@ docker service logs maplepress_backend-caddy --tail 100
# - Stop conflicting service
# 3. Network not found
docker network ls | grep maple-public-prod
# If missing, create it: docker network create --driver overlay --attachable maple-public-prod
docker network ls | grep mapleopentech-public-prod
# If missing, create it: docker network create --driver overlay --attachable mapleopentech-public-prod
```
### Problem: Deployment Fails with "only updates to Labels are allowed"
@ -1245,7 +1245,7 @@ docker service ls | grep backend
# 2. Are both on same network?
docker service inspect maplepress_backend --format '{{range .Spec.TaskTemplate.Networks}}{{.Target}} {{end}}'
docker service inspect maplepress_backend-caddy --format '{{range .Spec.TaskTemplate.Networks}}{{.Target}} {{end}}'
# Both should include: maple-public-prod
# Both should include: mapleopentech-public-prod
# 3. Test from Caddy container
ssh dockeradmin@<worker-6-public-ip>
@ -1478,7 +1478,7 @@ Internet (HTTPS)
Caddy (worker-6) - Automatic SSL, reverse proxy
Backend (worker-6) - Your Go application
↓ maple-private-prod network
↓ mapleopentech-private-prod network
Cassandra (workers 1-3) - Database cluster
Redis (worker-4) - Cache
Meilisearch (worker-5) - Search engine

View file

@ -67,7 +67,7 @@ Internet (HTTPS)
- **Image**: Ubuntu 24.04 LTS x64
- **Size**: Basic shared CPU, 1 GB / 1 vCPU ($6/mo) - Frontend is lightweight
- **Hostname**: `mapleopentech-swarm-worker-7-prod`
- **VPC Network**: Select same VPC as your swarm (maple-vpc-prod)
- **VPC Network**: Select same VPC as your swarm (mapleopentech-vpc-prod)
- **SSH Keys**: Add your SSH key
4. Click **Create Droplet**
5. Wait 1-2 minutes for droplet to provision

View file

@ -364,8 +364,8 @@ dig www.maplefile.ca +short
We need two overlay networks for our services:
1. **maple-private-prod** - Backend connects to databases (already exists from guides 02-04)
2. **maple-public-prod** - Caddy and Backend communicate (already exists from guide 06)
1. **mapleopentech-private-prod** - Backend connects to databases (already exists from guides 02-04)
2. **mapleopentech-public-prod** - Caddy and Backend communicate (already exists from guide 06)
**On manager:**
@ -376,15 +376,15 @@ ssh dockeradmin@143.110.210.162
docker network ls | grep maple
# Should show:
# maple-private-prod overlay swarm
# maple-public-prod overlay swarm
# mapleopentech-private-prod overlay swarm
# mapleopentech-public-prod overlay swarm
```
**If maple-public-prod doesn't exist, create it:**
**If mapleopentech-public-prod doesn't exist, create it:**
```bash
# Create public network
docker network create --driver overlay --attachable maple-public-prod
docker network create --driver overlay --attachable mapleopentech-public-prod
# Verify both exist
docker network ls | grep maple
@ -395,7 +395,7 @@ docker network ls | grep maple
- **Public**: Caddy forwards requests to Backend (internet-facing)
- Backend joins BOTH networks to receive requests and access databases
**✅ Checkpoint:** Both `maple-private-prod` and `maple-public-prod` networks exist
**✅ Checkpoint:** Both `mapleopentech-private-prod` and `mapleopentech-public-prod` networks exist
---
@ -623,9 +623,9 @@ vi ~/stacks/maplefile-stack.yml
version: '3.8'
networks:
maple-private-prod:
mapleopentech-private-prod:
external: true
maple-public-prod:
mapleopentech-public-prod:
external: true
secrets:
@ -645,8 +645,8 @@ services:
image: registry.digitalocean.com/ssp/maplefile-backend:prod
hostname: maplefile-backend
networks:
- maple-public-prod # Receives requests from Caddy
- maple-private-prod # Accesses databases
- mapleopentech-public-prod # Receives requests from Caddy
- mapleopentech-private-prod # Accesses databases
secrets:
- maplefile_jwt_secret
- redis_password
@ -935,7 +935,7 @@ docker service logs maplefile_backend --tail 100
# 1. Can't reach databases
# - Verify Cassandra running: docker service ls | grep cassandra
# - Verify Redis running: docker service ls | grep redis
# - Check backend is on maple-private-prod network
# - Check backend is on mapleopentech-private-prod network
# 2. Secrets missing
docker secret ls
@ -1027,9 +1027,9 @@ docker stack deploy -c ~/stacks/maplefile-stack.yml maplefile
docker service ls | grep cassandra
# Should show: cassandra_cassandra-1, cassandra_cassandra-2, cassandra_cassandra-3
# 2. Verify backend is on maple-private-prod network
# 2. Verify backend is on mapleopentech-private-prod network
docker service inspect maplefile_backend --format '{{range .Spec.TaskTemplate.Networks}}{{.Target}} {{end}}'
# Should include maple-private-prod
# Should include mapleopentech-private-prod
# 3. Test DNS resolution from backend container
ssh dockeradmin@143.110.212.253
@ -1189,14 +1189,14 @@ cd ~/stacks
## Network Architecture Notes
**Private Network (maple-private-prod):**
**Private Network (mapleopentech-private-prod):**
- Cassandra cluster (3 nodes) - Shared by ALL apps
- Redis - Shared by ALL apps (different DB numbers per app)
- Both MaplePress and MapleFile use same infrastructure
- MaplePress uses Cassandra keyspace: `maplepress`, Redis DB: 0
- MapleFile uses Cassandra keyspace: `maplefile`, Redis DB: 1
**Public Network (maple-public-prod):**
**Public Network (mapleopentech-public-prod):**
- Each app gets its own Caddy instance
- maplefile-backend-caddy (to be deployed in Part 2)
- maplepress-backend-caddy (already deployed)

View file

@ -4,7 +4,7 @@
**Time to Complete**: 20-30 minutes
**Prerequisites**:
- ✅ Completed guide **09_maplefile_backend.md** (Backend deployed and running)
- ✅ Backend service accessible on `maple-public-prod` network
- ✅ Backend service accessible on `mapleopentech-public-prod` network
- ✅ Domain name `maplefile.ca` pointing to worker-8 public IP
- ✅ Email address for Let's Encrypt SSL certificate notifications
@ -59,7 +59,7 @@ Backend (worker-8)
Databases (Cassandra, Redis on other workers)
```
**Key concept:** Caddy and Backend are both on worker-8, connected via the `maple-public-prod` Docker overlay network. Caddy can reach Backend by the hostname `maplefile-backend` - Docker's built-in DNS resolves this to the backend container's IP automatically.
**Key concept:** Caddy and Backend are both on worker-8, connected via the `mapleopentech-public-prod` Docker overlay network. Caddy can reach Backend by the hostname `maplefile-backend` - Docker's built-in DNS resolves this to the backend container's IP automatically.
---
@ -345,7 +345,7 @@ configs:
image: caddy:2.9.1-alpine
hostname: maplefile-caddy
networks:
- maple-public-prod
- mapleopentech-public-prod
ports:
# Port 80 - HTTP (for Let's Encrypt challenges and HTTP→HTTPS redirect)
# Using mode: host to bind directly to worker-8's network interface
@ -402,7 +402,7 @@ Save: `Esc`, then `:wq`, then `Enter`
**Understanding the stack file:**
- **`maple-public-prod` network**: Shared network with backend
- **`mapleopentech-public-prod` network**: Shared network with backend
- Both Caddy and Backend are connected here
- Allows Caddy to reach Backend by hostname
- `external: true` means we created this network earlier (in 09_maplefile_backend.md)
@ -431,7 +431,7 @@ Save: `Esc`, then `:wq`, then `Enter`
- **Placement constraint**:
- `node.labels.maplefile-backend == true` - Same as backend (worker-8)
- Caddy and Backend MUST be on the same node to share `maple-public-prod` network
- Caddy and Backend MUST be on the same node to share `mapleopentech-public-prod` network
- Docker overlay networks work best when services are colocated
### 3.2 Deploy Updated Stack
@ -679,12 +679,12 @@ docker service logs maplefile_backend-caddy --tail 50
# Should show: Running
```
2. **Backend not on maple-public-prod network**
2. **Backend not on mapleopentech-public-prod network**
```bash
# Check backend networks
docker service inspect maplefile_backend --format '{{json .Spec.TaskTemplate.Networks}}'
# Should include maple-public-prod
# Should include mapleopentech-public-prod
```
3. **Wrong hostname in Caddyfile**

View file

@ -75,7 +75,7 @@ Choose this approach if you want better isolation and independent scaling.
- **Image**: Ubuntu 24.04 LTS x64
- **Size**: Basic shared CPU, 1 GB / 1 vCPU ($6/mo) - Frontend is lightweight
- **Hostname**: `mapleopentech-swarm-worker-9-prod`
- **VPC Network**: Select same VPC as your swarm (maple-vpc-prod)
- **VPC Network**: Select same VPC as your swarm (mapleopentech-vpc-prod)
- **SSH Keys**: Add your SSH key
- **Tags**: Add tags like `production`, `maplefile`, `frontend`
4. Click **Create Droplet**

View file

@ -27,9 +27,9 @@ Internet (HTTPS)
├─ getmaplepress.ca → Backend API (worker-6)
└─ getmaplepress.com → Frontend (worker-7)
Backend Services (maple-public-prod + maple-private-prod)
Backend Services (mapleopentech-public-prod + mapleopentech-private-prod)
Databases (maple-private-prod only)
Databases (mapleopentech-private-prod only)
├─ Cassandra: 3-node cluster (workers 2,3,4) - RF=3, QUORUM
├─ Redis: Single instance (worker-1/manager)
└─ Meilisearch: Single instance (worker-5)
@ -51,7 +51,7 @@ Internet (HTTPS)
- Command-line tools verification
**[00-network-architecture.md](00-network-architecture.md)** - Network design
- Network segmentation strategy (`maple-private-prod` vs `maple-public-prod`)
- Network segmentation strategy (`mapleopentech-private-prod` vs `mapleopentech-public-prod`)
- Security principles (defense in depth)
- Service communication patterns
- Firewall rules overview
@ -360,13 +360,13 @@ setup/
### Network Architecture
**`maple-private-prod` (overlay network):**
**`mapleopentech-private-prod` (overlay network):**
- All databases (Cassandra, Redis, Meilisearch)
- Backend services (access to databases)
- **No internet access** (security)
- Internal-only communication
**`maple-public-prod` (overlay network):**
**`mapleopentech-public-prod` (overlay network):**
- Caddy reverse proxies
- Backend services (receive HTTP requests)
- Ports 80/443 exposed to internet
@ -447,7 +447,7 @@ docker logs <container-id>
docker service inspect maplepress_backend
# Check network
docker network inspect maple-private-prod
docker network inspect mapleopentech-private-prod
# List configs
docker config ls

View file

@ -1,9 +1,9 @@
version: '3.8'
version: "3.8"
networks:
maple-private-prod:
mapleopentech-private-prod:
external: true
maple-public-prod:
mapleopentech-public-prod:
external: true
secrets:
@ -24,8 +24,8 @@ services:
image: registry.digitalocean.com/ssp/maplepress_backend:latest
hostname: backend
networks:
- maple-public-prod # Receive requests from NGINX
- maple-private-prod # Access databases
- mapleopentech-public-prod # Receive requests from NGINX
- mapleopentech-private-prod # Access databases
secrets:
- maplepress_jwt_secret
- redis_password
@ -93,18 +93,27 @@ services:
resources:
limits:
memory: 1G
cpus: '1.0'
cpus: "1.0"
reservations:
memory: 512M
cpus: '0.5'
cpus: "0.5"
update_config:
parallelism: 1
delay: 10s
failure_action: rollback
order: start-first # Zero-downtime: start new before stopping old
order: start-first # Zero-downtime: start new before stopping old
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "--header=X-Tenant-ID: healthcheck", "http://localhost:8000/health"]
test:
[
"CMD",
"wget",
"--no-verbose",
"--tries=1",
"--spider",
"--header=X-Tenant-ID: healthcheck",
"http://localhost:8000/health",
]
interval: 30s
timeout: 5s
retries: 3

View file

@ -1,7 +1,7 @@
version: '3.8'
version: "3.8"
networks:
maple-private-prod:
mapleopentech-private-prod:
external: true
volumes:
@ -14,9 +14,9 @@ services:
image: cassandra:5.0.4
hostname: cassandra-1
networks:
- maple-private-prod
- mapleopentech-private-prod
environment:
- CASSANDRA_CLUSTER_NAME=maple-prod-cluster
- CASSANDRA_CLUSTER_NAME=mapleopentech-prod-cluster
- CASSANDRA_DC=datacenter1
- CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch
- CASSANDRA_SEEDS=cassandra-1,cassandra-2,cassandra-3
@ -44,9 +44,9 @@ services:
image: cassandra:5.0.4
hostname: cassandra-2
networks:
- maple-private-prod
- mapleopentech-private-prod
environment:
- CASSANDRA_CLUSTER_NAME=maple-prod-cluster
- CASSANDRA_CLUSTER_NAME=mapleopentech-prod-cluster
- CASSANDRA_DC=datacenter1
- CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch
- CASSANDRA_SEEDS=cassandra-1,cassandra-2,cassandra-3
@ -74,9 +74,9 @@ services:
image: cassandra:5.0.4
hostname: cassandra-3
networks:
- maple-private-prod
- mapleopentech-private-prod
environment:
- CASSANDRA_CLUSTER_NAME=maple-prod-cluster
- CASSANDRA_CLUSTER_NAME=mapleopentech-prod-cluster
- CASSANDRA_DC=datacenter1
- CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch
- CASSANDRA_SEEDS=cassandra-1,cassandra-2,cassandra-3

View file

@ -1,7 +1,7 @@
version: '3.8'
version: "3.8"
networks:
maple-private-prod:
mapleopentech-private-prod:
external: true
volumes:
@ -16,7 +16,7 @@ services:
image: getmeili/meilisearch:v1.5
hostname: meilisearch
networks:
- maple-private-prod
- mapleopentech-private-prod
volumes:
- meilisearch-data:/meili_data
secrets:
@ -49,7 +49,15 @@ services:
reservations:
memory: 768M
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:7700/health"]
test:
[
"CMD",
"wget",
"--no-verbose",
"--tries=1",
"--spider",
"http://localhost:7700/health",
]
interval: 30s
timeout: 10s
retries: 3

View file

@ -1,7 +1,7 @@
version: '3.8'
version: "3.8"
networks:
maple-public-prod:
mapleopentech-public-prod:
external: true
volumes:
@ -13,14 +13,14 @@ services:
image: nginx:alpine
hostname: nginx
networks:
- maple-public-prod
- mapleopentech-public-prod
ports:
- "80:80"
- "443:443"
volumes:
- nginx-ssl-certs:/etc/letsencrypt
- nginx-ssl-www:/var/www/certbot
- /var/run/docker.sock:/tmp/docker.sock:ro # For nginx-proxy
- /var/run/docker.sock:/tmp/docker.sock:ro # For nginx-proxy
configs:
- source: nginx_config
target: /etc/nginx/nginx.conf
@ -30,7 +30,7 @@ services:
replicas: 1
placement:
constraints:
- node.labels.backend == true # Same node as backend
- node.labels.backend == true # Same node as backend
restart_policy:
condition: on-failure
delay: 5s
@ -38,12 +38,20 @@ services:
resources:
limits:
memory: 256M
cpus: '0.5'
cpus: "0.5"
reservations:
memory: 128M
cpus: '0.25'
cpus: "0.25"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:80/health"]
test:
[
"CMD",
"wget",
"--no-verbose",
"--tries=1",
"--spider",
"http://localhost:80/health",
]
interval: 30s
timeout: 5s
retries: 3

View file

@ -1,7 +1,7 @@
version: '3.8'
version: "3.8"
networks:
maple-private-prod:
mapleopentech-private-prod:
external: true
volumes:
@ -16,7 +16,7 @@ services:
image: redis:7-alpine
hostname: redis
networks:
- maple-private-prod
- mapleopentech-private-prod
volumes:
- redis-data:/data
secrets:
@ -66,7 +66,13 @@ services:
reservations:
memory: 512M
healthcheck:
test: ["CMD", "sh", "-c", "redis-cli -a $$(cat /run/secrets/redis_password) ping | grep PONG"]
test:
[
"CMD",
"sh",
"-c",
"redis-cli -a $$(cat /run/secrets/redis_password) ping | grep PONG",
]
interval: 10s
timeout: 3s
retries: 3

View file

@ -11,7 +11,7 @@ bind 0.0.0.0
port 6379
# Protected mode disabled (we rely on Docker network isolation)
# Only containers on maple-prod overlay network can access
# Only containers on mapleopentech-prod overlay network can access
protected-mode no
# ==============================================================================

View file

@ -50,7 +50,7 @@ tasks:
silent: true
cmds:
- |
if ! docker network inspect maple-dev >/dev/null 2>&1; then
if ! docker network inspect mapleopentech-dev >/dev/null 2>&1; then
echo "❌ Infrastructure not running!"
echo ""
echo "Start it with:"
@ -58,7 +58,7 @@ tasks:
echo ""
exit 1
fi
if ! docker ps | grep -q maple-cassandra-1-dev; then
if ! docker ps | grep -q mapleopentech-cassandra-1-dev; then
echo "❌ Cassandra not running!"
echo ""
echo "Start it with:"
@ -89,7 +89,7 @@ tasks:
deps: [build]
cmds:
- echo "⚠️ Dropping keyspace 'maplefile'..."
- docker exec maple-cassandra-1-dev cqlsh -e "DROP KEYSPACE IF EXISTS maplefile;"
- docker exec mapleopentech-cassandra-1-dev cqlsh -e "DROP KEYSPACE IF EXISTS maplefile;"
- echo "✅ Keyspace dropped"
- echo "🔄 Running migrations to recreate schema..."
- ./maplefile-backend migrate up
@ -169,11 +169,11 @@ tasks:
cmds:
- echo "Building version {{.GIT_COMMIT}} at {{.BUILD_TIME}}"
- docker build -f Dockerfile --rm
--build-arg GIT_COMMIT={{.GIT_COMMIT_FULL}}
--build-arg BUILD_TIME={{.BUILD_TIME}}
-t registry.digitalocean.com/ssp/maplefile-backend:prod
-t registry.digitalocean.com/ssp/maplefile-backend:{{.GIT_COMMIT}}
--platform linux/amd64 .
--build-arg GIT_COMMIT={{.GIT_COMMIT_FULL}}
--build-arg BUILD_TIME={{.BUILD_TIME}}
-t registry.digitalocean.com/ssp/maplefile-backend:prod
-t registry.digitalocean.com/ssp/maplefile-backend:{{.GIT_COMMIT}}
--platform linux/amd64 .
- docker push registry.digitalocean.com/ssp/maplefile-backend:prod
- docker push registry.digitalocean.com/ssp/maplefile-backend:{{.GIT_COMMIT}}
- echo "Deployed version {{.GIT_COMMIT}} - use this to verify on production"

View file

@ -1,6 +1,6 @@
# Use external network from infrastructure
networks:
maple-dev:
mapleopentech-dev:
external: true
services:
@ -110,10 +110,11 @@ services:
volumes:
- ./:/go/src/codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend
networks:
- maple-dev
- mapleopentech-dev
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:${SERVER_PORT:-8000}/health"]
test:
["CMD", "curl", "-f", "http://localhost:${SERVER_PORT:-8000}/health"]
interval: 30s
timeout: 5s
retries: 3

View file

@ -2,4 +2,70 @@ module codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend
go 1.25.4
require go.uber.org/mock v0.6.0 // indirect
require (
codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend v0.0.0-20251202195307-f4a49ad4b9d0
github.com/awnumar/memguard v0.23.0
github.com/aws/aws-sdk-go-v2 v1.40.1
github.com/aws/aws-sdk-go-v2/config v1.32.3
github.com/aws/aws-sdk-go-v2/credentials v1.19.3
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.0
github.com/aws/smithy-go v1.24.0
github.com/bsm/redislock v0.9.4
github.com/gocql/gocql v1.7.0
github.com/golang-jwt/jwt/v5 v5.3.0
github.com/golang-migrate/migrate/v4 v4.19.1
github.com/google/wire v0.7.0
github.com/mailgun/mailgun-go/v4 v4.23.0
github.com/oschwald/geoip2-golang v1.13.0
github.com/redis/go-redis/v9 v9.17.2
github.com/robfig/cron/v3 v3.0.1
github.com/spf13/cobra v1.10.1
github.com/stretchr/testify v1.10.0
github.com/tyler-smith/go-bip39 v1.1.0
go.uber.org/mock v0.6.0
go.uber.org/zap v1.27.1
golang.org/x/crypto v0.45.0
golang.org/x/vuln v1.1.4
)
require (
github.com/awnumar/memcall v0.4.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.15 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.15 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.15 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.15 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.6 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.15 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.15 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.3 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.6 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.11 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.41.3 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/go-chi/chi/v5 v5.2.1 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/subcommands v1.2.0 // indirect
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailgun/errors v0.4.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/oschwald/maxminddb-golang v1.13.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/spf13/pflag v1.0.9 // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/mod v0.29.0 // indirect
golang.org/x/sync v0.18.0 // indirect
golang.org/x/sys v0.38.0 // indirect
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect
golang.org/x/tools v0.38.0 // indirect
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View file

@ -1,2 +1,217 @@
codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend v0.0.0-20251202195307-f4a49ad4b9d0 h1:B6BOeHvghv8GdsYE9WjrmY9dXGmBGlOvt5w204dL24Y=
codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend v0.0.0-20251202195307-f4a49ad4b9d0/go.mod h1:2FLpwTrS59a2D/CzoMBfC9SGHFhlMfX+8jXKW+Mpc2I=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/awnumar/memcall v0.4.0 h1:B7hgZYdfH6Ot1Goaz8jGne/7i8xD4taZie/PNSFZ29g=
github.com/awnumar/memcall v0.4.0/go.mod h1:8xOx1YbfyuCg3Fy6TO8DK0kZUua3V42/goA5Ru47E8w=
github.com/awnumar/memguard v0.23.0 h1:sJ3a1/SWlcuKIQ7MV+R9p0Pvo9CWsMbGZvcZQtmc68A=
github.com/awnumar/memguard v0.23.0/go.mod h1:olVofBrsPdITtJ2HgxQKrEYEMyIBAIciVG4wNnZhW9M=
github.com/aws/aws-sdk-go-v2 v1.40.1 h1:difXb4maDZkRH0x//Qkwcfpdg1XQVXEAEs2DdXldFFc=
github.com/aws/aws-sdk-go-v2 v1.40.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
github.com/aws/aws-sdk-go-v2/config v1.32.3 h1:cpz7H2uMNTDa0h/5CYL5dLUEzPSLo2g0NkbxTRJtSSU=
github.com/aws/aws-sdk-go-v2/config v1.32.3/go.mod h1:srtPKaJJe3McW6T/+GMBZyIPc+SeqJsNPJsd4mOYZ6s=
github.com/aws/aws-sdk-go-v2/credentials v1.19.3 h1:01Ym72hK43hjwDeJUfi1l2oYLXBAOR8gNSZNmXmvuas=
github.com/aws/aws-sdk-go-v2/credentials v1.19.3/go.mod h1:55nWF/Sr9Zvls0bGnWkRxUdhzKqj9uRNlPvgV1vgxKc=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.15 h1:utxLraaifrSBkeyII9mIbVwXXWrZdlPO7FIKmyLCEcY=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.15/go.mod h1:hW6zjYUDQwfz3icf4g2O41PHi77u10oAzJ84iSzR/lo=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.15 h1:Y5YXgygXwDI5P4RkteB5yF7v35neH7LfJKBG+hzIons=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.15/go.mod h1:K+/1EpG42dFSY7CBj+Fruzm8PsCGWTXJ3jdeJ659oGQ=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.15 h1:AvltKnW9ewxX2hFmQS0FyJH93aSvJVUEFvXfU+HWtSE=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.15/go.mod h1:3I4oCdZdmgrREhU74qS1dK9yZ62yumob+58AbFR4cQA=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.15 h1:NLYTEyZmVZo0Qh183sC8nC+ydJXOOeIL/qI/sS3PdLY=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.15/go.mod h1:Z803iB3B0bc8oJV8zH2PERLRfQUJ2n2BXISpsA4+O1M=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.6 h1:P1MU/SuhadGvg2jtviDXPEejU3jBNhoeeAlRadHzvHI=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.6/go.mod h1:5KYaMG6wmVKMFBSfWoyG/zH8pWwzQFnKgpoSRlXHKdQ=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.15 h1:3/u/4yZOffg5jdNk1sDpOQ4Y+R6Xbh+GzpDrSZjuy3U=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.15/go.mod h1:4Zkjq0FKjE78NKjabuM4tRXKFzUJWXgP0ItEZK8l7JU=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.15 h1:wsSQ4SVz5YE1crz0Ap7VBZrV4nNqZt4CIBBT8mnwoNc=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.15/go.mod h1:I7sditnFGtYMIqPRU1QoHZAUrXkGp4SczmlLwrNPlD0=
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.0 h1:IrbE3B8O9pm3lsg96AXIN5MXX4pECEuExh/A0Du3AuI=
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.0/go.mod h1:/sJLzHtiiZvs6C1RbxS/anSAFwZD6oC6M/kotQzOiLw=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.3 h1:d/6xOGIllc/XW1lzG9a4AUBMmpLA9PXcQnVPTuHHcik=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.3/go.mod h1:fQ7E7Qj9GiW8y0ClD7cUJk3Bz5Iw8wZkWDHsTe8vDKs=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.6 h1:8sTTiw+9yuNXcfWeqKF2x01GqCF49CpP4Z9nKrrk/ts=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.6/go.mod h1:8WYg+Y40Sn3X2hioaaWAAIngndR8n1XFdRPPX+7QBaM=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.11 h1:E+KqWoVsSrj1tJ6I/fjDIu5xoS2Zacuu1zT+H7KtiIk=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.11/go.mod h1:qyWHz+4lvkXcr3+PoGlGHEI+3DLLiU6/GdrFfMaAhB0=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.3 h1:tzMkjh0yTChUqJDgGkcDdxvZDSrJ/WB6R6ymI5ehqJI=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.3/go.mod h1:T270C0R5sZNLbWUe8ueiAF42XSZxxPocTaGSgs5c/60=
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY=
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bsm/redislock v0.9.4 h1:X/Wse1DPpiQgHbVYRE9zv6m070UcKoOGekgvpNhiSvw=
github.com/bsm/redislock v0.9.4/go.mod h1:Epf7AJLiSFwLCiZcfi6pWFO/8eAYrYpQXFxEDPoDeAk=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dhui/dktest v0.4.6 h1:+DPKyScKSEp3VLtbMDHcUq6V5Lm5zfZZVb0Sk7Ahom4=
github.com/dhui/dktest v0.4.6/go.mod h1:JHTSYDtKkvFNFHJKqCzVzqXecyv+tKt8EzceOmQOgbU=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI=
github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/gocql/gocql v1.7.0 h1:O+7U7/1gSN7QTEAaMEsJc1Oq2QHXvCWoF3DFK9HDHus=
github.com/gocql/gocql v1.7.0/go.mod h1:vnlvXyFZeLBF0Wy+RS8hrOdbn0UWsWtdg07XJnFxZ+4=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA=
github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RAtvaGgKxc+8FQIpxHgsF+HBzPyYL2cyVU=
github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786/go.mod h1:apVn/GCasLZUVpAJ6oWAuyP7Ne7CEsQbTnc0plM3m+o=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4=
github.com/google/wire v0.7.0/go.mod h1:n6YbUQD9cPKTnHXEBN2DXlOp/mVADhVErcMFb0v3J18=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mailgun/errors v0.4.0 h1:6LFBvod6VIW83CMIOT9sYNp28TCX0NejFPP4dSX++i8=
github.com/mailgun/errors v0.4.0/go.mod h1:xGBaaKdEdQT0/FhwvoXv4oBaqqmVZz9P1XEnvD/onc0=
github.com/mailgun/mailgun-go/v4 v4.23.0 h1:jPEMJzzin2s7lvehcfv/0UkyBu18GvcURPr2+xtZRbk=
github.com/mailgun/mailgun-go/v4 v4.23.0/go.mod h1:imTtizoFtpfZqPqGP8vltVBB6q9yWcv6llBhfFeElZU=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/oschwald/geoip2-golang v1.13.0 h1:Q44/Ldc703pasJeP5V9+aFSZFmBN7DKHbNsSFzQATJI=
github.com/oschwald/geoip2-golang v1.13.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo=
github.com/oschwald/maxminddb-golang v1.13.0 h1:R8xBorY71s84yO06NgTmQvqvTvlS/bnYZrrWX1MElnU=
github.com/oschwald/maxminddb-golang v1.13.0/go.mod h1:BU0z8BfFVhi1LQaonTwwGQlsHUEu9pWNdMfmq4ztm0o=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.17.2 h1:P2EGsA4qVIM3Pp+aPocCJ7DguDHhqrXNhVcEp4ViluI=
github.com/redis/go-redis/v9 v9.17.2/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU=
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
golang.org/x/tools/go/expect v0.1.0-deprecated h1:jY2C5HGYR5lqex3gEniOQL0r7Dq5+VGVgY1nudX5lXY=
golang.org/x/tools/go/expect v0.1.0-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM=
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8=
golang.org/x/vuln v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I=
golang.org/x/vuln v1.1.4/go.mod h1:F+45wmU18ym/ca5PLTPLsSzr2KppzswxPP603ldA67s=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View file

@ -106,7 +106,7 @@ LOGGER_FORMAT=console
# For running OUTSIDE Docker:
# Change to: MEILISEARCH_HOST=http://localhost:7700
MEILISEARCH_HOST=http://meilisearch:7700
MEILISEARCH_API_KEY=maple-dev-master-key-change-in-production
MEILISEARCH_API_KEY=mapleopentech-dev-master-key-change-in-production
MEILISEARCH_INDEX_PREFIX=site_
# ============================================================================

View file

@ -319,7 +319,7 @@ JWT tokens expire after 60 minutes. Re-run the [registration step](#testing-the-
**Verify:**
```bash
docker exec maple-wordpress-dev curl http://maplepress-backend-dev:8000/health
docker exec mapleopentech-wordpress-dev curl http://maplepress-backend-dev:8000/health
```
## 🛠️ Technology Stack

View file

@ -50,7 +50,7 @@ tasks:
silent: true
cmds:
- |
if ! docker network inspect maple-dev >/dev/null 2>&1; then
if ! docker network inspect mapleopentech-dev >/dev/null 2>&1; then
echo "❌ Infrastructure not running!"
echo ""
echo "Start it with:"
@ -58,7 +58,7 @@ tasks:
echo ""
exit 1
fi
if ! docker ps | grep -q maple-cassandra-1-dev; then
if ! docker ps | grep -q mapleopentech-cassandra-1-dev; then
echo "❌ Cassandra not running!"
echo ""
echo "Start it with:"
@ -89,7 +89,7 @@ tasks:
deps: [build]
cmds:
- echo "⚠️ Dropping keyspace 'maplepress'..."
- docker exec maple-cassandra-1-dev cqlsh -e "DROP KEYSPACE IF EXISTS maplepress;"
- docker exec mapleopentech-cassandra-1-dev cqlsh -e "DROP KEYSPACE IF EXISTS maplepress;"
- echo "✅ Keyspace dropped"
- echo "🔄 Running migrations to recreate schema..."
- ./maplepress-backend migrate up

View file

@ -1,6 +1,6 @@
# Use external network from infrastructure
networks:
maple-dev:
mapleopentech-dev:
external: true
services:
@ -41,7 +41,7 @@ services:
# Meilisearch Configuration (if needed)
MEILISEARCH_HOST: ${MEILISEARCH_HOST:-http://meilisearch:7700}
MEILISEARCH_API_KEY: ${MEILISEARCH_API_KEY:-maple-dev-master-key-change-in-production}
MEILISEARCH_API_KEY: ${MEILISEARCH_API_KEY:-mapleopentech-dev-master-key-change-in-production}
# S3 Configuration (SeaweedFS - S3-compatible storage)
AWS_ACCESS_KEY: ${AWS_ACCESS_KEY:-any}
@ -63,10 +63,18 @@ services:
volumes:
- ./:/go/src/codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend
networks:
- maple-dev
- mapleopentech-dev
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "-H", "X-Tenant-ID: healthcheck", "http://localhost:${SERVER_PORT:-8000}/health"]
test:
[
"CMD",
"curl",
"-f",
"-H",
"X-Tenant-ID: healthcheck",
"http://localhost:${SERVER_PORT:-8000}/health",
]
interval: 30s
timeout: 5s
retries: 3

View file

@ -2596,7 +2596,7 @@ CMD ["/app/app-backend", "daemon"]
```yaml
# Use external network from shared infrastructure
networks:
maple-dev:
mapleopentech-dev:
external: true
services:
@ -2640,7 +2640,7 @@ services:
volumes:
- ./:/go/src/codeberg.org/mapleopentech/monorepo/cloud/your-backend-name
networks:
- maple-dev
- mapleopentech-dev
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:${SERVER_PORT:-8000}/health"]

View file

@ -212,7 +212,7 @@ curl -X POST http://localhost:8000/api/v1/login \
**Verify from WordPress container**:
```bash
docker exec maple-wordpress-dev curl http://maplepress-backend-dev:8000/health
docker exec mapleopentech-wordpress-dev curl http://maplepress-backend-dev:8000/health
# Should return: {"status":"healthy"}
```
@ -322,8 +322,8 @@ task build # Build binary (only for manual operations)
task migrate:up # Manual migration (only if needed)
# View infrastructure logs
docker logs maple-cassandra-1-dev # Cassandra logs
docker logs maple-redis-dev # Redis logs
docker logs mapleopentech-cassandra-1-dev # Cassandra logs
docker logs mapleopentech-redis-dev # Redis logs
```
---