# ByteLyst Single-VM Deployment — Test Plan

> End-to-end validation steps for verifying a successful deployment.
> Run these after `setup.sh` completes all 8 phases.

---

## Quick Validation (2 minutes)

```bash
# 1. Run the generated health check script
/opt/bytelyst/check-health.sh

# 2. Quick dry-run to verify all prerequisites are satisfied
sudo ./setup.sh --dry-run
```

If all checks pass, the deployment is healthy. For deeper validation, continue below.

---

## Phase-by-Phase Verification

### Phase 1: System Dependencies

```bash
# Docker
docker --version                       # Expect: Docker version 2x.x+
docker compose version                 # Expect: Docker Compose version v2.x+
docker info | grep "Server Version"    # Daemon running

# Node.js + pnpm
node --version                         # Expect: v22.x
pnpm --version                         # Expect: 10.6.5

# Ollama
ollama --version                       # Expect: ollama version x.x.x
curl -s http://localhost:11434/api/version | jq .  # API responding
systemctl is-active ollama             # Expect: active

# System tools
git --version && jq --version && curl --version | head -1
```

### Phase 2: Gitea + CI Runner

```bash
# Gitea API
curl -s http://localhost:3300/api/v1/version | jq .
# Expect: {"version":"1.22.x"}

# Gitea admin auth
curl -s -u bytelyst-admin:ByteLyst2026! \
  http://localhost:3300/api/v1/user | jq .login
# Expect: "bytelyst-admin"

# Gitea org exists
curl -s http://localhost:3300/api/v1/orgs/bytelyst | jq .username
# Expect: "bytelyst"

# Gitea npm token saved
cat /opt/bytelyst/.gitea_token
# Expect: non-empty token string

# act_runner service
systemctl is-active act_runner         # Expect: active
```

### Phase 3: Repositories

```bash
# All 12 repos cloned
ls -1d /opt/bytelyst/learning_ai_* | wc -l
# Expect: 12

# Each repo has .git
for repo in /opt/bytelyst/learning_ai_*; do
  echo "$(basename $repo): $([ -d $repo/.git ] && echo OK || echo MISSING)"
done
```

### Phase 4-5: Packages Built + Published

```bash
# Packages built (dist/ exists)
ls /opt/bytelyst/learning_ai_common_plat/packages/*/dist/ 2>/dev/null | head -5
# Expect: files present

# Packages in Gitea registry
curl -s http://localhost:3300/api/packages/bytelyst/npm/ | jq '.[].name' | head -10
# Expect: @bytelyst/errors, @bytelyst/config, etc.
```

### Phase 6: Environment Config

```bash
# .env.ecosystem generated
cat /opt/bytelyst/learning_ai_common_plat/.env.ecosystem | head -5
# Expect: COSMOS_ENDPOINT, COSMOS_KEY, etc.

# Key values present
grep NODE_ENV /opt/bytelyst/learning_ai_common_plat/.env.ecosystem
# Expect: NODE_ENV=production

grep CORS_ORIGIN /opt/bytelyst/learning_ai_common_plat/.env.ecosystem
# Expect: CORS_ORIGIN=*

grep JWT_SECRET /opt/bytelyst/learning_ai_common_plat/.env.ecosystem
# Expect: non-empty random value
```

### Phase 7: Docker Services Running

```bash
# All 31 services running
cd /opt/bytelyst/learning_ai_common_plat
docker compose -f docker-compose.ecosystem.yml ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}" | head -35

# Count running containers
docker compose -f docker-compose.ecosystem.yml ps -q | wc -l
# Expect: 31
```

### Phase 8: Health Checks

Run each category. All should return HTTP 200.

