Compare commits
No commits in common. "main" and "kiro/forgejo-build-deploy" have entirely different histories.
main
...
kiro/forge
9 changed files with 45 additions and 131 deletions
|
|
@ -1,6 +1,6 @@
|
|||
node_modules
|
||||
dist
|
||||
.git
|
||||
.forgejo
|
||||
.github
|
||||
pics
|
||||
*.md
|
||||
|
|
|
|||
|
|
@ -31,17 +31,9 @@ jobs:
|
|||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Docker CLI
|
||||
# Debian bookworm's docker.io is too old (API 1.41) for the host daemon
|
||||
# (needs >= 1.44), so install the current docker-ce-cli from Docker's repo.
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends ca-certificates curl
|
||||
install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
|
||||
chmod a+r /etc/apt/keyrings/docker.asc
|
||||
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian bookworm stable" > /etc/apt/sources.list.d/docker.list
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends docker-ce-cli
|
||||
apt-get install -y --no-install-recommends docker.io
|
||||
docker version
|
||||
|
||||
- name: Log in to Forgejo registry
|
||||
|
|
@ -70,37 +62,3 @@ jobs:
|
|||
- name: Log out
|
||||
if: always()
|
||||
run: docker logout "$REGISTRY"
|
||||
|
||||
deploy:
|
||||
# Auto-deploy to racknerd2 after a successful build. Deploys the exact
|
||||
# images just built (pinned to this commit's SHA). For manual/on-demand
|
||||
# deploys of an arbitrary tag (e.g. rollback), use the separate
|
||||
# "Deploy to racknerd2" workflow (deploy.yml).
|
||||
needs: build
|
||||
runs-on: docker
|
||||
env:
|
||||
DEPLOY_HOST: 100.96.217.250
|
||||
DEPLOY_DIR: /opt/archnest
|
||||
steps:
|
||||
- name: Install SSH client
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends openssh-client
|
||||
|
||||
- name: Write deploy key
|
||||
run: |
|
||||
install -m 700 -d ~/.ssh
|
||||
printf '%s\n' "${{ secrets.RACKNERD2_SSH_KEY }}" > ~/.ssh/id_deploy
|
||||
chmod 600 ~/.ssh/id_deploy
|
||||
|
||||
- name: Pull this build's images and restart stack
|
||||
run: |
|
||||
ssh -i ~/.ssh/id_deploy -o StrictHostKeyChecking=accept-new \
|
||||
root@"$DEPLOY_HOST" \
|
||||
"cd $DEPLOY_DIR && ARCHNEST_TAG='${{ github.sha }}' docker compose pull && ARCHNEST_TAG='${{ github.sha }}' docker compose up -d --remove-orphans"
|
||||
|
||||
- name: Health check (backend /api/health via mesh)
|
||||
run: |
|
||||
ssh -i ~/.ssh/id_deploy -o StrictHostKeyChecking=accept-new \
|
||||
root@"$DEPLOY_HOST" \
|
||||
"for i in \$(seq 1 30); do curl -fsS http://$DEPLOY_HOST:8080/api/health && echo OK && exit 0; sleep 2; done; echo 'health check failed'; cd $DEPLOY_DIR && docker compose logs --tail=50; exit 1"
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"enabled": true,
|
||||
"name": "View ArchNest on racknerd2 (localhost:8080)",
|
||||
"description": "Opens an SSH local port-forward (localhost:8080 -> racknerd2 8080) so the deployed ArchNest site can be viewed in a browser at http://localhost:8080. RackNerd's edge only allows port 22, so this tunnels the web app over SSH. Trigger it to start the tunnel; stop the hook's process to close it.",
|
||||
"version": "1",
|
||||
"when": {
|
||||
"type": "userTriggered"
|
||||
},
|
||||
"then": {
|
||||
"type": "runCommand",
|
||||
"command": "ssh -o BatchMode=yes -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -L 8080:localhost:8080 -N racknerd2",
|
||||
"timeout": 0
|
||||
}
|
||||
}
|
||||
|
|
@ -10,10 +10,8 @@
|
|||
|
||||
ArchNest is a **self-hosted ops dashboard** — live infrastructure monitoring,
|
||||
SSH terminal/tunnels/files, Docker container management, remote desktop, and
|
||||
bookmarks. **Private Forgejo repo (never public) — no GitHub.** CI/CD is
|
||||
Forgejo Actions: push to `main` builds images, pushes to
|
||||
`registry.snsnetlabs.com`, and auto-deploys to **racknerd2** (validation/preview
|
||||
host) over SSH. See `HANDOFF.md` → "CI/CD & deploy" and `deploy/README.md`.
|
||||
bookmarks. Deployed at `archnest.snsnetlabs.com` via Docker Compose on
|
||||
`racknerd1`. Private Forgejo repo (never public).
|
||||
|
||||
## Tech Stack (exact versions matter)
|
||||
|
||||
|
|
@ -29,22 +27,20 @@ host) over SSH. See `HANDOFF.md` → "CI/CD & deploy" and `deploy/README.md`.
|
|||
| Validation | zod |
|
||||
| SSH | ssh2 library |
|
||||
| AWS | `@aws-sdk/client-ec2`, `@aws-sdk/client-sts` |
|
||||
| Deploy | Docker Compose (Alpine images) |
|
||||
| CI/CD | Forgejo Actions (`.forgejo/workflows/`): `ci.yml` validate; `build.yml` build+push to `registry.snsnetlabs.com` then auto-deploy to racknerd2. No GitHub. |
|
||||
| Deploy | Docker Compose (Alpine images), GitHub Actions → racknerd1 |
|
||||
|
||||
## Git Workflow
|
||||
|
||||
- **Remote**: `origin` → private Forgejo `forgejo.archnest.local:3000/sam/dev_arc_aws` (SSH via ProxyJump). **Forgejo-only — no GitHub, no `gh` CLI.**
|
||||
- **Container registry**: `registry.snsnetlabs.com` (user `sam`, package token). Unproxied host so large layers bypass Cloudflare's body cap; web UI/packages stay on `forgejo.snsnetlabs.com`.
|
||||
- **Remote**: `origin` → private Forgejo instance (SSH via ProxyJump)
|
||||
- **Never commit on `main`**. Always create `kiro/<feature>` branches.
|
||||
- **Commit style**: imperative title + body explaining why, with trailers:
|
||||
```
|
||||
Co-authored-by: Samuel James <ssamjame@amazon.com>
|
||||
Co-authored-by: Kiro <noreply@kiro.dev>
|
||||
```
|
||||
- **Before committing**: `npm run build` (frontend) + `cd backend && npx tsc --noEmit` (backend). Forgejo CI runs the same.
|
||||
- **Before committing**: `npm run build` (frontend) + `cd backend && npx tsc --noEmit` (backend)
|
||||
- **Stage specific files** — never `git add -A` blindly
|
||||
- **PR flow**: `git push -u origin <branch>` → open a PR on Forgejo (web UI/API) → merge to `main`. **Merging to `main` auto-builds + auto-deploys to racknerd2** (build.yml). `deploy.yml` is a manual dispatch for deploying/rolling back any tag.
|
||||
- **PR flow**: `git push -u origin <branch>` → `gh pr create` → squash-merge
|
||||
|
||||
## Code Patterns to Follow
|
||||
|
||||
|
|
@ -104,13 +100,4 @@ host) over SSH. See `HANDOFF.md` → "CI/CD & deploy" and `deploy/README.md`.
|
|||
|
||||
- `ssh forgejo` → Git operations (User: forgejo, via ProxyJump linode)
|
||||
- `ssh forgejo-admin` → root shell on Forgejo host (for admin tasks)
|
||||
- `ssh forgejo-runner` → host running the Forgejo Actions runner (has Docker; builds images). Runner config `/opt/config.yaml` sets `container.docker_host: automount`.
|
||||
- `ssh racknerd2` → validation/preview host (root). Runs the deployed stack from `/opt/archnest/`. Mesh IP `100.96.217.250`. Edge only allows port 22 — view the site via the SSH tunnel hook (`-L 8080:localhost:8080`) at `http://localhost:8080`.
|
||||
- `ssh linode` → jump host at 172.238.163.85
|
||||
|
||||
## CI/CD pipeline (full detail in `deploy/README.md`)
|
||||
|
||||
- Push to `main` → `build.yml`: job `build` (build + push `:latest` and `:<sha>` to the registry) → job `deploy` (needs build; SSH to racknerd2, `docker compose pull && up -d` pinned to `<sha>`, `/api/health` gate).
|
||||
- Required Forgejo Actions secrets: `FORGEJO_REGISTRY_TOKEN`, `RACKNERD2_SSH_KEY`.
|
||||
- The build job installs **`docker-ce-cli` from Docker's apt repo** (Debian's `docker.io` is too old for the host daemon). Don't switch it back to `docker.io`.
|
||||
- racknerd2 `/opt/archnest/docker-compose.yml` PULLS registry images; the repo-root `docker-compose.yml` BUILDS locally (dev/manual).
|
||||
|
|
|
|||
50
HANDOFF.md
50
HANDOFF.md
|
|
@ -1,43 +1,35 @@
|
|||
# ArchNest — Handoff Notes
|
||||
|
||||
Status snapshot as of **2026-06-25**. Written so a fresh AI session (or human) can pick this up with zero prior context. Always run `git branch --show-current` and work on a fresh feature branch off `main` (convention: `kiro/<feature>`).
|
||||
|
||||
> **Repo is on Forgejo — no GitHub.** `origin` = `forgejo.archnest.local:3000/sam/dev_arc_aws` (push via SSH). The container registry is `registry.snsnetlabs.com` (separate unproxied host). There is no `gh` CLI / GitHub Actions here.
|
||||
Status snapshot as of **2026-06-21**. Written so a fresh AI session (or human) can pick this up with zero prior context. Branch names rotate every session — always run `git branch --show-current` and work on a fresh feature branch off `main` (recent branches have used a `kiro/<feature>` or `claude/<feature>` naming pattern).
|
||||
|
||||
## TL;DR
|
||||
|
||||
ArchNest is **feature-complete and stable** as a self-hosted ops dashboard. The runtime stack is **better-sqlite3 + `@fastify/jwt`/bcrypt sessions + Docker Compose** (the Postgres/Redis/Cognito/Akamai stack in `README.md` + `docs/aws-architecture/` is the *planned paid AWS scale-up target*, not what runs today). All major subsystems are built and merged. **Auth Phases 1-3 done** (Phase 4 SSO is a deferred paid AWS add-on — see `ROADMAP.md`); **Mesh Prerequisite Gate** shipped (Settings → Mesh, defaults OFF).
|
||||
ArchNest is **live and deployed** at `archnest.snsnetlabs.com`, auto-deploying via GitHub Actions (`.github/workflows/deploy.yml`) on every merge to `main` — push triggers a build + SCP + `docker compose up -d --build` on `racknerd1`, with a health-check gate (`/api/health`). Deployment is no longer the open task; it's working infrastructure now.
|
||||
|
||||
## CI/CD & deploy — THE SETUP MOVING FORWARD
|
||||
**Auth is feature-complete for self-hosted** (Phases 1-3: user menu, password/sessions/login-log, multi-user roles; Phase 4 SSO deferred to a paid AWS add-on — see `ROADMAP.md`).
|
||||
|
||||
Fully automated. **Every push to `main`** runs Forgejo Actions on the `forgejo-runner` host:
|
||||
Since then, **Docker container visibility/management was expanded** (shipped, deployed):
|
||||
- **Persistent SSH terminal sessions** (PR #30) — terminals stay connected across in-app page navigation.
|
||||
- **Docker-over-SSH management** + **Docker push-agent monitoring** (PR #31) — see the "Docker: three ways" section below.
|
||||
|
||||
```
|
||||
push main ─► .forgejo/workflows/ci.yml → validate (tsc + build, frontend & backend)
|
||||
─► .forgejo/workflows/build.yml
|
||||
job build → build + push images → registry.snsnetlabs.com/sam/{archnest,archnest-backend} (:latest + :<sha>)
|
||||
job deploy → (needs build) ssh racknerd2 → docker compose pull + up -d @ this <sha> → /api/health gate
|
||||
```
|
||||
**The Mesh Prerequisite Gate is now built and shipped** (no longer the open task): NetBird-mesh-required-before-config, with universal CIDR-based verification (not NetBird-specific), a routed-mesh/VPC-peering reachability fallback, and a dedicated "Mesh" section in Settings to configure/test it. Defaults OFF, so it does not lock the live instance. Commits: `46d95fc` (gate), `0409159` (universal CIDR check), `800072f` (routed-mesh fallback), `4a4a5a0` (Settings UI) — all merged to `main`.
|
||||
|
||||
- **Registry**: `registry.snsnetlabs.com` (user `sam`). It is a **dedicated unproxied (DNS-only) Cloudflare host** so large image layers bypass Cloudflare's ~100 MB body cap (the backend has 260 MB+ layers). The Forgejo **web UI / packages list** stays on `forgejo.snsnetlabs.com` (Cloudflare Access SSO).
|
||||
- **Runner**: `forgejo-runner` host (ssh alias `forgejo-runner`), forgejo-runner v6.3.1, runs jobs in `node:22-bookworm` containers. Its config `/opt/config.yaml` sets `container.docker_host: automount` (mounts the host docker.sock into jobs so they can build images); systemd drop-in points the service at that config. The build job installs **`docker-ce-cli` from Docker's official apt repo** (NOT Debian's `docker.io`, which is too old — API 1.41 vs the daemon's required 1.44+).
|
||||
- **Required Forgejo Actions secrets**: `FORGEJO_REGISTRY_TOKEN` (package-scoped token for `sam`, used for registry login/push), `RACKNERD2_SSH_KEY` (private key for `root@racknerd2`, used by the deploy job).
|
||||
- **`deploy.yml`** is a manual `workflow_dispatch` (deploy/rollback to any tag without rebuilding); the auto-deploy lives in `build.yml`'s `deploy` job.
|
||||
|
||||
### racknerd2 — validation / preview host (NOT permanent)
|
||||
racknerd2 (ssh alias `racknerd2`) is where the deployed build can be **viewed for accuracy**. It only pulls + runs the images (1.9 GiB RAM — never builds). Mesh IP **100.96.217.250**; `/opt/archnest/{docker-compose.yml,.env}` drive a registry-image compose (frontend 8080, backend internal, guacd sidecar). Ports are bound to the mesh IP by default (Docker bypasses ufw, so binding to a specific IP is what keeps it off the public interface).
|
||||
|
||||
**Access for review**: RackNerd's edge only allows **inbound port 22** on racknerd2 (80/443/8080 are dropped upstream), so the site is **not directly reachable on its public IP**. View it via the **SSH local-forward tunnel** — Kiro hook **"View ArchNest on racknerd2 (localhost:8080)"** (`.kiro/hooks/tunnel-racknerd2-8080.kiro.hook`) runs `ssh -L 8080:localhost:8080 -N racknerd2`; trigger it, then open **http://localhost:8080**. A real public URL (later) goes through the NPM reverse proxy on linode (TLS), not racknerd2's raw IP.
|
||||
Most recently (this session, real user dogfooding rather than a planned feature): walked the user through replacing a broken/insecure Docker-TCP-API integration attempt with a working **SSH Host** integration to a real VM ("Portainer VM," running Portainer + a test container), confirmed Docker-over-SSH container management works end to end, and added supporting UX:
|
||||
- **Docker setup-script hint in Settings** (commit `628187b`, branch `claude/youthful-cerf-ibvxfb`, **pushed but NOT YET merged to `main`** — user explicitly deferred merging once already; revisit with the user before merging) — when editing a Docker (`type: 'docker'`) integration's `baseUrl`, Settings now renders a copyable systemd-override + `curl` verification script scoped to that exact host/port, so users don't have to hand-derive the remote-API-enablement steps themselves.
|
||||
- **Help page expansion** (commit `36a79ab`, same branch, pushed) — every page entry in `src/pages/Help.tsx` now has at least one real-world example callout (icon + optional label + scenario text), plus a "New here? Start in this order" quick-start card above the grid, aimed at first-time users who don't yet know which page does what.
|
||||
|
||||
### → NEXT TASK for the picking-up agent
|
||||
**Nothing is queued; the pipeline above is the baseline.** Push to `main` → it auto-builds and auto-deploys to racknerd2; view via the tunnel hook. Pick the next priority with the user (the `ROADMAP.md` tiered/paid add-ons are the menu). Optional small follow-ups noted but not requested: bump `package.json`/About panel to **v2** (convention recorded below); add a one-click "stop tunnel" hook.
|
||||
No new feature is queued. Pick up from here:
|
||||
1. **Decide with the user whether to merge `claude/youthful-cerf-ibvxfb` into `main`.** It contains the Docker setup-script hint (`628187b`) and the Help page expansion (`36a79ab`), both already build-clean (`npm run build` passes). Nothing else is blocking it.
|
||||
2. **Ask the user if removing the unused Docker API integration (the one superseded by the SSH Host setup) is done** — this was a live-instance UI action on their end, not something done via this repo's code.
|
||||
3. Otherwise, check with the user for the next priority — there is no pending design doc or half-built feature waiting right now (mesh gate and Docker UX work above are both fully shipped or ready-to-merge).
|
||||
|
||||
## Standing rules (read before doing anything)
|
||||
|
||||
- **Versioning convention**: development happens on **even** major versions, releases on **odd**. We are currently developing **v2** (prior released line is v1 — see the `v1.0` git tag). Dev image/version tags carry the even (v2) number. `package.json` (root + backend) still reads `0.0.0` and the Settings → About panel is hardcoded `v1.0.0`; neither has been bumped to v2 yet.
|
||||
|
||||
- **Branch**: never commit on `main`. Create a fresh feature branch off `main` (recent convention: `kiro/<short-feature>`). Confirm with `git branch --show-current` before starting.
|
||||
- **Workflow per change**: type-check (`npx tsc --noEmit -p .` in repo root AND in `backend/`) — for frontend changes prefer a full `npm run build` (`tsc -b && vite build`; stricter than plain `tsc --noEmit`) → commit → `git fetch origin main && git rebase origin/main` → `git push -u origin <branch>` → open a PR on Forgejo (web UI/API) and merge to `main`. **Merging to `main` auto-triggers CI: validate + build + push + auto-deploy to racknerd2** (`.forgejo/workflows/`). There is no `gh` CLI here. Watch a run via the runner: `ssh forgejo-runner 'docker ps'` (job containers) / `journalctl -u forgejo-runner`, and confirm the result by checking the SHA-tagged image in `registry.snsnetlabs.com` and `/api/health` on racknerd2 (via the tunnel hook).
|
||||
- **Workflow per change**: type-check (`npx tsc --noEmit -p .` in repo root AND in `backend/`) — and for frontend changes prefer a full `npm run build` (which runs `tsc -b && vite build`; the stricter `tsc -b` has caught errors a plain `tsc --noEmit` missed via stale incremental cache) → commit → `git fetch origin main && git rebase origin/main` → `git push -u origin <branch>` → open a PR with `gh pr create` → squash-merge (`gh pr merge <n> --squash --delete-branch`) → poll the resulting run (`gh run list --branch main`, then `gh run watch <id> --exit-status`) until `validate` and `deploy` both succeed (deploy's last step is "Health check (backend /api/health)").
|
||||
- **`git add -A` caution**: this has twice swept up unrelated untracked files (e.g. a bookmark-import JSON the user asked to be generated, not committed) into unrelated PRs. Prefer `git add <specific files>` and always check `git diff --cached --stat` before committing.
|
||||
- **Never open a PR unless the user's intent is clearly "ship this."** For exploratory/planning asks, use `AskUserQuestion` to confirm scope first — see how the Phase 2/3/4 plan below was scoped before any code was written.
|
||||
- **Mock data policy**: zero mock/fabricated data. Verify with `grep -ri "mock\|fake\|placeholder" src/ backend/src/` if continuing feature work and unsure.
|
||||
|
|
@ -137,14 +129,14 @@ Moved out of the core build. Planned as a **paid add-on shipped when ArchNest is
|
|||
|
||||
Moved to **`ROADMAP.md`** ("Known non-blocking stubs"). Summary: the Infrastructure "Network" sub-tab is intentionally disabled, and the Settings Appearance and Notifications sections are non-functional placeholders. None are flagged as work to do unless explicitly asked — check the latest conversation/commits before assuming a direction.
|
||||
|
||||
## Deployment (current — Forgejo Actions, automated)
|
||||
## Deployment (already working — reference only)
|
||||
|
||||
Full pipeline is documented in **"CI/CD & deploy — THE SETUP MOVING FORWARD"** near the top of this file and in **`deploy/README.md`**. Summary: push to `main` → Forgejo Actions builds + pushes images to `registry.snsnetlabs.com` and auto-deploys to **racknerd2** (validation host) over SSH, SHA-pinned, `/api/health` gated. View racknerd2 via the SSH tunnel hook → `http://localhost:8080` (its public IP only allows port 22). The old GitHub-Actions→racknerd1 SCP pipeline is gone (migrated to Forgejo). `docker-compose.yml` at the repo root still BUILDS locally (dev/manual); `deploy/docker-compose.yml` PULLS from the registry (what racknerd2 runs).
|
||||
`docker-compose.yml` (3 services: `archnest` frontend, `archnest-backend`, `guacd`) + `.github/workflows/deploy.yml` (push-to-`main` → SCP + `docker compose up -d --build` on `racknerd1`, gated on an `/api/health` check) are live and require no further setup. If a deploy fails, check the GitHub Actions run's `deploy` job steps in order — `Pre-flight` (host `.env` exists), `Copy repo to racknerd1`, `Build, restart, and clean up`, `Health check`.
|
||||
|
||||
## Quick orientation for a new session
|
||||
|
||||
1. Read this file, then `deploy/README.md` (build/deploy pipeline), then `ROADMAP.md` (deferred/tiered work), then `docs/` (subsystem design docs — `docker-agent-monitoring.md`, `mesh-prerequisite-gate.md`, `rdp-debug-handoff.md`, `aws-architecture/system-design.md`), then `TERMIX_MIGRATION.md` for feature history, then skim `git log --oneline -30`.
|
||||
2. Frontend: prefer `npm run build` (`tsc -b && vite build`) over plain `tsc --noEmit`. Backend: `npx tsc --noEmit -p .` from `backend/`. Both must pass before any commit (Forgejo CI runs exactly this).
|
||||
3. **Nothing is queued and nothing is half-built.** All major subsystems are merged; CI/CD auto-builds + auto-deploys to racknerd2 on every push to `main`. Check the "→ NEXT TASK" section above, then ask the user for the next priority (`ROADMAP.md` lists deferred/paid add-ons).
|
||||
1. Read this file, then `ROADMAP.md` (deferred/tiered work), then `docs/` (subsystem design docs — `docker-agent-monitoring.md`, `mesh-prerequisite-gate.md`), then `TERMIX_MIGRATION.md` for feature-level history, then skim `git log --oneline -30`.
|
||||
2. Frontend: prefer `npm run build` (`tsc -b && vite build`) over a plain `tsc --noEmit` (stricter, catches more). Backend: `npx tsc --noEmit -p .` from `backend/`. Both must pass before any commit.
|
||||
3. **The Mesh Prerequisite Gate is built and shipped** (Settings → Mesh; defaults OFF). **There is no other planned feature queued right now** — check the "→ NEXT TASK" section above first (merge decision on `claude/youthful-cerf-ibvxfb`), then ask the user for the next priority. Auth Phases 1-3 are done; Phase 4 SSO is a deferred paid AWS add-on (`ROADMAP.md`).
|
||||
4. If asked to add a feature, follow existing patterns: integration adapters in `backend/src/integrations/`, SSH-backed engines in `backend/src/ssh/`, one route file per feature in `backend/src/routes/`, one `api.ts` entry + page component per frontend feature. Subsystem-level work gets a `docs/` design doc first.
|
||||
5. For anything ambiguous in scope, ask the user rather than guessing — that's how the auth phases, Docker agent tiering, and mesh-gate decisions were all scoped.
|
||||
5. For anything ambiguous in scope, use `AskUserQuestion` rather than guessing — that's how the auth phases, the Docker agent tiering, and the mesh-gate decisions were all scoped.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Status doc for porting Termix's full feature set into ArchNest as a single app, single backend, single auth, single database — reskinned to match ArchNest's design. Written so any session (human or AI) can see exactly what's done, what's next, and why decisions were made.
|
||||
|
||||
**Migration status: COMPLETE.** All 8 phases below are DONE and verified. No further feature work is queued from this migration. CI/CD has since moved to **Forgejo Actions** (build → `registry.snsnetlabs.com` → auto-deploy to racknerd2) — see `HANDOFF.md` and `deploy/README.md`. Do not start new feature work here without explicit instruction.
|
||||
**Migration status: COMPLETE.** All 8 phases below are DONE and verified. No further feature work is queued on this branch. If you're picking this project up, the only remaining task is the GitHub Actions deploy setup — see `HANDOFF.md` and the Deployment section of `README.md`. Do not start new feature work here without explicit instruction.
|
||||
|
||||
Source: `https://github.com/SamuelSJames/Termix` (user's fork), cloned for reference at the time of writing. Upstream is `Termix-SSH/Termix`, an Electron + Express + Drizzle ORM self-hosted SSH/RDP/VNC management app — **not** a small terminal widget. It ships as its own Docker image with a `guacd` sidecar for RDP/VNC.
|
||||
|
||||
|
|
|
|||
|
|
@ -6,17 +6,11 @@ over the NetBird mesh. racknerd2 only pulls and runs — it never builds (1.9 Gi
|
|||
RAM).
|
||||
|
||||
```
|
||||
push to main ─► [build.yml]
|
||||
job: build ─► build + push images ─► registry.snsnetlabs.com/sam/{archnest,archnest-backend}
|
||||
job: deploy ─► (needs build) ssh racknerd2 ─► compose pull + up -d (this build's SHA) ─► /api/health
|
||||
push to main / manual ─► [build.yml] build + push images ─► registry.snsnetlabs.com/sam/{archnest,archnest-backend}
|
||||
│
|
||||
manual dispatch (any tag / rollback) ─► [deploy.yml] ssh racknerd2 ─► compose pull && up -d
|
||||
manual dispatch ─► [deploy.yml] ssh racknerd2 ─► docker compose pull && up -d
|
||||
```
|
||||
|
||||
Every push to `main` auto-builds and auto-deploys to racknerd2. `deploy.yml`
|
||||
stays as a manual `workflow_dispatch` for deploying/rolling back to an arbitrary
|
||||
tag without rebuilding.
|
||||
|
||||
## Images
|
||||
|
||||
| Image | From | Tags |
|
||||
|
|
@ -71,19 +65,16 @@ ufw, so this is what keeps the app off the public interface. Validate at
|
|||
|
||||
## Running it
|
||||
|
||||
- **Automatic**: push to `main` → `build.yml` builds + pushes both images, then
|
||||
its `deploy` job (needs `build`) pulls this commit's SHA onto racknerd2,
|
||||
restarts the stack, and health-checks `/api/health`. Fully hands-off.
|
||||
- **Manual build**: run **Build & Push Images** from the Actions tab (also
|
||||
triggers the auto-deploy job).
|
||||
- **Manual deploy / rollback**: run **Deploy to racknerd2**, entering any tag
|
||||
(`latest` or a specific commit SHA) to deploy without rebuilding.
|
||||
1. **Build**: push to `main`, or run **Build & Push Images** manually
|
||||
(Actions tab → Run workflow).
|
||||
2. **Deploy**: run **Deploy to racknerd2** manually, entering the tag
|
||||
(`latest` or a specific commit SHA). It pulls, restarts, and health-checks
|
||||
`/api/health`.
|
||||
|
||||
## Notes / ceilings
|
||||
|
||||
- Auto-deploy targets racknerd2 (the validation host) on every push to `main`,
|
||||
pinned to the built commit's SHA. If you later add a prod host, gate
|
||||
prod deploys behind a manual approval or a tag/release trigger rather than
|
||||
every push.
|
||||
- `ponytail:` deploy is manual (workflow_dispatch), not auto-on-merge — this is
|
||||
a validation host, so deploys are deliberate. Wire `build.yml` → `deploy.yml`
|
||||
with `needs:` later if auto-deploy-to-validation is wanted.
|
||||
- Single-arch (amd64) only — both the runner host and racknerd2 are amd64, so
|
||||
no buildx/multi-platform is needed.
|
||||
|
|
|
|||
|
|
@ -63,8 +63,8 @@ internal working notes that don't belong in a public project:
|
|||
| `docs/rdp-debug-handoff.md` | Contains lab creds (`sam` / `happy2026`) + private VM IP `192.168.122.55` + personal host names | **Exclude** (or heavily genericize into a "Remote Desktop setup" guide with no creds/IPs) |
|
||||
| `HANDOFF.md` | Internal session-to-session working notes | **Exclude** |
|
||||
| `docs/OPEN-SOURCE-RELEASE.md` (this file) | Internal release plan | **Exclude** |
|
||||
| `archnest.snsnetlabs.com` references in `.env.example`, `docker-compose.yml` | Personal domain/deploy target | **Genericize** to `example.com` / `localhost` |
|
||||
| Forgejo CI (`.forgejo/workflows/`) | Already build/validate only (no SCP/personal server). The build workflow pushes to a private registry + deploys to a private host | **Keep but genericize** the registry host + deploy job, or strip the deploy job for a public build-only CI |
|
||||
| `archnest.snsnetlabs.com` references in `.env.example`, `docker-compose.yml`, `.github/workflows/deploy.yml` | Personal domain/deploy target | **Genericize** to `example.com` / `localhost`; the deploy workflow should be removed or replaced with a generic CI (build + lint only, no SCP-to-my-server) |
|
||||
| `.github/workflows/deploy.yml` | SSHes/SCPs to the personal `racknerd1` server | **Remove**; replace with a generic build/test CI workflow |
|
||||
| `agent/` deploy specifics | Fine to include the agent script, but scrub any host-specific URLs/tokens in its README | **Review + genericize** |
|
||||
| `assets/` personal background images | Large PNGs; keep the ones the UI needs (hero banner, logo, KPI backgrounds), drop unused experiments (`opt1.bg`, `settings-custom-bg`, `pics/`) | **Trim to what's referenced** |
|
||||
| Test/scratch files | `backend/data/`, any `*.db`, session logs | Already gitignored — confirm none are force-added |
|
||||
|
|
@ -115,7 +115,7 @@ LICENSE, README.md, CONTRIBUTING.md, screenshots/ # new, written for OSS
|
|||
HANDOFF.md
|
||||
docs/rdp-debug-handoff.md
|
||||
docs/OPEN-SOURCE-RELEASE.md (this file)
|
||||
.forgejo/workflows/ (genericize: strip registry host + deploy job, or build-only CI)
|
||||
.github/workflows/deploy.yml (replace with generic CI)
|
||||
backend/data/, *.db, session logs, *.tsbuildinfo
|
||||
unused assets/ experiments + pics/
|
||||
```
|
||||
|
|
@ -212,7 +212,7 @@ Notes for credibility:
|
|||
- [ ] Create fresh public repo, copy INCLUDE list, exclude EXCLUDE list.
|
||||
- [ ] Genericize personal domain → `example.com`/`localhost` in
|
||||
`.env.example`, `docker-compose.yml`.
|
||||
- [ ] Genericize `.forgejo/workflows/` for public use (strip the private registry host + the racknerd2 deploy job, or ship build-only CI).
|
||||
- [ ] Replace `.github/workflows/deploy.yml` with a generic build/lint CI (no SCP).
|
||||
- [ ] Add `LICENSE` (MIT), public `README.md`, `CONTRIBUTING.md`.
|
||||
- [ ] Capture + add screenshots (sanitized data, dark theme).
|
||||
- [ ] Re-run a secret scan on the NEW repo before first push
|
||||
|
|
|
|||
|
|
@ -1343,7 +1343,7 @@ function AboutSection() {
|
|||
const rows: [string, string][] = [
|
||||
['App', 'ArchNest Dashboard v1.0.0'],
|
||||
['Author', 'Samuel James'],
|
||||
['Repo', 'forgejo.snsnetlabs.com/sam/dev_arc_aws'],
|
||||
['Repo', 'github.com/SamuelSJames/archnest'],
|
||||
['Stack', 'React 19, Vite, TypeScript'],
|
||||
['License', 'MIT'],
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue