Skip to main content
Version: Local Β· In Progress

Code Examples

This page shows real patterns extracted from the ThreatWeaver codebase. Use these as templates when building new features.


Example 1: Express Route Handler​

This pattern is taken from backend/src/routes/admin.routes.ts. It demonstrates a typical authenticated, permission-gated route:

// backend/src/routes/admin.routes.ts (actual pattern)
import { Router, Request, Response } from 'express'
import {
authenticate,
requirePermission,
AuthenticatedRequest,
} from '../middleware/auth.js'
import { PERMISSIONS } from '../entities/index.js'
import { settingsService } from '../services/settings.service.js'

const router = Router()

// Apply authentication to ALL routes in this file
router.use(authenticate)

// GET /api/admin/severity-debug
// Requires MANAGE_SETTINGS permission (admin-only)
router.get(
'/severity-debug',
requirePermission(PERMISSIONS.MANAGE_SETTINGS),
async (req: Request, res: Response) => {
try {
// Disable caching for dynamic data
res.setHeader('Cache-Control', 'no-store')

// Call the service layer (never put business logic in routes)
const summary = await settingsService.getSeveritySummary()

res.json(summary)
} catch (err: any) {
res.status(500).json({ error: err.message })
}
}
)

export default router

Key patterns:

  • router.use(authenticate) at the top applies to all routes in the file
  • requirePermission() is added as route-level middleware for admin gates
  • Business logic lives in a service, not in the route handler
  • Cache-Control: no-store for data that should not be cached
  • Try/catch wrapping every async handler
  • Type AuthenticatedRequest gives you req.user with userId, role, tenantId, etc.

Example 2: TypeORM Entity with Relationships​

This pattern is taken from backend/src/entities/User.entity.ts. It demonstrates a full entity with columns, relationships, lifecycle hooks, and instance methods:

// backend/src/entities/User.entity.ts (actual code)
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
BeforeInsert,
BeforeUpdate,
ManyToOne,
} from 'typeorm'
import bcrypt from 'bcryptjs'
import type { Role } from './Role.entity'

export type UserStatus = 'active' | 'inactive' | 'locked' | 'pending_invite' | 'deactivated'

@Entity('users')
export class User {
@PrimaryGeneratedColumn('uuid')
id!: string

@Column({ type: 'varchar', length: 255, unique: true })
email!: string

// select: false -- this column is excluded from default queries
// Must explicitly select it: .addSelect('user.passwordHash')
@Column({ type: 'varchar', length: 255, select: false, nullable: true })
passwordHash!: string | null

@Column({ type: 'varchar', length: 255 })
name!: string

@Column({ type: 'varchar', length: 50, default: 'viewer', nullable: true })
role!: string

// Relationship to Role entity (RBAC v2)
@ManyToOne('Role', (role: Role) => role.users, { nullable: true })
roleDefinition!: Role

@Column({ type: 'varchar', length: 50, default: 'active' })
status!: UserStatus

@Column({ type: 'int', default: 0 })
failedLoginAttempts!: number

@Column({ type: 'timestamp', nullable: true })
lockedUntil!: Date | null

@Column({ type: 'timestamp', nullable: true })
lastLoginAt!: Date | null

@Column({ type: 'boolean', default: false })
twoFactorEnabled!: boolean

@Column({ type: 'varchar', nullable: true, select: false })
twoFactorSecret!: string | null

// SSO fields
@Column({ type: 'varchar', length: 50, nullable: true })
ssoProvider!: string | null // 'microsoft-entra-id' | null

@Column({ type: 'varchar', length: 255, nullable: true })
ssoSubjectId!: string | null // Azure AD Object ID

@Column({ type: 'varchar', length: 50, default: 'credentials' })
loginMethod!: string // 'credentials' | 'sso'

@CreateDateColumn()
createdAt!: Date

@UpdateDateColumn()
updatedAt!: Date

// Lifecycle hook: hash password before insert/update
@BeforeInsert()
@BeforeUpdate()
async hashPassword(): Promise<void> {
if (this.passwordHash && !this.passwordHash.startsWith('$2')) {
this.passwordHash = await bcrypt.hash(this.passwordHash, 12)
}
}

// Instance method: verify password
async verifyPassword(password: string): Promise<boolean> {
if (!this.passwordHash) return false
return bcrypt.compare(password, this.passwordHash)
}

// Instance method: check account lockout
isLocked(): boolean {
if (!this.lockedUntil) return false
return new Date() < this.lockedUntil
}

// Instance method: lock after failed attempts
incrementFailedAttempts(): void {
this.failedLoginAttempts++
if (this.failedLoginAttempts >= 5) {
this.lockedUntil = new Date(Date.now() + 15 * 60 * 1000)
this.status = 'locked'
}
}

// Instance method: reset on successful login
resetFailedAttempts(): void {
this.failedLoginAttempts = 0
this.lockedUntil = null
if (this.status === 'locked') {
this.status = 'active'
}
}

// Instance method: record login metadata
recordLogin(ip: string): void {
this.lastLoginAt = new Date()
this.lastLoginIp = ip
this.resetFailedAttempts()
}
}

