Internal
Developer Guide
Complete guide for developers: setup, architecture, testing, and deployment.
InsiderShield Developer Guide
Complete guide for developers working on the InsiderShield codebase.
Table of Contents
- Development Setup
- Project Structure
- Tech Stack
- Development Workflow
- Testing
- Database
- API Development
- Authentication
- Integrations
- Deployment
- Troubleshooting
Development Setup
Prerequisites
- Node.js 20+ (LTS recommended)
- pnpm 10+ (
npm install -g pnpm) - Git
- Supabase CLI (
brew install supabase/tap/supabase) - Docker (for local Supabase)
Initial Setup
# Clone repository
git clone https://github.com/yourusername/insidershield.git
cd insidershield
# Install dependencies
pnpm install
# Copy environment variables
cp .env.production.example .env.local
# Generate secure secrets
openssl rand -base64 32 # Use for OAUTH_STATE_SECRET
openssl rand -base64 32 # Use for INTEGRATIONS_ENCRYPTION_KEY
openssl rand -hex 32 # Use for WEBHOOK_SECRET
# Start Supabase locally (optional)
supabase start
# Run database migrations
supabase migration up
# Start development server
pnpm dev
Visit http://localhost:3000
Required Environment Variables
Create .env.local with these required variables:
# Supabase
NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
# Security
OAUTH_STATE_SECRET=your_oauth_secret_32_chars_min
WEBHOOK_SECRET=your_webhook_secret
INTEGRATIONS_ENCRYPTION_KEY=your_encryption_key_32_chars
# App URLs
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_SITE_URL=http://localhost:3000
# Stripe (for billing)
STRIPE_SECRET_KEY=sk_test_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
# OAuth Providers
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
GITHUB_CLIENT_ID=your_github_client_id
GITHUB_CLIENT_SECRET=your_github_client_secret
SLACK_CLIENT_ID=your_slack_client_id
SLACK_CLIENT_SECRET=your_slack_client_secret
# Email (Resend)
RESEND_API_KEY=re_...
RESEND_FROM_EMAIL=noreply@insidershield.io
# Optional
OPENROUTER_API_KEY=your_openrouter_key # For AI features
SENTRY_DSN=your_sentry_dsn # For error tracking
CRON_SECRET=your_cron_secret # For scheduled jobs
Project Structure
insidershield/
├── app/ # Next.js App Router
│ ├── api/ # API routes
│ │ ├── ai/ # AI chat endpoints
│ │ ├── auth/ # Authentication
│ │ ├── controls/ # Control management
│ │ ├── integrations/ # Integration OAuth & webhooks
│ │ ├── policies/ # Policy management
│ │ ├── reports/ # Report generation
│ │ └── webhooks/ # Incoming webhooks
│ ├── auth/ # Auth pages
│ ├── dashboard/ # Protected dashboard routes
│ ├── docs/ # Documentation pages
│ └── layout.tsx # Root layout
├── components/ # React components
│ ├── ui/ # Shadcn/UI primitives
│ ├── dashboard/ # Dashboard-specific components
│ ├── billing/ # Billing components
│ └── site/ # Marketing site components
├── lib/ # Business logic & utilities
│ ├── data/ # Data access layer (Server Actions)
│ │ ├── actions.ts # Generic actions
│ │ ├── *-actions.ts # Domain-specific actions
│ │ ├── queries.ts # Database queries
│ │ └── plan-guard.ts # Plan-based access control
│ ├── supabase/ # Database clients
│ │ ├── client.ts # Client-side
│ │ ├── server.ts # Server-side
│ │ ├── admin.ts # Admin client
│ │ └── database.types.ts # Generated types
│ ├── integrations/ # Third-party integrations
│ │ ├── github/ # GitHub integration
│ │ ├── google-workspace/ # Google integration
│ │ └── slack/ # Slack integration
│ ├── security/ # Security utilities
│ │ ├── csrf.ts # CSRF protection
│ │ ├── oauth-state.ts # OAuth state management
│ │ └── rate-limit.ts # Rate limiting
│ ├── frameworks/ # Compliance frameworks
│ ├── email/ # Email service
│ └── config/ # Configuration
├── e2e/ # End-to-end tests
├── docs/ # Documentation (markdown)
├── public/ # Static assets
├── supabase/ # Supabase config
│ ├── migrations/ # SQL migrations
│ └── config.toml # Supabase configuration
├── jest.config.js # Jest configuration
├── playwright.config.ts # Playwright configuration
├── next.config.mjs # Next.js configuration
├── tsconfig.json # TypeScript configuration
└── package.json # Dependencies
Tech Stack
Frontend
- Next.js 16 - React framework with App Router
- React 19 - UI library
- TypeScript 5 - Type safety
- Tailwind CSS 4 - Styling
- Shadcn/UI - Component library
- Radix UI - Headless components
- Lucide - Icons
- Recharts - Charts
- React Hook Form - Form management
- Zod - Schema validation
Backend
- Next.js API Routes - RESTful API
- Supabase - PostgreSQL + Auth + Storage
- Stripe - Payment processing
- Resend - Email delivery
Development
- Jest - Unit testing
- Playwright - E2E testing
- ESLint - Linting
- Prettier - Code formatting
- Husky - Git hooks
- TypeScript - Type checking
Deployment
- Vercel - Hosting
- Supabase - Database hosting
- GitHub Actions - CI/CD
Development Workflow
Branch Strategy
main- Production branch (protected)develop- Development branchfeature/*- Feature branchesfix/*- Bug fix brancheshotfix/*- Production hotfixes
Making Changes
# Create feature branch
git checkout -b feature/my-feature
# Make changes
# Write tests
# Run tests
pnpm test
# Lint and format
pnpm lint:fix
pnpm format
# Commit (triggers pre-commit hooks)
git add .
git commit -m "feat: add my feature"
# Push and create PR
git push origin feature/my-feature
Commit Message Format
Follow Conventional Commits:
type(scope): description
[optional body]
[optional footer]
Types:
feat: New featurefix: Bug fixdocs: Documentationstyle: Formattingrefactor: Code restructuringtest: Adding testschore: Maintenance
Examples:
feat(integrations): add Slack OAuth flow
fix(auth): resolve login redirect loop
docs(api): document webhook endpoints
test(security): add CSRF validation tests
Testing
Unit Tests (Jest)
# Run all tests
pnpm test
# Run with coverage
pnpm test:coverage
# Watch mode
pnpm test:watch
# Run specific test file
pnpm test oauth-state.test.ts
Writing Tests:
// lib/security/__tests__/example.test.ts
import { describe, it, expect } from '@jest/globals'
import { myFunction } from '../example'
describe('myFunction', () => {
it('should return expected value', () => {
const result = myFunction('input')
expect(result).toBe('expected')
})
it('should handle edge cases', () => {
expect(() => myFunction('')).toThrow()
})
})
E2E Tests (Playwright)
# Run E2E tests
pnpm test:e2e
# Run with UI
pnpm test:e2e:ui
# Run specific test
pnpm test:e2e auth.spec.ts
# Debug mode
pnpm test:e2e --debug
Writing E2E Tests:
// e2e/example.spec.ts
import { test, expect } from '@playwright/test'
test('user can complete signup flow', async ({ page }) => {
await page.goto('/auth/signup')
await page.getByLabel('Email').fill('test@example.com')
await page.getByLabel('Password').fill('SecurePass123!')
await page.getByRole('button', { name: 'Sign Up' }).click()
await expect(page).toHaveURL('/dashboard')
})
Test Coverage Goals
- Overall: 60%+
- Critical paths: 80%+ (auth, payments, security)
- API routes: 70%+
- Components: 60%+
Database
Supabase Architecture
- PostgreSQL 14+ - Relational database
- Row Level Security (RLS) - Data access control
- Auth - User authentication
- Storage - File storage (policies, reports, evidence)
- Realtime - WebSocket subscriptions
Key Tables
-- Organizations
organizations (id, name, industry, framework, created_at)
-- Users & Membership
organization_members (organization_id, user_id, role)
-- Compliance
controls (id, organization_id, number, title, status, framework)
findings (id, organization_id, severity, status, integration_type)
policies (id, organization_id, type, file_path, status)
-- Integrations
integrations (id, organization_id, type, credentials, status)
-- Billing
subscriptions (organization_id, plan, stripe_subscription_id)
-- Activity
activities (organization_id, user_id, type, message, metadata)
Migrations
# Create migration
supabase migration new add_new_table
# Run migrations
supabase migration up
# Reset database (development only!)
supabase db reset
# Generate TypeScript types
supabase gen types typescript --local > lib/supabase/database.types.ts
Data Access Pattern
Use Server Actions for data access:
// lib/data/example-actions.ts
'use server'
import { createClient } from '@/lib/supabase/server'
export async function getMyData() {
const supabase = await createClient()
const {
data: { user },
} = await supabase.auth.getUser()
if (!user) return { error: 'Unauthorized' }
const { data, error } = await supabase.from('my_table').select('*').eq('user_id', user.id)
if (error) return { error: error.message }
return { data }
}
API Development
Creating API Routes
// app/api/example/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { createClient } from '@/lib/supabase/server'
import { validateCsrf } from '@/lib/security/csrf'
export async function POST(request: NextRequest) {
// 1. CSRF validation for state-changing requests
if (!validateCsrf(request)) {
return NextResponse.json({ error: 'Invalid CSRF token' }, { status: 403 })
}
// 2. Authentication
const supabase = await createClient()
const {
data: { user },
} = await supabase.auth.getUser()
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
// 3. Parse request body
const body = await request.json()
// 4. Validate input
// Use Zod schema for validation
// 5. Business logic
// ...
// 6. Return response
return NextResponse.json({ success: true })
}
API Security Checklist
- ✅ CSRF validation on POST/PUT/DELETE
- ✅ Authentication check
- ✅ Authorization (RLS or manual check)
- ✅ Input validation (Zod schemas)
- ✅ Rate limiting
- ✅ Error handling (don't leak sensitive info)
- ✅ Logging (for debugging)
Rate Limiting
import { rateLimit } from '@/lib/security/rate-limit'
export async function POST(request: NextRequest) {
// Apply rate limit
const { success, limit, remaining } = await rateLimit(request)
if (!success) {
return NextResponse.json({ error: 'Too many requests' }, { status: 429 })
}
// Continue with request...
}
Authentication
Supabase Auth Flow
- Client-side: User signs up/in
- Cookie: Session stored in httpOnly cookie
- Server-side: Validate session on each request
- RLS: Database enforces row-level security
Checking Authentication
// Server Component
import { createClient } from '@/lib/supabase/server'
export default async function ProtectedPage() {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) redirect('/auth/login')
return <div>Protected content</div>
}
// Client Component
'use client'
import { createClient } from '@/lib/supabase/client'
import { useEffect, useState } from 'react'
export function ProtectedComponent() {
const [user, setUser] = useState(null)
const supabase = createClient()
useEffect(() => {
supabase.auth.getUser().then(({ data: { user } }) => {
setUser(user)
})
}, [])
if (!user) return <div>Loading...</div>
return <div>Protected content</div>
}
Integrations
Creating New Integration
- Define OAuth Flow
// lib/integrations/my-service/client.ts
export class MyServiceClient {
private accessToken: string
constructor(accessToken: string) {
this.accessToken = accessToken
}
async getData() {
const response = await fetch('https://api.myservice.com/data', {
headers: {
Authorization: `Bearer ${this.accessToken}`,
},
})
return response.json()
}
}
- Add OAuth Routes
// app/api/integrations/my-service/connect/route.ts
export async function GET(request: NextRequest) {
// 1. Create OAuth state
const state = createOAuthState({
provider: 'my-service',
organization_id: orgId,
user_id: userId,
})
// 2. Redirect to OAuth provider
const authUrl = new URL('https://myservice.com/oauth/authorize')
authUrl.searchParams.set('client_id', process.env.MY_SERVICE_CLIENT_ID!)
authUrl.searchParams.set('redirect_uri', callbackUrl)
authUrl.searchParams.set('state', state)
authUrl.searchParams.set('scope', 'read:data')
return NextResponse.redirect(authUrl.toString())
}
- Add Callback Route
// app/api/integrations/my-service/callback/route.ts
export async function GET(request: NextRequest) {
// 1. Verify OAuth state
const state = searchParams.get('state')
const verified = verifyOAuthState(state, 'my-service')
if (!verified) {
return NextResponse.redirect('/dashboard/integrations?error=invalid_state')
}
// 2. Exchange code for token
const code = searchParams.get('code')
const tokenResponse = await fetch('https://myservice.com/oauth/token', {
method: 'POST',
body: JSON.stringify({
client_id: process.env.MY_SERVICE_CLIENT_ID,
client_secret: process.env.MY_SERVICE_CLIENT_SECRET,
code,
grant_type: 'authorization_code',
}),
})
const { access_token } = await tokenResponse.json()
// 3. Store encrypted credentials
const encrypted = await encryptToken(access_token)
await supabase.from('integrations').insert({
organization_id: verified.organization_id,
type: 'my-service',
credentials: encrypted,
status: 'active',
})
return NextResponse.redirect('/dashboard/integrations?success=true')
}
- Add Scanner
// lib/integrations/my-service/scanner.ts
export async function scanMyService(integrationId: string, orgId: string) {
// 1. Get integration credentials
const integration = await getIntegration(integrationId)
const accessToken = await decryptToken(integration.credentials)
// 2. Initialize client
const client = new MyServiceClient(accessToken)
// 3. Run security checks
const findings = []
const data = await client.getData()
if (data.securityIssue) {
findings.push({
organization_id: orgId,
integration_type: 'my-service',
severity: 'high',
title: 'Security Issue Detected',
description: 'Description of issue',
remediation: 'How to fix',
})
}
// 4. Save findings
await saveFindings(findings)
return { findingsCount: findings.length }
}
Deployment
Vercel Deployment
# Install Vercel CLI
npm i -g vercel
# Deploy to preview
vercel
# Deploy to production
vercel --prod
Environment Variables
Set in Vercel dashboard:
- Project Settings → Environment Variables
- Add all variables from
.env.local - Set for Production, Preview, Development
Cron Jobs
Defined in vercel.json:
{
"crons": [
{
"path": "/api/cron/sync-integrations",
"schedule": "0 1 * * *"
},
{
"path": "/api/cron/process-notifications",
"schedule": "30 1 * * *"
}
]
}
Database Migrations
# Production migrations (via Supabase dashboard)
1. Go to Supabase project → SQL Editor
2. Run migration SQL
3. Verify with test queries
# Or use CLI
supabase db push
Troubleshooting
Common Issues
Build Fails with TypeScript Errors
# Clear cache and rebuild
rm -rf .next
pnpm build
Database Connection Issues
# Check Supabase status
supabase status
# Restart local Supabase
supabase stop
supabase start
OAuth Redirect Not Working
- Verify OAuth callback URL in provider settings
- Check
NEXT_PUBLIC_APP_URLenvironment variable - Ensure HTTPS in production
Tests Failing
# Clear Jest cache
pnpm jest --clearCache
# Run tests with verbose output
pnpm test --verbose
Debug Mode
# Next.js debug mode
NODE_OPTIONS='--inspect' pnpm dev
# Verbose logging
DEBUG=* pnpm dev
Getting Help
- Internal Docs: Check
/docsdirectory - Slack: #engineering channel
- GitHub Issues: Create issue with bug label
- Pair Programming: Ask in team chat
Happy coding! 🚀