- Node.js: v26.3.0. Avoid outdated packages or packages deprecated in modern Node.js runtimes.
- Database: SQLite (managed by Prisma ORM v7 with
@prisma/adapter-better-sqlite3). Noconnection_limitquery param needed — the adapter handles pooling internally.
- NEVER use Tailwind utility classes (e.g.,
flex,p-4,text-sm,bg-blue-500) in any component or layout. - NEVER install
tailwindcss,@tailwindcss/postcss, or other tailwind dependencies. - CSS Modules only: Use scoped CSS files (
*.module.css) placed alongside components (e.g.Sidebar.tsxandSidebar.module.css). - CSS Custom Properties: Theme variables and layout globals are declared exclusively in
styles/globals.css. - Theme Selection: Toggle the
data-themeattribute on the<html>node (e.g.<html data-theme="dracula-dark">). Never inject Tailwind dynamic classes for themes.
- Sensitive columns:
passwordHash,mfaSecret,password(SSH profile),privateKey(SSH profile),passphrase(SSH profile). - NEVER store these fields in plaintext.
- Encrypt utilizing AES-256-GCM backed by
process.env.ENCRYPTION_KEY(minimum 32-byte hexadecimal key). - Read the Connection profile from the DB and decrypt credentials at connection time only. Never hold decrypted secrets in persistent global state or logs.
- NextAuth.js v5 JWT Strategy. Include claims
role(ADMINorUSER) andmfaEnabledinside the session token. - Secure route validation via
middleware.ts. Intercept unauthenticated users, routing to/loginor/setup. - Admin endpoints (
/api/admin/*) and pages/admin/*must strictly verifysession.user.role === 'ADMIN'. Return HTTP 403 on failure.
- Limit avatar image files to
image/png,image/jpeg, orimage/webp. Limit file sizes to 2MB maximum. - Save avatar images to local storage (
/data/uploads/avatarsorpublic/uploads/avatars). - Filename cache-busting: Store using
{userId}_{timestamp}.{ext}format. Never save with static filenames since browsers aggressively cache image URLs.
- Auth endpoints: Max 30 attempts per minute.
- Upload endpoints: Max 10 attempts per minute.
- Use a lightweight, in-memory sliding window rate-limiter.
- Always
awaitNext.js server-side parameters/headers:paramssearchParamscookies()headers()
- Standard syntax in routes/pages:
export default async function Page({ params }: { params: Promise<{ id: string }> }) { const { id } = await params; // ... }
All REST API routes must match these JSON models:
- Single resource:
{ data: { ... } }or{ connection: { ... } } - Lists:
{ data: [ ... ] }or{ connections: [ ... ] } - Paginated:
{ data: [ ... ], total: number, page: number, limit: number } - Error:
{ error: "Error details" }
- Prisma v7 requires a driver adapter. Use
@prisma/adapter-better-sqlite3and pass it tonew PrismaClient({ adapter }). - Cache your Prisma client on
globalThisto avoid SQLite locking during HMR in development. Production uses lazy Proxy init:import 'dotenv/config'; import { PrismaClient } from './generated/prisma/client'; let _db: PrismaClient | undefined; export const db = new Proxy({} as PrismaClient, { get(_, prop) { const client = _db ?? (_db = (() => { const { PrismaBetterSqlite3 } = require('@prisma/adapter-better-sqlite3'); return new PrismaClient({ adapter: new PrismaBetterSqlite3({ url: process.env.DATABASE_URL!.replace(/\?.*$/, '') }) }); })()); return typeof client[prop] === 'function' ? client[prop].bind(client) : client[prop]; }, });
- After successful auth or setup, execute a
window.location.href = "/dashboard"instead of client-siderouter.push(). Standard React Router navigations skip transmitting the updated HTTP-only cookie headers on immediate next fetches.
- Suppress runtime extension error overlays in the root layout's
useEffect(e.g. suppression ofmoz-extension://orchrome-extension://warnings).
When updating the app version (starting at 0.1.0 SemVer):
package.json—"version"AGENTS.md— overview block version- Settings page — Info footer display
- README.md — badges & logs
plan.md— title current indicatorCHANGELOG.md— add clean dated release log- Rule: NEVER perform
git tagor trigger GitHub release actions. Only the human owner creates tags or releases.