Key patterns:

  • PrimaryGeneratedColumn('uuid') -- UUIDs for all primary keys
  • select: false on sensitive fields (password hashes, secrets)
  • @BeforeInsert() / @BeforeUpdate() for automatic password hashing (bcrypt cost 12)
  • Instance methods for domain logic (lockout, password verification)
  • ! definite assignment assertions on all fields (required by TypeORM + strict TypeScript)
  • Nullable columns use Type | null union types

Example 3: Service with Tenant-Aware Repository​

This pattern shows how services access the database in a multi-tenant-safe way:

// backend/src/services/myFeature.service.ts (pattern from codebase)
import { getTenantAwareRepository } from '../multi-tenant/tenant-local-storage.js'
import { MyEntity } from '../entities/index.js'
import { ILike } from 'typeorm'

class MyFeatureService {
/**
* Get all items for the current tenant.
* getTenantAwareRepository automatically resolves the correct schema.
*/
async getAll(filters?: { search?: string; status?: string }): Promise<MyEntity[]> {
const repo = getTenantAwareRepository(MyEntity)

const where: any = {}
if (filters?.search) {
where.name = ILike(`%${filters.search}%`)
}
if (filters?.status) {
where.status = filters.status
}

return repo.find({
where,
order: { createdAt: 'DESC' },
})
}

/**
* Get a single item by ID.
*/
async getById(id: string): Promise<MyEntity | null> {
const repo = getTenantAwareRepository(MyEntity)
return repo.findOne({ where: { id } })
}

/**
* Create a new item.
*/
async create(data: Partial<MyEntity>): Promise<MyEntity> {
const repo = getTenantAwareRepository(MyEntity)
const entity = repo.create(data)
return repo.save(entity)
}

/**
* Update an existing item.
* Returns null if not found.
*/
async update(id: string, data: Partial<MyEntity>): Promise<MyEntity | null> {
const repo = getTenantAwareRepository(MyEntity)
const existing = await repo.findOne({ where: { id } })
if (!existing) return null

Object.assign(existing, data)
return repo.save(existing)
}

/**
* Delete an item by ID.
*/
async delete(id: string): Promise<boolean> {
const repo = getTenantAwareRepository(MyEntity)
const result = await repo.delete(id)
return (result.affected ?? 0) > 0
}
}

// Singleton export
export const myFeatureService = new MyFeatureService()

Key patterns:

  • Always call getTenantAwareRepository() inside the method, not as a class-level field. The tenant context is request-scoped (via AsyncLocalStorage), so the repository must be resolved per-call.
  • Singleton export at the bottom (export const myFeatureService = new MyFeatureService())
  • Services never import Request or Response -- they are framework-agnostic
  • Use TypeORM operators like ILike for search queries

