docs(vercel): improve Codex prompts with progress trackers, preconditions, verification gates, and per-repo checklists
This commit is contained in:
parent
5fb5a7d468
commit
80e6268924
@ -1,16 +1,67 @@
|
|||||||
# Track A: Azure VM — Gateway, Dashboards & Security
|
# Track A: Azure VM — Gateway, Dashboards & Security
|
||||||
|
|
||||||
> **Agent:** Codex on Azure VM (`/opt/bytelyst/`)
|
> **Agent:** Codex on Azure VM (`/opt/bytelyst/`)
|
||||||
> **Prompts:** 4 (run in order)
|
> **Prompts:** 4 (run in dependency order below)
|
||||||
> **Dependency:** None — this track runs first, unblocks Track B Prompt 4
|
> **Unblocks:** Track B Prompt B4 (`.npmrc` migration — needs `gitea.bytelyst.com` live)
|
||||||
|
> **Reference docs:**
|
||||||
|
>
|
||||||
|
> - [`SECURE_API_EXPOSURE.md`](../single_azure_vm/docker/SECURE_API_EXPOSURE.md) — Caddy decision + architecture
|
||||||
|
> - [`DEPLOYMENT_STATUS_2026-03-29.md`](../single_azure_vm/docker/DEPLOYMENT_STATUS_2026-03-29.md) — current VM status
|
||||||
|
> - [`ECOSYSTEM_WEB_APPS_INVENTORY.md`](./ECOSYSTEM_WEB_APPS_INVENTORY.md) — full Vercel audit
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Progress Tracker
|
||||||
|
|
||||||
|
| # | Prompt | Status | Commit SHA | Verified |
|
||||||
|
| --- | ------------------------ | :------------: | :--------: | :------: |
|
||||||
|
| A1 | Caddy Gateway Setup | ⬜ Not started | — | ⬜ |
|
||||||
|
| A2 | Gitea HTTPS Exposure | ⬜ Not started | — | ⬜ |
|
||||||
|
| A3 | Dashboard Containers Fix | ⬜ Not started | — | ⬜ |
|
||||||
|
| A4 | NSG Lockdown | ⬜ Not started | — | ⬜ |
|
||||||
|
|
||||||
|
**Execution order:**
|
||||||
|
|
||||||
|
```
|
||||||
|
A1: Caddy Gateway ──→ A2: Gitea HTTPS ──→ A4: NSG Lockdown
|
||||||
|
└──→ A3: Dashboard Fix (parallel with A2)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## DNS Prerequisites (manual — do before starting)
|
||||||
|
|
||||||
|
These DNS records must exist before Caddy can obtain Let's Encrypt certificates:
|
||||||
|
|
||||||
|
| Record | Type | Value | Purpose |
|
||||||
|
| ---------------------- | ---- | ---------------------- | ------------------- |
|
||||||
|
| `api.bytelyst.com` | A | `<Azure VM public IP>` | Backend API gateway |
|
||||||
|
| `gitea.bytelyst.com` | A | `<Azure VM public IP>` | Gitea npm registry |
|
||||||
|
| `admin.bytelyst.com` | A | `<Azure VM public IP>` | Admin dashboard |
|
||||||
|
| `tracker.bytelyst.com` | A | `<Azure VM public IP>` | Tracker dashboard |
|
||||||
|
|
||||||
|
**Verify DNS before starting A1:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dig +short api.bytelyst.com # must return VM IP
|
||||||
|
dig +short gitea.bytelyst.com # must return VM IP
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## A1: Caddy Gateway — Replace Traefik with Caddy
|
## A1: Caddy Gateway — Replace Traefik with Caddy
|
||||||
|
|
||||||
> **Depends on:** Nothing
|
> **Depends on:** DNS records for `api.bytelyst.com`
|
||||||
> **Blocks:** A2, A3, A4
|
> **Blocks:** A2, A3, A4
|
||||||
|
|
||||||
|
### Preconditions
|
||||||
|
|
||||||
|
- [ ] `api.bytelyst.com` DNS A record resolves to Azure VM IP
|
||||||
|
- [ ] All 13 backend services are healthy: `docker compose ps | grep -c healthy` → 13+
|
||||||
|
- [ ] Ports 80 and 443 are open in Azure NSG
|
||||||
|
|
||||||
|
### Prompt
|
||||||
|
|
||||||
```
|
```
|
||||||
You are working on the ByteLyst single-Azure-VM Docker deployment at /opt/bytelyst/.
|
You are working on the ByteLyst single-Azure-VM Docker deployment at /opt/bytelyst/.
|
||||||
|
|
||||||
@ -18,34 +69,66 @@ TASK: Replace the existing Traefik gateway container with Caddy to provide HTTPS
|
|||||||
|
|
||||||
CONTEXT:
|
CONTEXT:
|
||||||
- The decision doc is at docs/devops/single_azure_vm/docker/SECURE_API_EXPOSURE.md in the learning_ai_common_plat repo
|
- The decision doc is at docs/devops/single_azure_vm/docker/SECURE_API_EXPOSURE.md in the learning_ai_common_plat repo
|
||||||
- The domain is bytelyst.com
|
- The domain is bytelyst.com — DNS A records already point to this VM
|
||||||
- API hostname: api.bytelyst.com
|
- API hostname: api.bytelyst.com
|
||||||
- Currently 13 backend services are healthy on ports 4003, 4005, 4007, 4010-4019
|
- Currently 13 backend services are healthy on ports 4003, 4005, 4007, 4010-4019
|
||||||
- Traefik is running but only as a passthrough — no TLS, no path routing hardened
|
- Traefik is running but only as a passthrough — no TLS, no path routing hardened
|
||||||
- All backend containers are on a Docker network
|
- All backend containers are on a Docker network
|
||||||
|
|
||||||
DELIVERABLES:
|
TASK LIST:
|
||||||
1. Create a Caddyfile with:
|
- [ ] 1. Create a Caddyfile at /opt/bytelyst/Caddyfile with:
|
||||||
- api.bytelyst.com as the main host (automatic Let's Encrypt TLS)
|
- api.bytelyst.com as the main host (automatic Let's Encrypt TLS)
|
||||||
- Path-based routing to all 13 backends:
|
- Path-based routing to all 13 backends:
|
||||||
/platform/* → platform-service:4003
|
/platform/* → platform-service:4003
|
||||||
/extraction/* → extraction-service:4005
|
/extraction/* → extraction-service:4005
|
||||||
/mcp/* → mcp-server:4007
|
/mcp/* → mcp-server:4007
|
||||||
/peakpulse/* → peakpulse:4010
|
/peakpulse/* → peakpulse:4010
|
||||||
/chronomind/* → chronomind:4011
|
/chronomind/* → chronomind:4011
|
||||||
/jarvisjr/* → jarvisjr:4012
|
/jarvisjr/* → jarvisjr:4012
|
||||||
/nomgap/* → nomgap:4013
|
/nomgap/* → nomgap:4013
|
||||||
/mindlyst/* → mindlyst:4014
|
/mindlyst/* → mindlyst:4014
|
||||||
/lysnrai/* → lysnrai:4015
|
/lysnrai/* → lysnrai:4015
|
||||||
/notelett/* → notelett:4016
|
/notelett/* → notelett:4016
|
||||||
/flowmonk/* → flowmonk:4017
|
/flowmonk/* → flowmonk:4017
|
||||||
/actiontrail/* → actiontrail:4018
|
/actiontrail/* → actiontrail:4018
|
||||||
/localmemgpt/* → localmemgpt:4019
|
/localmemgpt/* → localmemgpt:4019
|
||||||
- Strip the path prefix before forwarding (backends expect / not /platform/)
|
- Strip the path prefix before forwarding (backends expect / not /platform/)
|
||||||
2. Add a caddy service to docker-compose replacing or alongside the gateway service
|
- [ ] 2. Add a caddy service to docker-compose replacing or alongside the gateway service
|
||||||
3. Stop publishing backend ports (4003, 4005, 4007, 4010-4019) publicly — only expose 80/443
|
- Image: caddy:2-alpine
|
||||||
4. Verify all 13 backends respond via https://api.bytelyst.com/<service>/health
|
- Volumes: ./Caddyfile:/etc/caddy/Caddyfile, caddy_data:/data, caddy_config:/config
|
||||||
5. Update docs/devops/single_azure_vm/docker/README.md with the new access model
|
- Ports: 80:80, 443:443
|
||||||
|
- Network: same Docker network as all backends
|
||||||
|
- [ ] 3. Remove published backend ports from docker-compose (4003, 4005, 4007, 4010-4019)
|
||||||
|
— backends remain accessible internally via Docker DNS
|
||||||
|
- [ ] 4. Restart the stack: docker compose up -d
|
||||||
|
- [ ] 5. Wait for Caddy to obtain TLS certificates (check logs: docker logs caddy --tail 50)
|
||||||
|
- [ ] 6. Update docs/devops/single_azure_vm/docker/README.md with the new access model
|
||||||
|
|
||||||
|
VERIFICATION (run all — every check must pass):
|
||||||
|
# TLS certificate obtained
|
||||||
|
curl -sI https://api.bytelyst.com/platform/health | head -5
|
||||||
|
# Expected: HTTP/2 200 + valid TLS
|
||||||
|
|
||||||
|
# All 13 backends reachable via path routing
|
||||||
|
for svc in platform extraction mcp peakpulse chronomind jarvisjr nomgap mindlyst lysnrai notelett flowmonk actiontrail localmemgpt; do
|
||||||
|
echo -n "$svc: "; curl -sf https://api.bytelyst.com/$svc/health | jq -r '.status // "FAIL"'
|
||||||
|
done
|
||||||
|
# Expected: all 13 print "ok"
|
||||||
|
|
||||||
|
# Direct port access blocked from outside
|
||||||
|
curl -sf --max-time 3 http://<VM_PUBLIC_IP>:4003/health && echo "FAIL: port still open" || echo "PASS: port closed"
|
||||||
|
# Expected: "PASS: port closed"
|
||||||
|
|
||||||
|
SUCCESS CRITERIA:
|
||||||
|
- All 13 health checks return "ok" via https://api.bytelyst.com/<service>/health
|
||||||
|
- TLS certificate is valid (Let's Encrypt)
|
||||||
|
- No backend ports (4003-4019) accessible directly from public internet
|
||||||
|
- Traefik config preserved but not in use
|
||||||
|
|
||||||
|
ROLLBACK:
|
||||||
|
If Caddy fails, revert docker-compose changes and restart Traefik:
|
||||||
|
git checkout -- docker-compose*.yml
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
DO NOT:
|
DO NOT:
|
||||||
- Delete the existing Traefik config — just stop using it
|
- Delete the existing Traefik config — just stop using it
|
||||||
@ -59,8 +142,16 @@ COMMIT: feat(gateway): replace Traefik with Caddy for HTTPS path routing
|
|||||||
|
|
||||||
## A2: Gitea HTTPS Exposure via Caddy
|
## A2: Gitea HTTPS Exposure via Caddy
|
||||||
|
|
||||||
> **Depends on:** A1 (Caddy must be running)
|
> **Depends on:** A1 ✅ (Caddy running + TLS working)
|
||||||
> **Blocks:** Track B Prompt B4
|
> **Blocks:** Track B → B4 (`.npmrc` update across all repos)
|
||||||
|
|
||||||
|
### Preconditions
|
||||||
|
|
||||||
|
- [ ] A1 is complete — Caddy is running with valid TLS on `api.bytelyst.com`
|
||||||
|
- [ ] `gitea.bytelyst.com` DNS A record resolves to Azure VM IP
|
||||||
|
- [ ] Gitea container is running: `docker compose ps gitea` → healthy
|
||||||
|
|
||||||
|
### Prompt
|
||||||
|
|
||||||
```
|
```
|
||||||
You are working on the ByteLyst single-Azure-VM Docker deployment at /opt/bytelyst/.
|
You are working on the ByteLyst single-Azure-VM Docker deployment at /opt/bytelyst/.
|
||||||
@ -69,66 +160,144 @@ TASK: Expose the Gitea npm registry over HTTPS via the Caddy gateway so that ext
|
|||||||
|
|
||||||
CONTEXT:
|
CONTEXT:
|
||||||
- Gitea is running on port 3300 inside the Docker network
|
- Gitea is running on port 3300 inside the Docker network
|
||||||
- Caddy is already configured for api.bytelyst.com (from A1)
|
- Caddy is already configured for api.bytelyst.com (from A1) and has valid TLS
|
||||||
- The Gitea npm registry URL pattern is: /api/packages/ByteLyst/npm/
|
- The Gitea npm registry URL pattern is: /api/packages/ByteLyst/npm/
|
||||||
- Gitea needs its own subdomain because its internal routing expects to be at root
|
- Gitea needs its own subdomain because its internal routing expects to be at root
|
||||||
- Target URL: https://gitea.bytelyst.com
|
- Target URL: https://gitea.bytelyst.com
|
||||||
|
|
||||||
DELIVERABLES:
|
TASK LIST:
|
||||||
1. Add a gitea.bytelyst.com block to the Caddyfile:
|
- [ ] 1. Add a gitea.bytelyst.com block to the Caddyfile:
|
||||||
gitea.bytelyst.com {
|
gitea.bytelyst.com {
|
||||||
reverse_proxy gitea:3300
|
reverse_proxy gitea:3300
|
||||||
}
|
}
|
||||||
2. Ensure Gitea's ROOT_URL / SERVER__ROOT_URL is updated to https://gitea.bytelyst.com
|
- [ ] 2. Reload Caddy: docker exec caddy caddy reload --config /etc/caddy/Caddyfile
|
||||||
3. Verify https://gitea.bytelyst.com loads the Gitea web UI
|
- [ ] 3. Update Gitea's ROOT_URL to https://gitea.bytelyst.com
|
||||||
4. Verify npm registry is accessible:
|
— Edit docker-compose env: SERVER__ROOT_URL=https://gitea.bytelyst.com
|
||||||
curl -s https://gitea.bytelyst.com/api/packages/ByteLyst/npm/@bytelyst%2ferrors | head
|
— Restart Gitea container: docker compose restart gitea
|
||||||
5. Remove port 3300 from public NSG rules (Gitea only accessible via Caddy now)
|
- [ ] 4. Remove port 3300 from docker-compose published ports (Gitea only via Caddy)
|
||||||
6. Lock down other operational ports from public access where possible:
|
- [ ] 5. Remove stale public NSG rules for ports that should not be exposed:
|
||||||
- 8025 (Mailpit)
|
- 3300 (Gitea)
|
||||||
- 8080 (Traefik dashboard — no longer needed)
|
- 8025 (Mailpit)
|
||||||
- 10000 (Azurite)
|
- 8080 (Traefik dashboard — no longer needed)
|
||||||
|
- 10000 (Azurite)
|
||||||
|
|
||||||
|
VERIFICATION (run all — every check must pass):
|
||||||
|
# Gitea web UI loads
|
||||||
|
curl -sI https://gitea.bytelyst.com | head -3
|
||||||
|
# Expected: HTTP/2 200 (or 302 redirect to login)
|
||||||
|
|
||||||
|
# npm registry returns package metadata
|
||||||
|
curl -sf https://gitea.bytelyst.com/api/packages/ByteLyst/npm/@bytelyst%2ferrors | jq '.name'
|
||||||
|
# Expected: "@bytelyst/errors"
|
||||||
|
|
||||||
|
# Authenticated npm install works
|
||||||
|
export GITEA_NPM_TOKEN=<token>
|
||||||
|
npm view @bytelyst/errors --registry=https://gitea.bytelyst.com/api/packages/ByteLyst/npm/
|
||||||
|
# Expected: package info printed (version, description, etc.)
|
||||||
|
|
||||||
|
# Direct port 3300 access blocked from outside
|
||||||
|
curl -sf --max-time 3 http://<VM_PUBLIC_IP>:3300 && echo "FAIL" || echo "PASS: port closed"
|
||||||
|
# Expected: "PASS: port closed"
|
||||||
|
|
||||||
|
# Internal Docker access still works
|
||||||
|
docker exec platform-service curl -sf http://gitea:3300/api/v1/version | jq '.version'
|
||||||
|
# Expected: Gitea version string
|
||||||
|
|
||||||
|
SUCCESS CRITERIA:
|
||||||
|
- https://gitea.bytelyst.com serves Gitea web UI with valid TLS
|
||||||
|
- npm registry API returns valid package metadata
|
||||||
|
- Authenticated `npm view` succeeds
|
||||||
|
- Port 3300 not accessible from public internet
|
||||||
|
- Docker-internal access to gitea:3300 still works (other containers unaffected)
|
||||||
|
|
||||||
DO NOT:
|
DO NOT:
|
||||||
- Break existing Docker-internal Gitea access (other containers still use gitea:3300)
|
- Break existing Docker-internal Gitea access (other containers still use gitea:3300)
|
||||||
- Remove the Gitea container or change its internal port
|
- Remove the Gitea container or change its internal port
|
||||||
|
|
||||||
COMMIT: feat(gateway): expose Gitea npm registry via HTTPS at gitea.bytelyst.com
|
COMMIT: feat(gateway): expose Gitea npm registry via HTTPS at gitea.bytelyst.com
|
||||||
|
|
||||||
|
AFTER COMPLETING: Notify the operator that Track B → B4 (.npmrc migration) is now unblocked.
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## A3: Fix admin-web and tracker-web Containers
|
## A3: Fix admin-web and tracker-web Containers
|
||||||
|
|
||||||
> **Depends on:** A1 (Caddy gateway for subdomain routing)
|
> **Depends on:** A1 ✅ (Caddy running for subdomain routing)
|
||||||
> **Blocks:** Nothing
|
> **Blocks:** Nothing (independent of Track B)
|
||||||
|
> **Can run in parallel with:** A2
|
||||||
|
|
||||||
|
### Preconditions
|
||||||
|
|
||||||
|
- [ ] A1 is complete — Caddy is running
|
||||||
|
- [ ] `admin.bytelyst.com` and `tracker.bytelyst.com` DNS A records resolve to VM IP
|
||||||
|
- [ ] Source code for dashboards is available on the VM
|
||||||
|
|
||||||
|
### Prompt
|
||||||
|
|
||||||
```
|
```
|
||||||
You are working on the ByteLyst single-Azure-VM Docker deployment at /opt/bytelyst/.
|
You are working on the ByteLyst single-Azure-VM Docker deployment at /opt/bytelyst/.
|
||||||
|
|
||||||
TASK: Resolve the remaining admin-web and tracker-web containers so they are running and healthy.
|
TASK: Resolve the remaining admin-web and tracker-web containers so they are running and healthy, then expose them via Caddy.
|
||||||
|
|
||||||
CONTEXT:
|
CONTEXT:
|
||||||
- Per DEPLOYMENT_STATUS_2026-03-29.md, all 13 backend services are healthy
|
- Per DEPLOYMENT_STATUS_2026-03-29.md, all 13 backend services are healthy
|
||||||
- admin-web and tracker-web are the two remaining unresolved containers
|
- admin-web and tracker-web are the two remaining UNRESOLVED containers
|
||||||
- Both are Next.js 16 apps from the learning_ai_common_plat repo under dashboards/
|
- Both are Next.js 16 apps from learning_ai_common_plat under dashboards/
|
||||||
- Both use workspace:* dependencies resolved by pnpm
|
- Both use workspace:* dependencies resolved by pnpm
|
||||||
- Both use the --webpack build flag
|
- Both use the --webpack build flag
|
||||||
- admin-web runs on port 3001, tracker-web on port 3003
|
- admin-web port: 3001, tracker-web port: 3003
|
||||||
- The Docker build context is dashboards/admin-web/ and dashboards/tracker-web/
|
- Docker build context: dashboards/admin-web/ and dashboards/tracker-web/
|
||||||
|
|
||||||
DELIVERABLES:
|
TASK LIST:
|
||||||
1. Diagnose why admin-web and tracker-web builds failed
|
- [ ] 1. Check current container status:
|
||||||
2. Fix the build issues (likely @bytelyst/* package resolution or standalone entrypoint)
|
docker compose ps admin-web tracker-web
|
||||||
3. Rebuild and start both containers
|
docker compose logs admin-web --tail 100
|
||||||
4. Verify health:
|
docker compose logs tracker-web --tail 100
|
||||||
curl -s http://127.0.0.1:3001 | head
|
- [ ] 2. Diagnose the build/runtime failure (likely causes):
|
||||||
curl -s http://127.0.0.1:3003 | head
|
- @bytelyst/* package resolution — may need .docker-deps/ tarballs
|
||||||
5. Add Caddy routes for the dashboards:
|
- Standalone entrypoint not found
|
||||||
- https://admin.bytelyst.com → admin-web:3001
|
- Missing env vars (COSMOS_ENDPOINT, COSMOS_KEY, JWT_SECRET)
|
||||||
- https://tracker.bytelyst.com → tracker-web:3003
|
- [ ] 3. Fix the identified issues
|
||||||
6. Update DEPLOYMENT_STATUS_2026-03-29.md to reflect the fix
|
- [ ] 4. Rebuild and restart:
|
||||||
7. Mark Phase 7 as DONE if all services are now healthy
|
docker compose up -d --build admin-web tracker-web
|
||||||
|
- [ ] 5. Add Caddy routes for the dashboards to the Caddyfile:
|
||||||
|
admin.bytelyst.com {
|
||||||
|
reverse_proxy admin-web:3001
|
||||||
|
}
|
||||||
|
tracker.bytelyst.com {
|
||||||
|
reverse_proxy tracker-web:3003
|
||||||
|
}
|
||||||
|
- [ ] 6. Reload Caddy: docker exec caddy caddy reload --config /etc/caddy/Caddyfile
|
||||||
|
- [ ] 7. Update DEPLOYMENT_STATUS_2026-03-29.md to reflect the fix
|
||||||
|
|
||||||
|
VERIFICATION (run all — every check must pass):
|
||||||
|
# Containers healthy
|
||||||
|
docker compose ps admin-web tracker-web
|
||||||
|
# Expected: both show "Up" and "healthy" (or at least "Up")
|
||||||
|
|
||||||
|
# Local port access
|
||||||
|
curl -sf http://127.0.0.1:3001 | head -5
|
||||||
|
curl -sf http://127.0.0.1:3003 | head -5
|
||||||
|
# Expected: HTML response from each
|
||||||
|
|
||||||
|
# HTTPS via Caddy
|
||||||
|
curl -sI https://admin.bytelyst.com | head -3
|
||||||
|
# Expected: HTTP/2 200 (or 302)
|
||||||
|
|
||||||
|
curl -sI https://tracker.bytelyst.com | head -3
|
||||||
|
# Expected: HTTP/2 200 (or 302)
|
||||||
|
|
||||||
|
# All containers now healthy
|
||||||
|
docker compose ps | grep -E "(unhealthy|Exit)" | wc -l
|
||||||
|
# Expected: 0
|
||||||
|
|
||||||
|
SUCCESS CRITERIA:
|
||||||
|
- Both admin-web and tracker-web containers are running
|
||||||
|
- Both respond on their ports (3001, 3003)
|
||||||
|
- Both accessible via HTTPS at admin.bytelyst.com and tracker.bytelyst.com
|
||||||
|
- DEPLOYMENT_STATUS doc updated with fix details
|
||||||
|
- Zero unhealthy containers in the full stack
|
||||||
|
|
||||||
COMMIT: fix(deployment): resolve admin-web and tracker-web containers
|
COMMIT: fix(deployment): resolve admin-web and tracker-web containers
|
||||||
```
|
```
|
||||||
@ -137,41 +306,126 @@ COMMIT: fix(deployment): resolve admin-web and tracker-web containers
|
|||||||
|
|
||||||
## A4: NSG Lockdown — Reduce Public Port Exposure
|
## A4: NSG Lockdown — Reduce Public Port Exposure
|
||||||
|
|
||||||
> **Depends on:** A1 + A2 (Caddy handling all traffic)
|
> **Depends on:** A1 + A2 + A3 all complete (all traffic routed through Caddy)
|
||||||
> **Blocks:** Nothing
|
> **Blocks:** Nothing
|
||||||
|
> **Run this LAST in Track A**
|
||||||
|
|
||||||
|
### Preconditions
|
||||||
|
|
||||||
|
- [ ] A1 complete — all backends accessible via `api.bytelyst.com`
|
||||||
|
- [ ] A2 complete — Gitea accessible via `gitea.bytelyst.com`
|
||||||
|
- [ ] A3 complete — dashboards accessible via `admin.bytelyst.com` and `tracker.bytelyst.com`
|
||||||
|
- [ ] All services verified working through Caddy (no direct port access needed)
|
||||||
|
|
||||||
|
### Prompt
|
||||||
|
|
||||||
```
|
```
|
||||||
TASK: Reduce the Azure NSG (Network Security Group) rules so only ports 80, 443, and 22 are publicly accessible.
|
TASK: Reduce the Azure NSG (Network Security Group) rules so only ports 80, 443, and 22 are publicly accessible.
|
||||||
|
|
||||||
CONTEXT:
|
CONTEXT:
|
||||||
- The Azure VM currently exposes many service ports publicly (3000-3300, 4003-4019, 8025, 8080, 10000, 11434)
|
- The Azure VM currently exposes many service ports publicly (3000-3300, 4003-4019, 8025, 8080, 10000, 11434)
|
||||||
- Caddy now handles all public HTTPS traffic on 80/443
|
- Caddy now handles ALL public HTTPS traffic on ports 80/443
|
||||||
- Backend services, Gitea, Grafana, Mailpit, and Azurite are all accessed through Caddy
|
- All services (backends, Gitea, dashboards, monitoring) are accessed through Caddy subdomains
|
||||||
- Only SSH (22) and HTTP/HTTPS (80/443) should remain publicly open
|
- Only SSH (22) and HTTP/HTTPS (80/443) should remain publicly open
|
||||||
- This follows the recommendation in SECURE_API_EXPOSURE.md
|
- This follows the recommendation in SECURE_API_EXPOSURE.md
|
||||||
|
|
||||||
DELIVERABLES:
|
TASK LIST:
|
||||||
1. List current NSG rules: az network nsg rule list --resource-group <rg> --nsg-name <nsg> -o table
|
- [ ] 1. Snapshot current NSG rules (save output for rollback reference):
|
||||||
2. Remove or deny inbound rules for all ports except 22, 80, 443
|
az network nsg rule list --resource-group <rg> --nsg-name <nsg> -o table > /opt/bytelyst/nsg-rules-before.txt
|
||||||
3. Verify Caddy still serves all routes correctly
|
cat /opt/bytelyst/nsg-rules-before.txt
|
||||||
4. Verify SSH access still works
|
- [ ] 2. Identify rules to remove — everything except:
|
||||||
5. Document the changes in DEPLOYMENT_STATUS_2026-03-29.md
|
- SSH (22/tcp)
|
||||||
|
- HTTP (80/tcp)
|
||||||
|
- HTTPS (443/tcp)
|
||||||
|
- [ ] 3. Delete each unnecessary rule:
|
||||||
|
az network nsg rule delete --resource-group <rg> --nsg-name <nsg> --name <rule-name>
|
||||||
|
- [ ] 4. List final NSG rules to confirm only 3 remain:
|
||||||
|
az network nsg rule list --resource-group <rg> --nsg-name <nsg> -o table
|
||||||
|
- [ ] 5. Document changes in DEPLOYMENT_STATUS_2026-03-29.md
|
||||||
|
|
||||||
|
VERIFICATION (run all — every check must pass):
|
||||||
|
# SSH still works
|
||||||
|
ssh -o ConnectTimeout=5 <user>@<VM_IP> echo "SSH OK"
|
||||||
|
# Expected: "SSH OK"
|
||||||
|
|
||||||
|
# Caddy still serves all routes
|
||||||
|
curl -sf https://api.bytelyst.com/platform/health | jq '.status'
|
||||||
|
# Expected: "ok"
|
||||||
|
|
||||||
|
curl -sf https://gitea.bytelyst.com/api/v1/version | jq '.version'
|
||||||
|
# Expected: version string
|
||||||
|
|
||||||
|
curl -sI https://admin.bytelyst.com | head -1
|
||||||
|
# Expected: HTTP/2 200 (or 302)
|
||||||
|
|
||||||
|
# Direct port access blocked
|
||||||
|
for port in 3001 3003 3300 4003 4005 8025 8080 10000; do
|
||||||
|
curl -sf --max-time 3 http://<VM_PUBLIC_IP>:$port && echo "FAIL: $port open" || echo "PASS: $port closed"
|
||||||
|
done
|
||||||
|
# Expected: all "PASS: <port> closed"
|
||||||
|
|
||||||
|
# Only 3 NSG rules remain
|
||||||
|
az network nsg rule list --resource-group <rg> --nsg-name <nsg> -o table | grep -c Allow
|
||||||
|
# Expected: 3 (SSH, HTTP, HTTPS)
|
||||||
|
|
||||||
|
SUCCESS CRITERIA:
|
||||||
|
- Only ports 22, 80, 443 open in NSG
|
||||||
|
- SSH access confirmed working
|
||||||
|
- All Caddy routes still functional
|
||||||
|
- No direct port access possible from public internet
|
||||||
|
- Before/after NSG snapshots saved
|
||||||
|
|
||||||
|
ROLLBACK:
|
||||||
|
If services become unreachable after lockdown:
|
||||||
|
# Re-add a rule temporarily
|
||||||
|
az network nsg rule create --resource-group <rg> --nsg-name <nsg> \
|
||||||
|
--name AllowTemp --priority 200 --access Allow --direction Inbound \
|
||||||
|
--source-address-prefixes '*' --destination-port-ranges <port> --protocol Tcp
|
||||||
|
# Then investigate Caddy routing
|
||||||
|
|
||||||
DO NOT:
|
DO NOT:
|
||||||
- Remove the SSH (22) rule
|
- Remove the SSH (22) rule — you will lose access
|
||||||
- Remove the HTTP (80) or HTTPS (443) rules
|
- Remove the HTTP (80) or HTTPS (443) rules — Caddy needs them
|
||||||
- Make changes without first listing the current rules
|
- Make changes without first saving the current rules snapshot
|
||||||
|
|
||||||
COMMIT: chore(security): lock down Azure NSG to 22/80/443 only
|
COMMIT: chore(security): lock down Azure NSG to 22/80/443 only
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Track A Execution Order
|
## Track A — Final Verification Checklist
|
||||||
|
|
||||||
```
|
After all 4 prompts are complete, run this full end-to-end verification:
|
||||||
A1: Caddy Gateway ──→ A2: Gitea HTTPS ──→ A4: NSG Lockdown
|
|
||||||
└──→ A3: Dashboards Fix
|
```bash
|
||||||
|
echo "=== Track A Final Verification ==="
|
||||||
|
|
||||||
|
echo "--- DNS ---"
|
||||||
|
for d in api.bytelyst.com gitea.bytelyst.com admin.bytelyst.com tracker.bytelyst.com; do
|
||||||
|
echo -n "$d → "; dig +short $d
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "--- Backend Health (13 services) ---"
|
||||||
|
for svc in platform extraction mcp peakpulse chronomind jarvisjr nomgap mindlyst lysnrai notelett flowmonk actiontrail localmemgpt; do
|
||||||
|
echo -n "$svc: "; curl -sf https://api.bytelyst.com/$svc/health | jq -r '.status // "FAIL"'
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "--- Gitea npm registry ---"
|
||||||
|
curl -sf https://gitea.bytelyst.com/api/packages/ByteLyst/npm/@bytelyst%2ferrors | jq '.name'
|
||||||
|
|
||||||
|
echo "--- Dashboards ---"
|
||||||
|
curl -sI https://admin.bytelyst.com | head -1
|
||||||
|
curl -sI https://tracker.bytelyst.com | head -1
|
||||||
|
|
||||||
|
echo "--- Port lockdown ---"
|
||||||
|
for port in 3001 3003 3300 4003 4005 8025 8080 10000; do
|
||||||
|
curl -sf --max-time 3 http://<VM_PUBLIC_IP>:$port > /dev/null 2>&1 && echo "FAIL: $port open" || echo "PASS: $port closed"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "--- Docker containers ---"
|
||||||
|
docker compose ps --format 'table {{.Name}}\t{{.Status}}' | grep -E "(unhealthy|Exit)" | wc -l
|
||||||
|
# Expected: 0
|
||||||
```
|
```
|
||||||
|
|
||||||
A3 can run in parallel with A2. A4 runs last after everything is routed through Caddy.
|
**All checks must pass before Track A is considered complete.**
|
||||||
|
Once A2 verification passes, signal to Track B that Prompt B4 is unblocked.
|
||||||
|
|||||||
@ -2,6 +2,29 @@
|
|||||||
|
|
||||||
> **Agent:** Any Codex agent with repo access (local or cloud)
|
> **Agent:** Any Codex agent with repo access (local or cloud)
|
||||||
> **Prompts:** 4 (B1–B3 run in parallel, B4 runs last after Track A completes A2)
|
> **Prompts:** 4 (B1–B3 run in parallel, B4 runs last after Track A completes A2)
|
||||||
|
> **Reference docs:**
|
||||||
|
>
|
||||||
|
> - [`ECOSYSTEM_WEB_APPS_INVENTORY.md`](./ECOSYSTEM_WEB_APPS_INVENTORY.md) — full Vercel audit + per-app status
|
||||||
|
> - Individual `ROADMAP_*.md` files — per-app gaps, env vars, and deployment steps
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Progress Tracker
|
||||||
|
|
||||||
|
| # | Prompt | Repos | Status | Commits | Verified |
|
||||||
|
| --- | ------------------------ | :---: | :--------------: | :-----: | :------: |
|
||||||
|
| B1 | Fix `file:` refs | 7 | ⬜ Not started | 0/7 | ⬜ |
|
||||||
|
| B2 | Fix `output: standalone` | 4 | ⬜ Not started | 0/4 | ⬜ |
|
||||||
|
| B3 | EffoRise `vercel.json` | 1 | ⬜ Not started | 0/1 | ⬜ |
|
||||||
|
| B4 | Update `.npmrc` | 12 | ⬜ Blocked on A2 | 0/12 | ⬜ |
|
||||||
|
|
||||||
|
**Execution order:**
|
||||||
|
|
||||||
|
```
|
||||||
|
B1: Fix file: refs ──────┐
|
||||||
|
B2: Fix standalone ──────┼──→ B4: Update .npmrc (blocked until Track A → A2 done)
|
||||||
|
B3: EffoRise vercel.json ┘
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -10,15 +33,28 @@
|
|||||||
> **Depends on:** Nothing (packages are already published to Gitea)
|
> **Depends on:** Nothing (packages are already published to Gitea)
|
||||||
> **Blocks:** Nothing
|
> **Blocks:** Nothing
|
||||||
|
|
||||||
|
### Per-Repo Checklist
|
||||||
|
|
||||||
|
| # | Repo | File | Packages to fix | Edited | Built | Committed | Pushed |
|
||||||
|
| --- | ------------------------------ | ------------------------ | ----------------- | :----: | :---: | :-------: | :----: |
|
||||||
|
| 1 | `learning_ai_clock` | `web/package.json` | design-tokens, ui | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 2 | `learning_ai_jarvis_jr` | `web/package.json` | ui | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 3 | `learning_ai_fastgap` | `web/package.json` | ui | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 4 | `learning_ai_flowmonk` | `web/package.json` | ui | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 5 | `learning_ai_notes` | `web/package.json` | ui | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 6 | `learning_ai_local_memory_gpt` | `web/package.json` | ui | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 7 | `learning_ai_local_llms` | `dashboard/package.json` | design-tokens, ui | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
|
||||||
|
### Prompt
|
||||||
|
|
||||||
```
|
```
|
||||||
TASK: Convert all file: references to @bytelyst/* packages into semver ^0.1.0 references across 7 web app repos.
|
TASK: Convert all file: references to @bytelyst/* packages into semver ^0.1.0 references across 7 web app repos.
|
||||||
|
|
||||||
CONTEXT:
|
CONTEXT:
|
||||||
- 7 repos have web/package.json files that use file: references to ../../learning_ai_common_plat/packages/*
|
- 7 repos have web/package.json (or dashboard/package.json) files with file: references to ../../learning_ai_common_plat/packages/*
|
||||||
- These fail on Vercel because the sibling repo doesn't exist
|
- These fail on Vercel because the sibling repo doesn't exist during build
|
||||||
- The packages are already published to the Gitea npm registry
|
- The packages are already published to the Gitea npm registry
|
||||||
- Each fix is: change "file:../../learning_ai_common_plat/packages/X" to "^0.1.0"
|
- Each fix: change "file:../../learning_ai_common_plat/packages/X" to "^0.1.0"
|
||||||
- After changing, run pnpm install to update the lockfile, then verify pnpm build passes
|
|
||||||
|
|
||||||
REPOS AND FILES TO FIX:
|
REPOS AND FILES TO FIX:
|
||||||
|
|
||||||
@ -45,17 +81,35 @@ REPOS AND FILES TO FIX:
|
|||||||
- "@bytelyst/design-tokens": "file:..." → "^0.1.0"
|
- "@bytelyst/design-tokens": "file:..." → "^0.1.0"
|
||||||
- "@bytelyst/ui": "file:..." → "^0.1.0"
|
- "@bytelyst/ui": "file:..." → "^0.1.0"
|
||||||
|
|
||||||
FOR EACH REPO:
|
FOR EACH REPO (repeat 7 times):
|
||||||
1. Edit the package.json — replace file: refs with ^0.1.0
|
- [ ] 1. Edit the package.json — replace file: refs with ^0.1.0
|
||||||
2. Run: cd web && pnpm install (or cd dashboard for LLM Lab)
|
- [ ] 2. Run: cd web && pnpm install (or cd dashboard for LLM Lab)
|
||||||
3. Run: pnpm build
|
- [ ] 3. Verify no file: refs remain: grep -r "file:.*common_plat" package.json
|
||||||
4. If build passes, commit: fix(web): convert file: refs to registry semver for Vercel compatibility
|
Expected: no output
|
||||||
5. Push to origin main
|
- [ ] 4. Run: pnpm build
|
||||||
|
Expected: build succeeds with exit code 0
|
||||||
|
- [ ] 5. Commit: fix(web): convert file: refs to registry semver for Vercel compatibility
|
||||||
|
- [ ] 6. Push to origin main
|
||||||
|
|
||||||
|
VERIFICATION (after all 7 repos):
|
||||||
|
# Confirm zero file: refs remain across all repos
|
||||||
|
for repo in learning_ai_clock learning_ai_jarvis_jr learning_ai_fastgap learning_ai_flowmonk learning_ai_notes learning_ai_local_memory_gpt learning_ai_local_llms; do
|
||||||
|
echo -n "$repo: "
|
||||||
|
grep -rl "file:.*common_plat" $repo/web/package.json $repo/dashboard/package.json 2>/dev/null | wc -l | tr -d ' '
|
||||||
|
echo " file: refs remaining"
|
||||||
|
done
|
||||||
|
# Expected: all show "0 file: refs remaining"
|
||||||
|
|
||||||
|
SUCCESS CRITERIA:
|
||||||
|
- All 7 repos have zero file: references in their web/dashboard package.json
|
||||||
|
- All 7 builds pass (pnpm build exits 0)
|
||||||
|
- All 7 commits pushed to origin main
|
||||||
|
- No other dependencies or source code modified
|
||||||
|
|
||||||
DO NOT:
|
DO NOT:
|
||||||
- Change any other dependencies
|
- Change any other dependencies
|
||||||
- Modify any source code
|
- Modify any source code
|
||||||
- Skip the build verification step
|
- Skip the build verification step for any repo
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -65,16 +119,28 @@ DO NOT:
|
|||||||
> **Depends on:** Nothing
|
> **Depends on:** Nothing
|
||||||
> **Blocks:** Nothing
|
> **Blocks:** Nothing
|
||||||
|
|
||||||
|
### Per-Repo Checklist
|
||||||
|
|
||||||
|
| # | Repo | File | Pattern | Edited | Docker Build | Vercel Build | Committed | Pushed |
|
||||||
|
| --- | ------------------------------ | -------------------- | --------------------- | :----: | :----------: | :----------: | :-------: | :----: |
|
||||||
|
| 1 | `learning_ai_fastgap` | `web/next.config.ts` | output + tracing root | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 2 | `learning_ai_notes` | `web/next.config.ts` | output + tracing root | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 3 | `learning_ai_trails` | `web/next.config.ts` | output only | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 4 | `learning_ai_local_memory_gpt` | `web/next.config.ts` | output only | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
|
||||||
|
> **Skip:** `learning_ai_local_llms/dashboard/next.config.ts` — LLM Lab not viable on Vercel (needs local Ollama)
|
||||||
|
|
||||||
|
### Prompt
|
||||||
|
|
||||||
```
|
```
|
||||||
TASK: Make the Next.js output mode Vercel-aware in 4 repos that currently hardcode output: 'standalone'.
|
TASK: Make the Next.js output mode Vercel-aware in 4 repos that currently hardcode output: 'standalone'.
|
||||||
|
|
||||||
CONTEXT:
|
CONTEXT:
|
||||||
- Vercel manages its own output mode — hardcoded standalone breaks Vercel builds
|
- Vercel manages its own output mode — hardcoded standalone breaks Vercel builds
|
||||||
- The fix is: wrap standalone output in a process.env.VERCEL conditional
|
- The fix: wrap standalone output in a process.env.VERCEL conditional
|
||||||
- Docker builds (which don't set VERCEL env var) will still get standalone mode
|
- Docker builds (which don't set VERCEL env var) will still get standalone mode
|
||||||
- 4 repos need this fix
|
|
||||||
|
|
||||||
REPOS AND FILES:
|
REPOS AND EXACT CHANGES:
|
||||||
|
|
||||||
1. learning_ai_fastgap/web/next.config.ts
|
1. learning_ai_fastgap/web/next.config.ts
|
||||||
Change:
|
Change:
|
||||||
@ -87,7 +153,7 @@ REPOS AND FILES:
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
2. learning_ai_notes/web/next.config.ts
|
2. learning_ai_notes/web/next.config.ts
|
||||||
Same pattern as above.
|
Same pattern as #1 (output + outputFileTracingRoot).
|
||||||
|
|
||||||
3. learning_ai_trails/web/next.config.ts
|
3. learning_ai_trails/web/next.config.ts
|
||||||
Change:
|
Change:
|
||||||
@ -96,16 +162,36 @@ REPOS AND FILES:
|
|||||||
...(process.env.VERCEL ? {} : { output: 'standalone' }),
|
...(process.env.VERCEL ? {} : { output: 'standalone' }),
|
||||||
|
|
||||||
4. learning_ai_local_memory_gpt/web/next.config.ts
|
4. learning_ai_local_memory_gpt/web/next.config.ts
|
||||||
Same pattern as #3.
|
Same pattern as #3 (output only).
|
||||||
|
|
||||||
NOTE: learning_ai_local_llms/dashboard/next.config.ts also has this but LLM Lab is NOT viable on Vercel (needs local Ollama), so skip it.
|
FOR EACH REPO (repeat 4 times):
|
||||||
|
- [ ] 1. Edit next.config.ts with the VERCEL conditional
|
||||||
|
- [ ] 2. Verify Docker build still works (standalone activates without VERCEL env):
|
||||||
|
cd web && pnpm build
|
||||||
|
# Check output: look for "Creating an optimized production build" + ".next/standalone/" dir
|
||||||
|
ls -d .next/standalone/ && echo "PASS: standalone created" || echo "FAIL"
|
||||||
|
- [ ] 3. Verify Vercel-mode build works (standalone skipped with VERCEL env):
|
||||||
|
cd web && VERCEL=1 pnpm build
|
||||||
|
# Check output: .next/standalone/ should NOT exist
|
||||||
|
ls -d .next/standalone/ 2>/dev/null && echo "FAIL: standalone still created" || echo "PASS: no standalone"
|
||||||
|
- [ ] 4. Commit: fix(web): make output mode Vercel-aware — conditional standalone
|
||||||
|
- [ ] 5. Push to origin main
|
||||||
|
|
||||||
FOR EACH REPO:
|
VERIFICATION (after all 4 repos):
|
||||||
1. Edit next.config.ts with the conditional
|
for repo in learning_ai_fastgap learning_ai_notes learning_ai_trails learning_ai_local_memory_gpt; do
|
||||||
2. Verify Docker build still works: pnpm build (standalone should still activate without VERCEL env)
|
echo "=== $repo ==="
|
||||||
3. Verify VERCEL=1 pnpm build also works (output should be default, not standalone)
|
cd $repo/web
|
||||||
4. Commit: fix(web): make output mode Vercel-aware — conditional standalone
|
grep -c "process.env.VERCEL" next.config.ts
|
||||||
5. Push to origin main
|
# Expected: 1 (the conditional)
|
||||||
|
cd ../..
|
||||||
|
done
|
||||||
|
|
||||||
|
SUCCESS CRITERIA:
|
||||||
|
- All 4 next.config.ts files contain process.env.VERCEL conditional
|
||||||
|
- Docker build (no VERCEL env) produces .next/standalone/
|
||||||
|
- Vercel build (VERCEL=1) does NOT produce .next/standalone/
|
||||||
|
- All 4 commits pushed to origin main
|
||||||
|
- No other config options changed
|
||||||
|
|
||||||
DO NOT:
|
DO NOT:
|
||||||
- Change any other config options in next.config.ts
|
- Change any other config options in next.config.ts
|
||||||
@ -120,33 +206,63 @@ DO NOT:
|
|||||||
> **Depends on:** Nothing
|
> **Depends on:** Nothing
|
||||||
> **Blocks:** Nothing
|
> **Blocks:** Nothing
|
||||||
|
|
||||||
|
### Checklist
|
||||||
|
|
||||||
|
| Step | Description | Done |
|
||||||
|
| ---- | ------------------------- | :--: |
|
||||||
|
| 1 | Create `vercel.json` | ⬜ |
|
||||||
|
| 2 | Verify local build | ⬜ |
|
||||||
|
| 3 | Verify SPA routing config | ⬜ |
|
||||||
|
| 4 | Commit + push | ⬜ |
|
||||||
|
|
||||||
|
### Prompt
|
||||||
|
|
||||||
```
|
```
|
||||||
TASK: Create a vercel.json file for the EffoRise Vite SPA to handle client-side routing and API proxy configuration.
|
TASK: Create a vercel.json file for the EffoRise Vite SPA to handle client-side routing and API proxy configuration.
|
||||||
|
|
||||||
CONTEXT:
|
CONTEXT:
|
||||||
- EffoRise is a Vite + React 19 SPA (not Next.js) in the learning_ai_efforise repo
|
- EffoRise is a Vite + React 19 SPA (NOT Next.js) in the learning_ai_efforise repo
|
||||||
- The Vite config is at the repo root (vite.config.ts)
|
- The Vite config is at the repo root (client/ directory has the SPA)
|
||||||
- Build output goes to dist/public/ (custom, not default dist/)
|
- Build output goes to dist/public/ (custom, not default dist/)
|
||||||
- Uses wouter for client-side routing — all routes must serve index.html
|
- Uses wouter for client-side routing — all routes must serve index.html
|
||||||
- The backend API is at https://api.bytelyst.com/efforise
|
- The backend API is at https://api.bytelyst.com/efforise
|
||||||
- Currently uses a dev proxy /api → localhost:4020
|
- Currently uses a dev proxy /api → localhost:4020
|
||||||
|
|
||||||
DELIVERABLES:
|
TASK LIST:
|
||||||
1. Create vercel.json at the repo root with:
|
- [ ] 1. Create client/vercel.json with:
|
||||||
{
|
{
|
||||||
"$schema": "https://openapi.vercel.sh/vercel.json",
|
"$schema": "https://openapi.vercel.sh/vercel.json",
|
||||||
"framework": "vite",
|
"framework": "vite",
|
||||||
"buildCommand": "pnpm build",
|
"buildCommand": "pnpm build",
|
||||||
"outputDirectory": "dist/public",
|
"outputDirectory": "dist/public",
|
||||||
"rewrites": [
|
"rewrites": [
|
||||||
{ "source": "/api/(.*)", "destination": "https://api.bytelyst.com/efforise/$1" },
|
{ "source": "/api/(.*)", "destination": "https://api.bytelyst.com/efforise/$1" },
|
||||||
{ "source": "/(.*)", "destination": "/index.html" }
|
{ "source": "/(.*)", "destination": "/index.html" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
- [ ] 2. Verify local build: cd client && pnpm build
|
||||||
|
Expected: exit code 0, dist/public/index.html exists
|
||||||
|
- [ ] 3. Verify vercel.json is valid JSON: cat client/vercel.json | jq .
|
||||||
|
Expected: formatted JSON output, no parse errors
|
||||||
|
- [ ] 4. Commit: feat(web): add vercel.json for Vite SPA deployment
|
||||||
|
- [ ] 5. Push to origin main
|
||||||
|
|
||||||
2. Verify pnpm build still works locally
|
VERIFICATION:
|
||||||
3. Commit: feat(web): add vercel.json for Vite SPA deployment
|
# Build works
|
||||||
4. Push to origin main
|
cd client && pnpm build && echo "BUILD: PASS" || echo "BUILD: FAIL"
|
||||||
|
|
||||||
|
# Output directory exists
|
||||||
|
ls client/dist/public/index.html && echo "OUTPUT: PASS" || echo "OUTPUT: FAIL"
|
||||||
|
|
||||||
|
# vercel.json valid
|
||||||
|
jq '.rewrites | length' client/vercel.json
|
||||||
|
# Expected: 2
|
||||||
|
|
||||||
|
SUCCESS CRITERIA:
|
||||||
|
- client/vercel.json exists with correct framework, build command, output directory, and rewrites
|
||||||
|
- Local build still produces dist/public/index.html
|
||||||
|
- vercel.json is valid JSON
|
||||||
|
- Commit pushed to origin main
|
||||||
|
|
||||||
DO NOT:
|
DO NOT:
|
||||||
- Modify vite.config.ts
|
- Modify vite.config.ts
|
||||||
@ -158,12 +274,44 @@ DO NOT:
|
|||||||
|
|
||||||
## B4: Update .npmrc Across All Product Repos
|
## B4: Update .npmrc Across All Product Repos
|
||||||
|
|
||||||
> **Depends on:** Track A Prompt A2 (gitea.bytelyst.com must be live and accessible)
|
> **Depends on:** Track A → A2 complete (`gitea.bytelyst.com` live + verified)
|
||||||
> **Blocks:** Vercel deployment
|
> **Blocks:** All Vercel deployments (this is the final gate)
|
||||||
|
|
||||||
|
### Pre-flight Check (must pass before starting)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Verify gitea.bytelyst.com is live and serving packages
|
||||||
|
curl -sf https://gitea.bytelyst.com/api/packages/ByteLyst/npm/@bytelyst%2ferrors | jq '.name'
|
||||||
|
# Expected: "@bytelyst/errors"
|
||||||
|
# If this fails, DO NOT proceed — Track A → A2 is not complete
|
||||||
|
```
|
||||||
|
|
||||||
|
### Per-Repo Checklist
|
||||||
|
|
||||||
|
| # | Repo | .npmrc locations | Updated | Install OK | Committed | Pushed |
|
||||||
|
| --- | ----------------------------------- | -------------------------- | :-----: | :--------: | :-------: | :----: |
|
||||||
|
| 1 | `learning_voice_ai_agent` | root, user-dashboard-web/ | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 2 | `learning_ai_clock` | root, web/ | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 3 | `learning_ai_jarvis_jr` | root, web/ | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 4 | `learning_ai_fastgap` | root, web/ | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 5 | `learning_ai_flowmonk` | root, web/, mobile/ | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 6 | `learning_ai_notes` | root, web/, mobile/ | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 7 | `learning_ai_trails` | root, web/, sdk/ | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 8 | `learning_multimodal_memory_agents` | root, mindlyst-native/web/ | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 9 | `learning_ai_local_memory_gpt` | root, web/ | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 10 | `learning_ai_efforise` | root, mobile/ | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 11 | `learning_ai_local_llms` | dashboard/ | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
| 12 | `learning_ai_peakpulse` | root | ⬜ | ⬜ | ⬜ | ⬜ |
|
||||||
|
|
||||||
|
### Prompt
|
||||||
|
|
||||||
```
|
```
|
||||||
TASK: Update .npmrc files in all product repos to point to the public Gitea npm registry at gitea.bytelyst.com.
|
TASK: Update .npmrc files in all product repos to point to the public Gitea npm registry at gitea.bytelyst.com.
|
||||||
|
|
||||||
|
PRE-FLIGHT (must pass before starting):
|
||||||
|
curl -sf https://gitea.bytelyst.com/api/packages/ByteLyst/npm/@bytelyst%2ferrors | jq '.name'
|
||||||
|
# Must return "@bytelyst/errors" — if not, STOP and report that Track A → A2 is not done
|
||||||
|
|
||||||
CONTEXT:
|
CONTEXT:
|
||||||
- All product repos currently have .npmrc pointing to http://localhost:3300 (local Gitea)
|
- All product repos currently have .npmrc pointing to http://localhost:3300 (local Gitea)
|
||||||
- Gitea is now accessible at https://gitea.bytelyst.com via Caddy reverse proxy
|
- Gitea is now accessible at https://gitea.bytelyst.com via Caddy reverse proxy
|
||||||
@ -171,67 +319,126 @@ CONTEXT:
|
|||||||
- Auth token is passed via GITEA_NPM_TOKEN env var
|
- Auth token is passed via GITEA_NPM_TOKEN env var
|
||||||
- This change enables Vercel builds to install @bytelyst/* packages
|
- This change enables Vercel builds to install @bytelyst/* packages
|
||||||
|
|
||||||
NEW .npmrc CONTENT (same for all repos):
|
TARGET .npmrc CONTENT (same for all repos):
|
||||||
@bytelyst:registry=https://gitea.bytelyst.com/api/packages/ByteLyst/npm/
|
@bytelyst:registry=https://gitea.bytelyst.com/api/packages/ByteLyst/npm/
|
||||||
//gitea.bytelyst.com/api/packages/ByteLyst/npm/:_authToken=${GITEA_NPM_TOKEN}
|
//gitea.bytelyst.com/api/packages/ByteLyst/npm/:_authToken=${GITEA_NPM_TOKEN}
|
||||||
|
|
||||||
REPOS TO UPDATE (12 total):
|
REPOS TO UPDATE (12 total — see checklist above for .npmrc locations):
|
||||||
|
|
||||||
1. learning_voice_ai_agent (user-dashboard-web, backend)
|
1. learning_voice_ai_agent (root .npmrc + user-dashboard-web/.npmrc)
|
||||||
2. learning_ai_clock (web, backend)
|
2. learning_ai_clock (root + web/)
|
||||||
3. learning_ai_jarvis_jr (web, backend)
|
3. learning_ai_jarvis_jr (root + web/)
|
||||||
4. learning_ai_fastgap (web, backend)
|
4. learning_ai_fastgap (root + web/)
|
||||||
5. learning_ai_flowmonk (web, backend, mobile)
|
5. learning_ai_flowmonk (root + web/ + mobile/)
|
||||||
6. learning_ai_notes (web, backend, mobile)
|
6. learning_ai_notes (root + web/ + mobile/)
|
||||||
7. learning_ai_trails (web, backend, sdk)
|
7. learning_ai_trails (root + web/ + sdk/)
|
||||||
8. learning_multimodal_memory_agents (mindlyst-native/web, backend)
|
8. learning_multimodal_memory_agents (root + mindlyst-native/web/)
|
||||||
9. learning_ai_local_memory_gpt (web, backend)
|
9. learning_ai_local_memory_gpt (root + web/)
|
||||||
10. learning_ai_efforise (root, backend, mobile)
|
10. learning_ai_efforise (root + mobile/)
|
||||||
11. learning_ai_local_llms (dashboard)
|
11. learning_ai_local_llms (dashboard/)
|
||||||
12. learning_ai_peakpulse (backend)
|
12. learning_ai_peakpulse (root)
|
||||||
|
|
||||||
FOR EACH REPO:
|
FOR EACH REPO (repeat 12 times):
|
||||||
1. Find all .npmrc files (there may be multiple — root, web/, backend/, mobile/)
|
- [ ] 1. Find all .npmrc files: find . -name ".npmrc" -not -path "*/node_modules/*"
|
||||||
2. Update the @bytelyst registry line to use gitea.bytelyst.com
|
- [ ] 2. In each .npmrc, replace the @bytelyst registry line:
|
||||||
3. Add the auth token line if not present
|
OLD: @bytelyst:registry=http://localhost:3300/api/packages/ByteLyst/npm/
|
||||||
4. Run: GITEA_NPM_TOKEN=<token> pnpm install (verify packages resolve)
|
NEW: @bytelyst:registry=https://gitea.bytelyst.com/api/packages/ByteLyst/npm/
|
||||||
5. Commit: chore: update .npmrc to public Gitea registry at gitea.bytelyst.com
|
- [ ] 3. Ensure the auth token line exists:
|
||||||
6. Push to origin main
|
//gitea.bytelyst.com/api/packages/ByteLyst/npm/:_authToken=${GITEA_NPM_TOKEN}
|
||||||
|
- [ ] 4. Verify no localhost:3300 references remain:
|
||||||
|
grep -r "localhost:3300" . --include=".npmrc"
|
||||||
|
Expected: no output
|
||||||
|
- [ ] 5. Verify packages resolve:
|
||||||
|
GITEA_NPM_TOKEN=<token> pnpm install
|
||||||
|
Expected: exit code 0, all @bytelyst/* packages resolved
|
||||||
|
- [ ] 6. Commit: chore: update .npmrc to public Gitea registry at gitea.bytelyst.com
|
||||||
|
- [ ] 7. Push to origin main
|
||||||
|
|
||||||
VERIFICATION:
|
VERIFICATION (after all 12 repos — run from parent directory containing all repos):
|
||||||
After updating all repos, verify one end-to-end:
|
echo "=== .npmrc Migration Verification ==="
|
||||||
|
|
||||||
|
# Check no localhost:3300 remains anywhere
|
||||||
|
for repo in learning_voice_ai_agent learning_ai_clock learning_ai_jarvis_jr learning_ai_fastgap learning_ai_flowmonk learning_ai_notes learning_ai_trails learning_multimodal_memory_agents learning_ai_local_memory_gpt learning_ai_efforise learning_ai_local_llms learning_ai_peakpulse; do
|
||||||
|
count=$(grep -rl "localhost:3300" $repo/ --include=".npmrc" 2>/dev/null | wc -l | tr -d ' ')
|
||||||
|
echo "$repo: $count old refs remaining"
|
||||||
|
done
|
||||||
|
# Expected: all show "0 old refs remaining"
|
||||||
|
|
||||||
|
# End-to-end build test on one repo
|
||||||
cd learning_ai_clock/web
|
cd learning_ai_clock/web
|
||||||
GITEA_NPM_TOKEN=<token> pnpm install
|
GITEA_NPM_TOKEN=<token> pnpm install && pnpm build && echo "E2E: PASS" || echo "E2E: FAIL"
|
||||||
pnpm build
|
# Expected: "E2E: PASS"
|
||||||
|
|
||||||
|
SUCCESS CRITERIA:
|
||||||
|
- All 12 repos have zero localhost:3300 references in .npmrc files
|
||||||
|
- All 12 repos can resolve @bytelyst/* packages via gitea.bytelyst.com
|
||||||
|
- At least one repo verified with full pnpm install + pnpm build
|
||||||
|
- All 12 commits pushed to origin main
|
||||||
|
- No package versions changed, no auth tokens hardcoded
|
||||||
|
|
||||||
DO NOT:
|
DO NOT:
|
||||||
- Change any package versions
|
- Change any package versions
|
||||||
- Remove any other registry configurations (e.g., npmjs.org for non-@bytelyst packages)
|
- Remove any other registry configurations (e.g., npmjs.org for non-@bytelyst packages)
|
||||||
- Hardcode the auth token — always use ${GITEA_NPM_TOKEN}
|
- Hardcode the auth token — always use ${GITEA_NPM_TOKEN}
|
||||||
|
- Proceed if the pre-flight check fails
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Track B Execution Order
|
## Track B — Final Verification Checklist
|
||||||
|
|
||||||
```
|
After all 4 prompts are complete, verify the full picture:
|
||||||
B1: Fix file: refs ──────┐
|
|
||||||
B2: Fix standalone ──────┼──→ B4: Update .npmrc (waits for Track A → A2)
|
```bash
|
||||||
B3: EffoRise vercel.json ┘
|
echo "=== Track B Final Verification ==="
|
||||||
|
|
||||||
|
echo "--- B1: file: refs (7 repos) ---"
|
||||||
|
for repo in learning_ai_clock learning_ai_jarvis_jr learning_ai_fastgap learning_ai_flowmonk learning_ai_notes learning_ai_local_memory_gpt learning_ai_local_llms; do
|
||||||
|
count=$(grep -rl "file:.*common_plat" $repo/web/package.json $repo/dashboard/package.json 2>/dev/null | wc -l | tr -d ' ')
|
||||||
|
echo "$repo: $count file: refs"
|
||||||
|
done
|
||||||
|
# Expected: all 0
|
||||||
|
|
||||||
|
echo "--- B2: standalone conditional (4 repos) ---"
|
||||||
|
for repo in learning_ai_fastgap learning_ai_notes learning_ai_trails learning_ai_local_memory_gpt; do
|
||||||
|
count=$(grep -c "process.env.VERCEL" $repo/web/next.config.ts 2>/dev/null)
|
||||||
|
echo "$repo: $count VERCEL conditionals"
|
||||||
|
done
|
||||||
|
# Expected: all 1
|
||||||
|
|
||||||
|
echo "--- B3: EffoRise vercel.json ---"
|
||||||
|
jq '.rewrites | length' learning_ai_efforise/client/vercel.json 2>/dev/null
|
||||||
|
# Expected: 2
|
||||||
|
|
||||||
|
echo "--- B4: .npmrc migration (12 repos) ---"
|
||||||
|
for repo in learning_voice_ai_agent learning_ai_clock learning_ai_jarvis_jr learning_ai_fastgap learning_ai_flowmonk learning_ai_notes learning_ai_trails learning_multimodal_memory_agents learning_ai_local_memory_gpt learning_ai_efforise learning_ai_local_llms learning_ai_peakpulse; do
|
||||||
|
count=$(grep -rl "localhost:3300" $repo/ --include=".npmrc" 2>/dev/null | wc -l | tr -d ' ')
|
||||||
|
echo "$repo: $count old .npmrc refs"
|
||||||
|
done
|
||||||
|
# Expected: all 0
|
||||||
```
|
```
|
||||||
|
|
||||||
B1, B2, B3 can all run in parallel immediately. B4 must wait until `gitea.bytelyst.com` is live (Track A, Prompt A2).
|
**All checks must pass before Track B is considered complete.**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## After Both Tracks Complete
|
## After Both Tracks Complete — Vercel Project Setup (Manual)
|
||||||
|
|
||||||
```
|
Once Track A and Track B are both verified, the remaining work is manual in the Vercel UI:
|
||||||
Manual steps (Vercel UI):
|
|
||||||
→ Create Vercel projects for each app
|
|
||||||
→ Set GITEA_NPM_TOKEN + other env vars per project
|
|
||||||
→ Trigger first deploys and verify
|
|
||||||
```
|
|
||||||
|
|
||||||
See [`ECOSYSTEM_WEB_APPS_INVENTORY.md`](./ECOSYSTEM_WEB_APPS_INVENTORY.md) for the full app list and per-app environment variables.
|
| # | App | Vercel Root Dir | Framework | Key Env Vars | Roadmap |
|
||||||
See individual `ROADMAP_*.md` files for per-app Vercel project setup details.
|
| --- | ----------------- | ------------------------ | --------- | ------------------------------------------------------ | ---------------------------------------------------------- |
|
||||||
|
| 1 | Admin Dashboard | `dashboards/admin-web` | Next.js | `COSMOS_ENDPOINT`, `COSMOS_KEY`, `JWT_SECRET` | [ROADMAP_ADMIN_WEB.md](./ROADMAP_ADMIN_WEB.md) |
|
||||||
|
| 2 | Tracker Dashboard | `dashboards/tracker-web` | Next.js | `JWT_SECRET`, `PLATFORM_SERVICE_URL` | [ROADMAP_TRACKER_WEB.md](./ROADMAP_TRACKER_WEB.md) |
|
||||||
|
| 3 | User Dashboard | `user-dashboard-web` | Next.js | `PLATFORM_SERVICE_URL`, `ACTIONTRAIL_SERVICE_URL` | [ROADMAP_USER_DASHBOARD.md](./ROADMAP_USER_DASHBOARD.md) |
|
||||||
|
| 4 | ChronoMind Web | `web` | Next.js | `GITEA_NPM_TOKEN` | [ROADMAP_CHRONOMIND_WEB.md](./ROADMAP_CHRONOMIND_WEB.md) |
|
||||||
|
| 5 | JarvisJr Web | `web` | Next.js | `GITEA_NPM_TOKEN`, `NEXT_PUBLIC_PLATFORM_URL` | [ROADMAP_JARVISJR_WEB.md](./ROADMAP_JARVISJR_WEB.md) |
|
||||||
|
| 6 | NomGap Web | `web` | Next.js | `GITEA_NPM_TOKEN`, `NEXT_PUBLIC_BACKEND_URL` | [ROADMAP_NOMGAP_WEB.md](./ROADMAP_NOMGAP_WEB.md) |
|
||||||
|
| 7 | FlowMonk Web | `web` | Next.js | `GITEA_NPM_TOKEN`, `NEXT_PUBLIC_BACKEND_URL` | [ROADMAP_FLOWMONK_WEB.md](./ROADMAP_FLOWMONK_WEB.md) |
|
||||||
|
| 8 | NoteLett Web | `web` | Next.js | `GITEA_NPM_TOKEN`, `NEXT_PUBLIC_BACKEND_URL` | [ROADMAP_NOTELETT_WEB.md](./ROADMAP_NOTELETT_WEB.md) |
|
||||||
|
| 9 | ActionTrail Web | `web` | Next.js | `GITEA_NPM_TOKEN`, `NEXT_PUBLIC_BACKEND_URL` | [ROADMAP_ACTIONTRAIL_WEB.md](./ROADMAP_ACTIONTRAIL_WEB.md) |
|
||||||
|
| 10 | MindLyst Web | `mindlyst-native/web` | Next.js | `GITEA_NPM_TOKEN`, `COSMOS_ENDPOINT`, `OPENAI_API_KEY` | [ROADMAP_MINDLYST_WEB.md](./ROADMAP_MINDLYST_WEB.md) |
|
||||||
|
| 11 | LocalMemGPT Web | `web` | Next.js | `GITEA_NPM_TOKEN`, `NEXT_PUBLIC_BACKEND_URL` | [ROADMAP_LOCALMEMGPT_WEB.md](./ROADMAP_LOCALMEMGPT_WEB.md) |
|
||||||
|
| 12 | EffoRise Client | `client` | Vite | `GITEA_NPM_TOKEN`, `VITE_BACKEND_URL` | [ROADMAP_EFFORISE.md](./ROADMAP_EFFORISE.md) |
|
||||||
|
|
||||||
|
**Every Vercel project needs `GITEA_NPM_TOKEN` set.** See individual roadmap files for the complete env var list per app.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user