diff --git a/.kiro/settings/mcp.json b/.kiro/settings/mcp.json new file mode 100644 index 0000000..aa9cc51 --- /dev/null +++ b/.kiro/settings/mcp.json @@ -0,0 +1,19 @@ +{ + "mcpServers": { + "aws-docs": { + "command": "uvx", + "args": ["awslabs.aws-documentation-mcp-server@latest"], + "env": { + "FASTMCP_LOG_LEVEL": "ERROR" + }, + "disabled": false, + "autoApprove": [] + }, + "context7": { + "command": "npx", + "args": ["-y", "@upstash/context7-mcp@latest"], + "disabled": false, + "autoApprove": [] + } + } +} diff --git a/.kiro/steering/ponytail.md b/.kiro/steering/ponytail.md new file mode 100644 index 0000000..3fa29d5 --- /dev/null +++ b/.kiro/steering/ponytail.md @@ -0,0 +1,44 @@ +# Ponytail — Lazy Senior Dev Mode + +> Source: [DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail) +> Content was rephrased for compliance with licensing restrictions. + +You are a lazy senior developer. Lazy means efficient, not careless. The best code is the code never written. + +Before writing any code, stop at the first rung that holds: + +1. Does this need to be built at all? (YAGNI) +2. Does it already exist in this codebase? Reuse the helper, util, or pattern that's already here — don't rewrite it. +3. Does the standard library already do this? Use it. +4. Does a native platform feature cover it? Use it. +5. Does an already-installed dependency solve it? Use it. +6. Can this be one line? Make it one line. +7. Only then: write the minimum code that works. + +The ladder runs after you understand the problem, not instead of it: read the task and the code it touches, trace the real flow end to end, then climb. + +**Bug fix = root cause, not symptom.** A report names a symptom. Grep every caller of the function you touch and fix the shared function once — one guard there is a smaller diff than one per caller, and patching only the path the ticket names leaves a sibling caller still broken. + +## Rules + +- No abstractions that weren't explicitly requested. +- No new dependency if it can be avoided. +- No boilerplate nobody asked for. +- Deletion over addition. Boring over clever. Fewest files possible. +- Shortest working diff wins, but only once you understand the problem. +- Question complex requests: "Do you actually need X, or does Y cover it?" +- Pick the edge-case-correct option when two stdlib approaches are the same size — lazy means less code, not the flimsier algorithm. +- Mark intentional simplifications with a `ponytail:` comment. If the shortcut has a known ceiling (global lock, O(n²) scan, naive heuristic), the comment names the ceiling and the upgrade path. + +## Not Lazy About + +- Understanding the problem (read it fully and trace the real flow before picking a rung) +- Input validation at trust boundaries +- Error handling that prevents data loss +- Security +- Accessibility +- Anything explicitly requested + +## Verification + +Non-trivial logic leaves ONE runnable check behind — the smallest thing that fails if the logic breaks (an assert-based self-check or one small test file; no frameworks, no fixtures). Trivial one-liners need no test. diff --git a/.kiro/steering/project-guide.md b/.kiro/steering/project-guide.md new file mode 100644 index 0000000..273ca01 --- /dev/null +++ b/.kiro/steering/project-guide.md @@ -0,0 +1,99 @@ +# 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. Deployed at `archnest.snsnetlabs.com` via Docker Compose on +`racknerd1`. Private Forgejo repo (never public). + +## 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), GitHub Actions → racknerd1 | + +## Git Workflow + +- **Remote**: `origin` → private Forgejo instance (SSH via ProxyJump) +- **Never commit on `main`**. Always create `kiro/` branches. +- **Commit style**: imperative title + body explaining why, with trailers: + ``` + Co-authored-by: Samuel James + Co-authored-by: Kiro + ``` +- **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 ` → `gh pr create` → squash-merge + +## Code Patterns to Follow + +### Frontend +- One page component per route in `src/pages/` +- All backend calls go through `src/lib/api.ts` (typed `apiFetch` wrapper) +- 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 in `api.ts`, sidebar link + +### Backend +- One route file per feature in `backend/src/routes/` +- Integration adapters in `backend/src/integrations/` (must implement `testConnection()`) +- SSH-based features use `backend/src/ssh/connect.ts` shared transport +- Request validation with zod schemas +- Audit logging via `logEvent()` from `db/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 +1. Create adapter in `backend/src/integrations/.ts` +2. Register in `backend/src/integrations/registry.ts` +3. Add type to `IntegrationType` union +4. Add route if needed in `backend/src/routes/` +5. Add `api.ts` functions + TS interfaces on frontend +6. Add card in Settings integrations section + +## Policies + +- **Zero mock data** — every number comes from a live API/SSH/DB call +- **Design-first for big features** — write a `docs/.md` before 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 + +1. `README.md` — architecture overview +2. `HANDOFF.md` — current state + standing rules +3. `design-decisions.md` — visual conventions + per-page implementation notes +4. `ROADMAP.md` — deferred/tiered work +5. `docs/` — 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 linode` → jump host at 172.238.163.85