Example 4: Route with Zod Validation​

This pattern is taken from backend/src/routes/dashboard.routes.ts, showing request body validation:

// backend/src/routes/dashboard.routes.ts (actual pattern)
import { z } from 'zod'

const ALLOWED_DATA_SOURCES = [
'vulnerabilities', 'assets', 'risk_scores', 'compliance',
'remediation', 'sla', 'trends', 'appsec',
] as const

const ALLOWED_CHART_TYPES = [
'kpi', 'bar', 'line', 'doughnut', 'gauge', 'table',
'matrix', 'stacked_bar', 'area', 'pie', 'number',
] as const

const widgetDataSchema = z.object({
dataSource: z.enum(ALLOWED_DATA_SOURCES),
chartType: z.enum(ALLOWED_CHART_TYPES).optional(),
groupBy: z.string().max(50).optional(),
groupBySecondary: z.string().max(50).optional(),
filters: z.record(z.string(), z.unknown()).optional(),
sort: z.object({
field: z.string().max(50),
order: z.enum(['ASC', 'DESC']),
}).optional(),
limit: z.number().int().min(1).max(1000).optional(),
metric: z.string().max(50).optional(),
days: z.number().int().min(1).max(730).optional(),
}).passthrough()

// Usage in a route handler:
router.post('/widget-data', async (req: AuthenticatedRequest, res: Response) => {
try {
const parsed = widgetDataSchema.parse(req.body)
// Use parsed.dataSource, parsed.chartType, etc.
// ...
} catch (err: any) {
if (err instanceof z.ZodError) {
return res.status(400).json({
error: 'Validation failed',
details: err.errors,
})
}
res.status(500).json({ error: err.message })
}
})

Key patterns:

  • Define allowed values as as const arrays for type-safe enums
  • Use z.enum() for whitelisting -- prevents injection through unvalidated input
  • .max(50) on string fields to prevent oversized inputs
  • .passthrough() to allow additional fields without failing validation
  • Catch ZodError specifically and return structured error details

Example 5: Rate Limiter Configuration​

This pattern is from backend/src/routes/scan.routes.ts, showing per-route rate limiting:

// backend/src/routes/scan.routes.ts (actual code)
import rateLimit from 'express-rate-limit'

// Per-user rate limiter for scan launches
const scanLaunchLimiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 10, // 10 launches per minute per user
keyGenerator: (req: any) => req.user?.userId || 'anon',
message: { error: 'Too many scan launches. Maximum 10 per minute.' },
standardHeaders: true,
legacyHeaders: false,
validate: { xForwardedForHeader: false, default: true },
})

const bulkOperationLimiter = rateLimit({
windowMs: 60 * 1000,
max: 5, // 5 bulk operations per minute per user
keyGenerator: (req: any) => req.user?.userId || 'anon',
message: { error: 'Too many bulk operations. Maximum 5 per minute.' },
standardHeaders: true,
legacyHeaders: false,
validate: { xForwardedForHeader: false, default: true },
})

// Apply to specific routes
router.post('/launch', scanLaunchLimiter, async (req, res) => { ... })
router.post('/bulk-action', bulkOperationLimiter, async (req, res) => { ... })

Key patterns:

  • keyGenerator uses req.user?.userId for per-user limiting (not per-IP)
  • validate: { xForwardedForHeader: false } to avoid warnings behind reverse proxies
  • Different limits for different operation types (reads vs. writes vs. bulk)
  • JSON error messages for API consumers

Example 6: Scanner Agent (Attack Agent Pattern)​

This pattern is from the actual agent architecture in backend/src/services/appsec/agents/:

// backend/src/services/appsec/agents/myAgent.agent.ts (pattern)
import {
BaseAttackAgent,
AgentFinding,
} from './baseAttackAgent.js'
import type { SharedBlackboard } from '../sharedBlackboard.service.js'
import type { PentestAiAdapter } from '../pentestAiAdapter.service.js'
import type { ScannerPolicy } from '../scannerConstants.js'

