ποΈ Simplified MVP Architecture¶
Overview¶
GetCimple MVP uses deterministic, rule-based processing instead of AI orchestration. Sophistication comes from data structure and presentation, not machine learning.
Core Principle¶
"Simple internal processes, sophisticated customer features"
- Structured data model enables powerful reporting
- Rule-based logic is transparent and auditable
- Professional presentation delivers board-ready value
Tech Stack¶
Frontend¶
- Framework: React 19 + Vite
- UI Components: shadcn/ui (Radix UI + Tailwind)
- State Management: TanStack Query + React Context
- Forms: React Hook Form + Zod validation
- Routing: React Router v7
- Deployment: Cloudflare Pages
Backend¶
- Database: Supabase (PostgreSQL)
- Authentication: Kinde Auth
- Storage: Supabase Storage
- Edge Functions: Cloudflare Workers
- Background Jobs: Simple cron triggers
Reporting & Documents¶
- PDF Generation: WeasyPrint (Python) or Puppeteer (Node.js)
- Text Extraction: pdf-parse, mammoth.js (non-AI)
- Charts: Chart.js or similar
Infrastructure¶
- Hosting: Cloudflare (edge deployment)
- Monitoring: Built-in Cloudflare analytics
- Email: Resend or similar transactional service
- WhatsApp: Twilio
Data Model¶
COMPANIES ββ< POLICIES ββ< CONTROLS ββ< TASKS ββ< EVIDENCE
β β
βββββββββββββββ< USERS >ββββββββββββββββ
Relationships:
- One company has many policies
- One policy contains many controls
- One control generates many tasks
- One task requires many evidence items
- One company has many users
- One user is assigned many tasks
Key Tables¶
-- Companies (Multi-tenant)
CREATE TABLE companies (
id UUID PRIMARY KEY,
name TEXT NOT NULL,
domain TEXT UNIQUE,
logo_url TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
-- Policies (Version tracked)
CREATE TABLE policies (
id UUID PRIMARY KEY,
company_id UUID REFERENCES companies(id),
policy_name TEXT NOT NULL,
category TEXT NOT NULL, -- 'Access Control', 'Data Protection', etc.
status TEXT CHECK (status IN ('active', 'draft', 'archived')),
version INT DEFAULT 1,
approved_at TIMESTAMP,
approved_by UUID REFERENCES users(id)
);
-- Controls (Framework mappings)
CREATE TABLE controls (
id UUID PRIMARY KEY,
policy_id UUID REFERENCES policies(id),
control_name TEXT NOT NULL,
description TEXT,
framework_mappings JSONB, -- {'e8': 'ML-1', 'nist': 'AC-2'}
criticality TEXT CHECK (criticality IN ('critical', 'high', 'medium', 'low'))
);
-- Tasks (Audit trail)
CREATE TABLE tasks (
id UUID PRIMARY KEY,
control_id UUID REFERENCES controls(id),
assignee_id UUID REFERENCES users(id),
due_date DATE NOT NULL,
status TEXT CHECK (status IN ('not_started', 'in_progress', 'pending_review', 'complete')),
created_at TIMESTAMP DEFAULT NOW(),
completed_at TIMESTAMP
);
-- Evidence (Human attestation)
CREATE TABLE evidence (
id UUID PRIMARY KEY,
task_id UUID REFERENCES tasks(id),
file_url TEXT NOT NULL,
submitted_by UUID REFERENCES users(id),
submitted_at TIMESTAMP DEFAULT NOW(),
attestation_statement TEXT NOT NULL, -- "I attest this evidence satisfies..."
reviewed_by UUID REFERENCES users(id),
reviewed_at TIMESTAMP
);
-- Policy Archive (Legacy documents)
CREATE TABLE archived_policies (
id UUID PRIMARY KEY,
company_id UUID REFERENCES companies(id),
filename TEXT NOT NULL,
file_url TEXT NOT NULL,
status TEXT CHECK (status IN ('archived', 'superseded')),
uploaded_by UUID REFERENCES users(id),
uploaded_at TIMESTAMP DEFAULT NOW()
);
Rule Engine¶
Simple TypeScript/SQL-based business logic:
// Example: Calculate compliance percentage
async function calculateCompliancePercentage(
companyId: string
): Promise<number> {
const { data } = await supabase
.from('tasks')
.select('status', { count: 'exact' })
.eq('company_id', companyId)
const total = data.length
const complete = data.filter((t) => t.status === 'complete').length
return (complete / total) * 100
}
// Example: Identify at-risk controls
async function getAtRiskControls(companyId: string) {
const today = new Date()
const { data } = await supabase
.from('tasks')
.select(
`
id,
control:controls(control_name),
assignee:users(name),
due_date,
status
`
)
.eq('company_id', companyId)
.neq('status', 'complete')
.lt('due_date', today.toISOString())
.order('due_date', { ascending: true })
return data.map((task) => ({
controlName: task.control.control_name,
assignee: task.assignee.name,
daysOverdue: Math.floor(
(today - new Date(task.due_date)) / (1000 * 60 * 60 * 24)
),
}))
}
Key Workflows¶
1. Onboarding (20-Second Domain Discovery)¶
- User enters domain
- Parallel DNS/SSL/subdomain checks (deterministic)
- Generate smart defaults
- User confirms and proceeds
2. Policy Setup¶
- User chooses: "Start fresh" or "Upload existing"
- If existing β Archive upload (no parsing)
- Load pre-written policy templates
- Customize with company details (find-replace)
- Generate task list from policy controls
3. Task Management¶
- Tasks auto-generated from controls
- Assign to team members
- Set due dates
- Track status: Not Started β In Progress β Pending Review β Complete
- Upload evidence + attestation statement
4. Board Reporting¶
- Director clicks "Generate Report"
- SQL queries calculate metrics
- HTML template populated with data
- PDF generated via WeasyPrint/Puppeteer
- Download or email to board members
Scaling Strategy¶
When to add AI (Post-MVP triggers):
- Customer feedback demands AI features
- Manual workflows become bottleneck
- Revenue supports operational costs
- Metrics prove core value proposition
What AI will enhance:
- Natural language policy generation
- Intelligent recommendations
- Automated evidence validation
- Conversational guidance interface
MVP Constraints¶
What's Included:
- Rule-based processing (transparent, auditable)
- Structured data model (enables reporting)
- Professional PDF outputs
- Standard workflows (proven patterns)
What's Deferred:
- AI/ML capabilities
- Complex integrations
- Custom frameworks
- Advanced analytics
Related Documents: