Skip to main content
Home / Portfolio / SecSuite
Security Tooling

SecSuite

Security consultant platform — 10 modules

Built by Rogue AI · One platform for the whole consultant lifecycle · Self-hosted

Built solo as a portfolio project, iterated module by module.

SecSuite — Security consultant platform — 10 modules

The problem

An independent security consultant runs the same workflow on every engagement — scope the work, track findings, manage evidence, write the report, raise the invoice — but the tooling is scattered across spreadsheets, note files, and disconnected SaaS subscriptions. Each tool owns a slice of the data, nothing shares a client record, and the same finding gets retyped three times before it reaches a deliverable. SecSuite is one platform that holds the entire lifecycle behind a single login, so a client, an engagement, its findings, the evidence, and the resulting report and invoice all reference the same rows.

What I built

A single Next.js 16 / React 19 application backed by one PostgreSQL database. The schema is large — 47 Prisma models — because the consultant lifecycle genuinely has that many entities: clients, engagements, findings, evidence, recon targets, phishing campaigns, compliance assessments, proposals, invoices, time entries. Ten modules sit on top of that schema, each owning a slice of the workflow but reading and writing the same shared records. Auth is a custom HS256 JWT (jose) in an httpOnly cookie rather than NextAuth, which keeps the session model small and explicit and avoids pulling a framework's opinions into a single-operator tool.

Architecture

Ten lifecycle modules, one schema
Engagement management, findings + reports, recon, phishing simulation, compliance tracking, AI security testing, attack-surface monitoring, a knowledge base, proposals/SOWs, and invoicing + time. They aren't separate apps — they are views over one Prisma schema, so a finding raised during an engagement flows into the report and the proposal without copy-paste.
47 Prisma models on Prisma 7 + Postgres
The data model is the real surface area of the platform. Prisma 7 requires the PrismaPg adapter and a prisma.config.ts (no url in the datasource block), and every PrismaClient routes through it. The app DB user is least-privilege, not the postgres superuser.
Custom JWT auth, not NextAuth
A secsuite_session httpOnly cookie carries a 24-hour HS256 token signed with jose; bcryptjs at cost 12 for password hashing. Middleware validates the token, sets an x-user-id header for API routes, and enforces an Origin check (CSRF) on every mutating request. Page routes redirect to /login; API routes return 401 JSON.
Per-client RAG over a shared knowledge service
Each client's documentation is indexed for retrieval through a shared knowledge service (a Qdrant vector store reached via a local bridge), so answers and drafts are grounded in that client's own material rather than the whole corpus. Collections are namespaced per client to keep one engagement's context out of another's.
Local-first LLM with a provider switch
LLM calls default to a local Ollama model and can flip to a hosted model via a single LLM_PROVIDER env var routed through a local bridge. Defaulting to local keeps client material on the machine and the tool usable offline; the switch exists for when a heavier model is worth it.
Isolated, hardened Docker deployment
App, Postgres, Redis, and a separate egress-only scanner worker run on a dedicated bridge network, all ports bound to 127.0.0.1. Containers drop all capabilities, run no-new-privileges with a read-only root filesystem and tmpfs scratch, and pin base images by digest. The active-scan worker holds no inbound ports and is gated by an explicit in-scope authorization check before it touches a target.

Tech stack

Next.jsPrisma 7PostgreSQLOllamaCustom JWT

What broke first

  • A wide schema is honest, not bloat — the consultant lifecycle really has dozens of distinct entities, and forcing them through one shared data model is what removes the retyping that scattered tools cause.

  • Custom JWT was the right call for a single-operator tool: a small, explicit session model is easier to reason about and harden than wiring a full auth framework I'd only use one path of.

  • Per-client RAG namespacing matters more than retrieval quality at this scale — keeping one client's context from bleeding into another's is the part you cannot get wrong.

Outcome

The result is one application where a client record, its engagements, findings, evidence, reports, and invoices share the same rows, with per-client RAG grounding any AI assistance in that client's own material — running entirely on self-hosted infrastructure with local-first LLM inference.

Honest limits

This is a self-hosted, single-operator tool built solo as a portfolio project, not a multi-tenant SaaS. It runs in a local Docker lab; the old VPS it once targeted has been retired. There is no team behind it, no hosted offering, and no uptime claim — it demonstrates how the full consultant lifecycle can live behind one schema and one login, and the AI features are only as good as the local model and the documents fed into them.

Related reading

← Back to portfolio