- Add API endpoint and curl commands to check CI status - Document authentication with Authorization: token header - Add response field descriptions (status, conclusion) - Reference BWS key for GITEA_API_TOKEN
264 lines
8.3 KiB
Markdown
264 lines
8.3 KiB
Markdown
# Testing Guide
|
|
|
|
## Quick Verification
|
|
|
|
```bash
|
|
# 1. Start server
|
|
bun run dev
|
|
|
|
# 2. Health check
|
|
curl http://localhost:3000/health
|
|
|
|
# 3. Open browser
|
|
open http://localhost:3000
|
|
```
|
|
|
|
## API Endpoints
|
|
|
|
| Endpoint | Method | Purpose |
|
|
|----------|--------|---------|
|
|
| `/health` | GET | Server status |
|
|
| `/api/check/:name` | GET | Name availability |
|
|
| `/api/deploy` | POST | Start deployment |
|
|
| `/api/status/:id` | GET | SSE progress stream |
|
|
| `/api/stack/:name` | DELETE | Delete stack and cleanup |
|
|
|
|
## Test Checklist
|
|
|
|
### Backend
|
|
|
|
| Test | Command | Expected |
|
|
|------|---------|----------|
|
|
| Server starts | `bun run dev` | "starting on http://0.0.0.0:3000" |
|
|
| Health endpoint | `curl localhost:3000/health` | `{"status":"healthy"...}` |
|
|
| TypeScript | `bun run typecheck` | No errors |
|
|
| Dokploy connection | Check `/api/check/test-name` | Returns availability |
|
|
|
|
### Frontend
|
|
|
|
| Test | Action | Expected |
|
|
|------|--------|----------|
|
|
| Page loads | Open localhost:3000 | Dark theme, centered content |
|
|
| Typewriter | Wait 2s | "Choose Your Stack Name" animates |
|
|
| Language switch | Click 🇲🇦 | Arabic text, RTL layout |
|
|
| Name validation | Type "ab" | Error: too short |
|
|
| Reserved name | Type "admin" | Error: reserved |
|
|
| Valid name | Type "my-stack" | "✓ Name is available!" |
|
|
|
|
### Deployment Flow
|
|
|
|
| Step | Indicator |
|
|
|------|-----------|
|
|
| Submit form | Progress bar appears |
|
|
| SSE updates | Log entries animate in |
|
|
| Success | Typewriter: "Deployment Complete" |
|
|
| Error | Typewriter: "Deployment Failed" |
|
|
|
|
## Infrastructure
|
|
|
|
| Service | URL | Purpose |
|
|
|---------|-----|---------|
|
|
| Dokploy | https://app.flexinit.nl | Container orchestration |
|
|
| Traefik | 144.76.116.169 | SSL termination |
|
|
| Stacks | *.ai.flexinit.nl | Deployed AI assistants |
|
|
|
|
## Full Deployment Test
|
|
|
|
```bash
|
|
# 1. Generate unique name
|
|
NAME="test-$(date +%s | tail -c 5)"
|
|
|
|
# 2. Check availability
|
|
curl -s http://localhost:3000/api/check/$NAME
|
|
|
|
# 3. Deploy
|
|
curl -s -X POST http://localhost:3000/api/deploy \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"name\": \"$NAME\"}"
|
|
|
|
# 4. Monitor SSE (wait ~2-3 min)
|
|
curl -N http://localhost:3000/api/status/<deployment-id>
|
|
|
|
# 5. Verify stack accessible
|
|
curl -s https://$NAME.ai.flexinit.nl
|
|
|
|
# 6. Cleanup
|
|
curl -s -X DELETE http://localhost:3000/api/stack/$NAME
|
|
```
|
|
|
|
## Cleanup Commands
|
|
|
|
```bash
|
|
# Delete specific stack
|
|
curl -s -X DELETE http://localhost:3000/api/stack/my-stack
|
|
|
|
# List all projects (direct Dokploy)
|
|
source .env && curl -s -H "x-api-key: $DOKPLOY_API_TOKEN" \
|
|
"$DOKPLOY_URL/api/project.all" | jq '.[].name'
|
|
```
|
|
|
|
## Common Issues
|
|
|
|
| Issue | Solution |
|
|
|-------|----------|
|
|
| CSS not loading | Check `/style.css` returns CSS, not HTML |
|
|
| 401 on Dokploy | Regenerate API token in Dokploy dashboard |
|
|
| Typewriter not running | Check browser console for JS errors |
|
|
| RTL not working | Verify `dir="rtl"` on `<html>` element |
|
|
| Health check timeout | Container startup can take 1-2 min, timeout is 3 min |
|
|
| SSL cert errors | Health check treats SSL errors as "alive" during provisioning |
|
|
| SSE disconnects | idleTimeout set to 255s (max), long deployments should complete |
|
|
|
|
---
|
|
|
|
## Production Verification (2026-01-10)
|
|
|
|
### Verified Working
|
|
|
|
| Component | Status | Notes |
|
|
|-----------|--------|-------|
|
|
| Portal Health | ✅ | `https://portal.ai.flexinit.nl/health` returns healthy |
|
|
| Name Validation | ✅ | `/api/check/:name` validates correctly |
|
|
| Frontend UI | ✅ | 3 languages (NL, AR, EN), RTL support, typewriter animation |
|
|
| Stack Deployment | ✅ | Full flow: project → app → domain → deploy → health check |
|
|
| Stack Cleanup | ✅ | `DELETE /api/stack/:name` removes all resources |
|
|
| SSL/HTTPS | ✅ | Wildcard cert working for all `*.ai.flexinit.nl` |
|
|
|
|
### Critical Configuration
|
|
|
|
```bash
|
|
# These settings are REQUIRED for deployment to work
|
|
DOKPLOY_URL=https://app.flexinit.nl # Public URL, NOT internal 10.100.0.20
|
|
STACK_IMAGE=git.app.flexinit.nl/oussamadouhou/oh-my-opencode-free:latest
|
|
STACK_REGISTRY_ID=bKDYM5X7NN34x_lRDjWbz # Registry ID for Docker auth
|
|
```
|
|
|
|
### Known Gotchas (Fixed)
|
|
|
|
1. **Registry URL format** - Use `git.app.flexinit.nl`, NOT `https://git.app.flexinit.nl`
|
|
2. **Username in image path** - Must be `oussamadouhou`, not `odouhou`
|
|
3. **Dokploy URL** - Must use public URL for container-to-container communication
|
|
4. **Health check** - Now uses Dokploy API status check (not HTTP fetch)
|
|
5. **Resource limits** - Removed temporarily (Dokploy API format issues with CPU/memory values)
|
|
6. **Typewriter race condition** - Fixed by tracking active instances and canceling previous
|
|
|
|
### UI/UX Fixes (2026-01-10 v2)
|
|
|
|
| Issue | Fix | Status |
|
|
|-------|-----|--------|
|
|
| Double letters in typewriter | Track active instances, cancel before starting new | ✅ Verified |
|
|
| Flag emojis not showing | Replaced with text labels (NL/AR/EN) | ✅ Verified |
|
|
| SSE disconnects during deployment | Use Dokploy API status instead of HTTP health check | ✅ Verified |
|
|
| 'yourname' not translated | Added translation key per language | ✅ Verified |
|
|
|
|
### Health Check Change
|
|
|
|
The health check was changed from HTTP fetch (which failed from inside Docker) to Dokploy API status check:
|
|
|
|
```typescript
|
|
// Before: HTTP fetch (failed - container can't reach external URL)
|
|
const response = await fetch(`${state.url}/`);
|
|
|
|
// After: Dokploy API status check (works)
|
|
const app = await this.client.getApplication(applicationId);
|
|
if (app.applicationStatus === 'done') { /* success */ }
|
|
```
|
|
|
|
### Test Commands
|
|
|
|
```bash
|
|
# Quick health check
|
|
curl -s https://portal.ai.flexinit.nl/health | jq .
|
|
|
|
# Full deployment test
|
|
NAME="test-$(date +%s | tail -c 5)"
|
|
RESULT=$(curl -s -X POST https://portal.ai.flexinit.nl/api/deploy \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"name\": \"$NAME\"}")
|
|
echo $RESULT | jq .
|
|
|
|
# Monitor deployment (use deploymentId from above)
|
|
curl -N "https://portal.ai.flexinit.nl/api/status/$(echo $RESULT | jq -r .deploymentId)"
|
|
|
|
# Verify stack accessible (after deployment completes)
|
|
curl -s -k https://$NAME.ai.flexinit.nl | head -5
|
|
|
|
# Cleanup
|
|
curl -s -X DELETE https://portal.ai.flexinit.nl/api/stack/$NAME | jq .
|
|
```
|
|
|
|
### Dokploy Direct Commands
|
|
|
|
```bash
|
|
# List all ai-stack projects
|
|
source .env && curl -s -H "x-api-key: $DOKPLOY_API_TOKEN" \
|
|
https://app.flexinit.nl/api/project.all | \
|
|
jq '[.[] | select(.name | startswith("ai-stack-")) | {name: .name, id: .projectId}]'
|
|
|
|
# Get application status
|
|
source .env && curl -s -H "x-api-key: $DOKPLOY_API_TOKEN" \
|
|
"https://app.flexinit.nl/api/project.one?projectId=<PROJECT_ID>" | \
|
|
jq '.environments[0].applications[0] | {name: .name, status: .applicationStatus}'
|
|
```
|
|
|
|
---
|
|
|
|
## Gitea Actions CI/CD Status
|
|
|
|
### Check Workflow Status
|
|
|
|
The `oh-my-opencode-free` Docker image is built via Gitea Actions. To check CI status:
|
|
|
|
**Web UI:**
|
|
```
|
|
https://git.app.flexinit.nl/oussamadouhou/oh-my-opencode-free/actions
|
|
```
|
|
|
|
**API (requires token):**
|
|
```bash
|
|
# Get GITEA_API_TOKEN from BWS (key: GITEA_API_TOKEN)
|
|
GITEA_TOKEN="<your-token>"
|
|
|
|
# List recent workflow runs
|
|
curl -s -H "Authorization: token $GITEA_TOKEN" \
|
|
"https://git.app.flexinit.nl/api/v1/repos/oussamadouhou/oh-my-opencode-free/actions/runs?limit=5" | \
|
|
jq '.workflow_runs[] | {id, run_number, status, conclusion, display_title, head_sha: .head_sha[0:7]}'
|
|
|
|
# Get specific run details
|
|
curl -s -H "Authorization: token $GITEA_TOKEN" \
|
|
"https://git.app.flexinit.nl/api/v1/repos/oussamadouhou/oh-my-opencode-free/actions/runs/<RUN_ID>" | jq .
|
|
|
|
# Get jobs for a specific run
|
|
curl -s -H "Authorization: token $GITEA_TOKEN" \
|
|
"https://git.app.flexinit.nl/api/v1/repos/oussamadouhou/oh-my-opencode-free/actions/runs/<RUN_ID>/jobs" | jq .
|
|
```
|
|
|
|
### API Response Fields
|
|
|
|
| Field | Description |
|
|
|-------|-------------|
|
|
| `status` | `queued`, `in_progress`, `completed` |
|
|
| `conclusion` | `success`, `failure`, `cancelled`, `skipped` (only when status=completed) |
|
|
| `head_sha` | Commit SHA that triggered the run |
|
|
| `run_number` | Sequential run number |
|
|
| `display_title` | Commit message or PR title |
|
|
|
|
### Gitea API Authentication
|
|
|
|
From [Gitea docs](https://docs.gitea.com/development/api-usage):
|
|
|
|
```bash
|
|
# Header format
|
|
Authorization: token <your-api-token>
|
|
|
|
# Alternative: query parameter
|
|
?token=<your-api-token>
|
|
```
|
|
|
|
### BWS Token Reference
|
|
|
|
| Key | Purpose |
|
|
|-----|---------|
|
|
| `GITEA_API_TOKEN` | Gitea API access for workflow status |
|
|
| `DOKPLOY_API_TOKEN` | Dokploy deployment API (BWS ID: `6b3618fc-ba02-49bc-bdc8-b3c9004087bc`) |
|