This project contains specific architecture patterns and development directives. Any AI developer editing this repository must adhere to the rules laid out in this document and agent.md.
- Install packages:
npm install - Local dev server:
npm run dev - Build standalone:
npm run build - Check code quality:
npm run lint - Sync database:
npm run db:push - Start WebSocket / Web Gateway:
npm start(Runs customserver.ts) - Run all tests:
npm test(Vitest — 122 tests across 15 files) - Test watch mode:
npm run test:watch - Test with coverage:
npm run test:coverage - Legacy integration test:
npm run test:integration(Runstest-ssh.ts)
pillar/
├── server.ts # Express.js + Next.js + WebSocket entry
├── next.config.ts # Standalone Next.js config
├── tsconfig.json # TypeScript compilation rules
├── package.json # Dependencies and scripts
├── LICENSE # AGPL-3.0 copyleft license
├── .github/
│ └── FUNDING.yml # Buy Me a Coffee settings
│
├── prisma/
│ ├── schema.prisma # Prisma schema definitions
│ └── dev.db # Local development SQLite file
│
├── src/
│ ├── app/ # App Router files
│ │ ├── layout.tsx # Root layout (theme, font, error handling)
│ │ ├── page.tsx # Entry router (redirects to /dashboard or login)
│ │ ├── globals.css # Theme selectors & variables (NO Tailwind)
│ │ ├── (auth)/ # Auth routes group
│ │ │ ├── login/
│ │ │ └── setup/ # First-run admin creation
│ │ ├── (app)/ # Authenticated client workspace
│ │ │ ├── dashboard/
│ │ │ ├── connections/
│ │ │ │ └── [id]/ # Terminal page
│ │ │ ├── settings/ # Account & Preferences
│ │ │ ├── docs/ # Markdown documentation
│ │ │ └── apidocs/ # Dynamic API specifications
│ │ └── api/ # Protected API routes
│ │
│ ├── components/ # Scoped elements and UI buttons
│ ├── lib/ # Database singletons, crypto, SSH engine
│ └── types/ # TypeScript models
│
└── docs/content/ # Markdown guides for docs portal
- Never write unencrypted credentials: Passwords, private keys, and MFA secrets must pass through
lib/crypto.tsbefore database insertion. - Never log decrypted keys: Mask decrypted strings inside debug output.
- Verify owner scopes: Every connection request must check if
userId === session.user.idor if the record is shared with the current user insideSharedConnection. - Enforce Role Access: Admin features must check
session.user.role === 'ADMIN'. Reject unauthorized edits withHTTP 403 Forbidden.
This project utilizes Next.js CSS Modules (*.module.css) for UI scoping and CSS Custom Properties for theme variables.
- DO NOT write class lists matching Tailwind CSS styles.
- DO NOT install package scripts referencing tailwind.
- If changing theme templates, add custom properties inside
styles/globals.csswith attribute rules like[data-theme="dracula-dark"].
- NEVER run
git tagor call GitHub release APIs autonomously. Bumping version strings in repository documents is encouraged, but committing tags remains the human owner's action.
- Node.js 26 deprecates
url.parse()in favor of the WHATWGnew URL()API. - All WebSocket handlers in
server.tsuse a customparseUrl()helper based onnew URL(). - The Next.js catch-all handler (
expressApp.use((req, res) => handle(req, res, parsedUrl))) must use the deprecatedurl.parse()because Next.js'sgetRequestHandlerexpectsNextUrlWithParsedQuery. - DO NOT replace the
parse()call on the catch-all middleware line — it will break Next.js routing. - The deprecation warning for this single remaining usage is suppressed via import comment.
- Driver adapter required: Prisma v7 removed the built-in SQLite driver. Must install and use
@prisma/adapter-better-sqlite3and pass it tonew PrismaClient({ adapter }). - Generator renamed:
prisma-client-js→prisma-clientwith requiredoutputpath (e.g.,output = "../src/lib/generated/prisma"). urlremoved from schema: The datasourceurlis no longer inschema.prisma. Must configure viaprisma.config.tswithimport 'dotenv/config'andenv('DATABASE_URL').@prisma/clientshim trap: The@prisma/clientnpm package is a shim that doesrequire('.prisma/client/default'). With a customoutputpath, this fails at runtime. Always import from the generated path directly:import { PrismaClient } from './generated/prisma/client'.?connection_limit=1BREAKS v7 adapter: Prisma v6 usedconnection_limit=1in the DATABASE_URL query string. The v7PrismaBetterSqlite3driver adapter interprets query strings as part of the filename, causing "table does not exist" errors. Must strip query params:process.env.DATABASE_URL!.replace(/\?.*$/, '').import.meta.urlin generated CJS output: Prisma v7 generates ESMclient.tsusingimport.meta.url. Whentsccompiles to CJS,import.meta.urlis left verbatim. Node.js v24+ detects this and switches the module to ESM scope, breakingexports. Fix: post-build patch script (scripts/patch-prisma-cjs.mjs) replacesimport.meta.urlwithrequire("url").pathToFileURL(__filename).href.- Next.js SSR env inlining: Turbopack inlines
process.envvalues at build time into SSR chunks. Useenv.DATABASE_URLinnext.config.tsto ensure it reaches SSR bundles. Thedb.tsadapter uses lazy Proxy init so the URL is resolved at first query, not module load time. dotenv/configrequired:import 'dotenv/config'at the top ofdb.tsensures.envis loaded before the adapter is created, covering both the Express server and Next.js SSR paths.
- Next.js/Turbopack caches SSR chunks from previous builds. These chunks can hold stale
DATABASE_URLvalues (e.g.,file:./prisma/dev.dbinstead of the production path). - Always run
rm -rf .next distbeforenpm run buildin deployment scripts. - Failure to do so causes "TableDoesNotExist" errors in production because the cached SSR bundle points to an empty/nonexistent database.
- The root layout does NOT include a
<SessionProvider>. Authentication is handled server-side viaauth()from@/lib/authin server components. - Client components receive user data as props passed down from layouts (e.g.,
Sidebar user={user}). - NEVER call
useSession()fromnext-auth/reactin any page or component — it will returnnulland crash with "Cannot destructure property 'data' from null".
Whenever asked "is docs updated?" or "update docs", you must audit and synchronize these five files/folders:
docs/content/(Guide Markdown files)/apidocsUI & schemasREADME.mdAGENTS.mdplan.md