Make the automated pipeline the documented "setup moving forward" and finish scrubbing the last stale GitHub-Actions/racknerd1 references that never reached main. - HANDOFF.md: refresh the stale 2026-06-21 snapshot. New "CI/CD & deploy" section (push to main -> build + push to registry.snsnetlabs.com -> auto-deploy to racknerd2 over SSH, SHA-pinned, /api/health gate), racknerd2 validation-host + SSH-tunnel access notes, Forgejo workflow rule, and a current Deployment + orientation section. - .kiro/steering/project-guide.md: Forgejo-only Git workflow (no gh), CI/CD row, registry host, racknerd2 + forgejo-runner SSH entries, and a CI/CD pipeline section. - .kiro/hooks/tunnel-racknerd2-8080.kiro.hook: the "View ArchNest on racknerd2" hook (ssh -L 8080:localhost:8080 -N) to view the deployed site at http://localhost:8080 (racknerd2's edge only allows port 22). - src/pages/Settings.tsx: About panel repo URL -> Forgejo. - .dockerignore: .github -> .forgejo. - TERMIX_MIGRATION.md / docs/OPEN-SOURCE-RELEASE.md: drop stale .github/workflows + "GitHub Actions deploy" references. Co-authored-by: Samuel James <ssamjame@amazon.com> Co-authored-by: Kiro <noreply@kiro.dev>
6.1 KiB
6.1 KiB
ArchNest — Project Guide for Kiro
Steering file for AI sessions working on this repo. Covers architecture decisions, workflow rules, and patterns to follow. Read alongside
design-rules.md(visual conventions) which is injected separately.
Quick Context
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.
Tech Stack (exact versions matter)
| Layer | Tech |
|---|---|
| Frontend | React 19, Vite 8, TypeScript 6, Tailwind CSS v4, React Router 7 |
| Charts | Recharts 3 |
| Icons | Lucide React (verify exports exist at runtime, not just TS types) |
| Terminal | xterm.js 6 (@xterm/xterm + @xterm/addon-fit) |
| Backend | Fastify 5, TypeScript 5.7, ESM (tsx dev, tsc -b build) |
| DB | better-sqlite3 (SQLite) |
| Auth | @fastify/jwt + bcryptjs + server-tracked sessions |
| 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. |
Git Workflow
- Remote:
origin→ private Forgejoforgejo.archnest.local:3000/sam/dev_arc_aws(SSH via ProxyJump). Forgejo-only — no GitHub, noghCLI. - Container registry:
registry.snsnetlabs.com(usersam, package token). Unproxied host so large layers bypass Cloudflare's body cap; web UI/packages stay onforgejo.snsnetlabs.com. - Never commit on
main. Always createkiro/<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. - Stage specific files — never
git add -Ablindly - PR flow:
git push -u origin <branch>→ open a PR on Forgejo (web UI/API) → merge tomain. Merging tomainauto-builds + auto-deploys to racknerd2 (build.yml).deploy.ymlis a manual dispatch for deploying/rolling back any tag.
Code Patterns to Follow
Frontend
- One page component per route in
src/pages/ - All backend calls go through
src/lib/api.ts(typedapiFetchwrapper) - No global state library — plain React state + localStorage for prefs
- Auth via
src/lib/AuthContext.tsx(JWT in localStorage) - New pages need: route in
App.tsx, entry inapi.ts, sidebar link
Backend
- One route file per feature in
backend/src/routes/ - Integration adapters in
backend/src/integrations/(must implementtestConnection()) - SSH-based features use
backend/src/ssh/connect.tsshared transport - Request validation with zod schemas
- Audit logging via
logEvent()fromdb/index.ts - Secrets encrypted at rest (AES-256-GCM via
db/crypto.ts) - Never expose secret values to frontend — only
secretKeys: string[]
Adding a New Integration
- Create adapter in
backend/src/integrations/<name>.ts - Register in
backend/src/integrations/registry.ts - Add type to
IntegrationTypeunion - Add route if needed in
backend/src/routes/ - Add
api.tsfunctions + TS interfaces on frontend - Add card in Settings integrations section
Policies
- Versioning: development happens on even major versions; odd majors
are released/stable lines. We are currently developing v2 (the prior
released line is v1, see the
v1.0git tag). Image/version tags should reflect this — dev builds carry the even (v2) version. - Zero mock data — every number comes from a live API/SSH/DB call
- Design-first for big features — write a
docs/<feature>.mdbefore coding - No footer on any page
- Primary target: 1920px+ viewport, should feel spacious
- Mesh gate defaults OFF — never lock the live instance
- OpenSSL legacy provider in backend Dockerfile — don't remove (needed for old PEM keys)
Environment
- Required env vars:
ARCHNEST_SECRET_KEY,ARCHNEST_JWT_SECRET - Optional:
ARCHNEST_DB_PATH,PORT,ARCHNEST_GUAC_CRYPT_KEY,ARCHNEST_CORS_ORIGIN,ARCHNEST_AGENT_TOKEN,ARCHNEST_AGENT_STALE_MS - Frontend dev proxies
/api→http://localhost:4000
Key Files to Read First
README.md— architecture overviewHANDOFF.md— current state + standing rulesdesign-decisions.md— visual conventions + per-page implementation notesROADMAP.md— deferred/tiered workdocs/— subsystem design documents
SSH Config (for reference)
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.yamlsetscontainer.docker_host: automount.ssh racknerd2→ validation/preview host (root). Runs the deployed stack from/opt/archnest/. Mesh IP100.96.217.250. Edge only allows port 22 — view the site via the SSH tunnel hook (-L 8080:localhost:8080) athttp://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: jobbuild(build + push:latestand:<sha>to the registry) → jobdeploy(needs build; SSH to racknerd2,docker compose pull && up -dpinned to<sha>,/api/healthgate). - Required Forgejo Actions secrets:
FORGEJO_REGISTRY_TOKEN,RACKNERD2_SSH_KEY. - The build job installs
docker-ce-clifrom Docker's apt repo (Debian'sdocker.iois too old for the host daemon). Don't switch it back todocker.io. - racknerd2
/opt/archnest/docker-compose.ymlPULLS registry images; the repo-rootdocker-compose.ymlBUILDS locally (dev/manual).