class MyVulnAgent extends BaseAttackAgent {
constructor() {
super()
this.agentName = 'my_vuln_agent'
}

async run(
blackboard: SharedBlackboard,
aiAdapter: PentestAiAdapter,
policy: ScannerPolicy,
): Promise<AgentFinding[]> {
const findings: AgentFinding[] = []
const endpoints = blackboard.getEndpoints()

for (const ep of endpoints) {
// Budget check -- stop if we've used our allocation
if (this.isOverBudget()) break

// Skip endpoints outside scope
if (!this.isInScope(ep.url, policy)) continue

// Send a probe request
const response = await this.probe({
url: ep.url,
method: ep.method,
headers: this.getDefaultHeaders(),
})

// Classify the response (WAF blocked? Error? Success?)
const classification = this.classifyResponse(response)

if (classification.isWafBlocked) continue
if (classification.isRateLimited) {
await this.backoff(classification.retryAfter)
continue
}

// Analyze for vulnerability indicators
// ... your detection logic ...

// Record finding if vulnerability confirmed
findings.push({
type: 'my_vuln_type',
severity: 'high',
title: 'Vulnerability Detected',
description: 'Description of the vulnerability...',
endpoint: ep.url,
method: ep.method,
parameter: 'paramName',
payload: 'test-payload',
evidence: {
request: response.requestDetails,
response: response.body.substring(0, 500),
proofType: 'deterministic',
},
confidence: 0.85,
cweId: 'CWE-79',
owaspCategory: 'A03:2021',
remediation: 'How to fix this vulnerability...',
})
}

return findings
}
}

export const myVulnAgent = new MyVulnAgent()

Key patterns:

  • Extend BaseAttackAgent and implement run()
  • Use this.isOverBudget() to respect resource limits
  • Use this.classifyResponse() to detect WAF blocks and rate limiting
  • Return AgentFinding[] with structured evidence
  • Singleton export matches the coordinator's import pattern

Example 7: Multi-Tenant Aware Query​

This pattern shows how to use raw SQL queries in a tenant-aware context:

// Using getTenantAwareQuery for raw SQL
import {
getTenantAwareRepository,
getTenantAwareQuery,
} from '../multi-tenant/tenant-local-storage.js'

// Repository approach (preferred for CRUD)
async function getUserCount(): Promise<number> {
const repo = getTenantAwareRepository(User)
return repo.count()
}

// Raw query approach (for complex aggregations)
async function getVulnStats(): Promise<any> {
const query = getTenantAwareQuery()
const results = await query(
`SELECT severity, COUNT(*) as count
FROM vulnerabilities
WHERE status = $1
GROUP BY severity`,
['open']
)
return results
}

Key patterns:

  • getTenantAwareRepository() for standard TypeORM operations
  • getTenantAwareQuery() for raw SQL -- the returned function automatically uses the tenant-scoped EntityManager (which has search_path set to the correct schema)
  • Both fall back to AppDataSource when called outside a tenant request context (background jobs, startup)

Project File Structure Reference​

backend/
src/
config/ # env.ts, database.ts, redis.ts
entities/ # TypeORM entities (100+ files)
middleware/ # auth.ts, validation.ts, moduleGate.ts
multi-tenant/ # schema-manager.ts, tenant-local-storage.ts
routes/ # Express route files (40+ files)
services/ # Business logic services
appsec/ # AppSec scanner module
agents/ # 56+ attack agents
scripts/ # Migration scripts
utils/ # Utility functions
types/ # TypeScript type definitions
index.ts # Application entry point

frontend/
src/
components/ # Reusable UI components
pages/ # Page-level components
services/ # API client functions
stores/ # Zustand state stores
hooks/ # Custom React hooks
App.tsx # Route definitions