```bash
# ── Infrastructure ──
curl -sf http://localhost:3300/api/v1/version    && echo " Gitea OK"
curl -sf http://localhost:11434/api/version       && echo " Ollama OK"
curl -sf http://localhost:1234                     && echo " Cosmos Explorer OK"
curl -sf http://localhost:10000                    && echo " Azurite OK"
curl -sf http://localhost:8025                     && echo " Mailpit OK"
curl -sf http://localhost:3100/ready               && echo " Loki OK"
curl -sf http://localhost:3000/api/health          && echo " Grafana OK"
curl -sf http://localhost:8080/api/overview        && echo " Traefik OK"

# ── Platform Services ──
curl -sf http://localhost:4003/health | jq .status  # platform-service
curl -sf http://localhost:4005/health | jq .status  # extraction-service
curl -sf http://localhost:4007/health | jq .status  # mcp-server

# ── Dashboards ──
curl -sf http://localhost:3001 | head -1            # admin-web
curl -sf http://localhost:3003 | head -1            # tracker-web

# ── Product Backends ──
for port in 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019; do
  status=$(curl -sf http://localhost:${port}/health | jq -r .status 2>/dev/null)
  echo "  :${port} -> ${status:-FAIL}"
done

# ── Product Web Apps ──
for port in 3002 3030 3035 3040 3045 3050 3055 3060 3070 3075; do
  code=$(curl -so /dev/null -w '%{http_code}' http://localhost:${port}/)
  echo "  :${port} -> HTTP ${code}"
done
```

---

## Functional Smoke Tests

### LocalMemGPT + Ollama Integration

```bash
# Verify LocalMemGPT can see Ollama models
curl -sf http://localhost:4019/api/models | jq '.[0].name'
# Expect: model name (e.g., "llama3.2:3b")
```

### LLM Lab Dashboard + Ollama

```bash
# Verify LLM Lab dashboard serves and can proxy to Ollama
curl -sf http://localhost:3075 | head -1
# Expect: HTML content

curl -sf http://localhost:3075/api/ollama/tags | jq '.models[0].name'
# Expect: model name
```

### Platform Service Auth

```bash
# Health with request ID
curl -sf -H "x-request-id: test-123" http://localhost:4003/health | jq .
# Expect: {"status":"ok","service":"platform-service","requestId":"test-123"}
```

### Mailpit (Email)

```bash
# Mailpit inbox (should be empty initially)
curl -sf http://localhost:8025/api/v1/messages | jq .total
# Expect: 0
```

### Grafana

```bash
# Grafana login (default credentials)
curl -sf -u admin:bytelyst http://localhost:3000/api/org | jq .name
# Expect: "Main Org."
```

---

## Idempotency Test

```bash
# Run setup again — should complete without errors
sudo ./setup.sh --resume
# Expect: "All phases already completed. Use --reset to start over."

# Run single phase — should be safe
sudo ./setup.sh --phase=8
# Expect: health check passes again
```

## Resume Test

```bash
# Check status
sudo ./setup.sh --status
# Expect: all 8 phases DONE

# Reset and verify
sudo ./setup.sh --reset
sudo ./setup.sh --status
# Expect: all 8 phases pending
```

---

## Port Connectivity (from external machine)

If testing remote access via SSH port-forwarding:

```bash
# From your laptop (not the VM)
ssh -N -L 3001:localhost:3001 -L 3060:localhost:3060 -L 4003:localhost:4003 azureuser@<vm-ip>

# Then in another terminal on your laptop:
curl -sf http://localhost:4003/health | jq .
# Expect: {"status":"ok",...}

# Open in browser:
# http://localhost:3001  -> Admin Console
# http://localhost:3060  -> ActionTrail Web
```

---

## Expected Service Count Summary

| Category          | Count  | Ports                                                |
| ----------------- | ------ | ---------------------------------------------------- |
| Infrastructure    | 6      | 1234, 3000, 3100, 8025, 8080, 10000                  |
| Platform Services | 3      | 4003, 4005, 4007                                     |
| Dashboards        | 2      | 3001, 3003                                           |
| Product Backends  | 10     | 4010-4019                                            |
| Product Web Apps  | 9      | 3002, 3030, 3035, 3040, 3045, 3050, 3055, 3060, 3070 |
| LLM Lab Dashboard | 1      | 3075                                                 |
| **Total**         | **31** |                                                      |

Plus external to Docker: Gitea (:3300), Ollama (:11434).
