# AI Agent Prompt: Production-Ready Multi-Tenant GRC Application

---

## MISSION DIRECTIVE

You are a senior full-stack engineer and compliance architect. Your task is to build a **comprehensive, production-ready, multi-tenant Governance, Risk & Compliance (GRC) platform** from scratch. The system must be enterprise-grade, secure, scalable, and capable of ingesting regulatory data to generate region-specific compliance frameworks automatically.

**Tech stack:** HTML5 + CSS3 + Vanilla JavaScript (frontend) · Node.js + Express.js (backend API) · MariaDB (primary database) · No frontend frameworks unless specified.

---

## SYSTEM OVERVIEW

The GRC platform is a SaaS application serving multiple independent tenants (organizations). Each tenant manages their own:
- Compliance frameworks (mapped to regulatory regions/standards)
- Risk register and assessments
- Control library and evidence tracking
- Audit programs and findings
- Policy and document management
- Vendor/third-party risk management
- Incident management
- Reporting and dashboards

---

## PART 1 — DATABASE SCHEMA (MariaDB)

### Multi-Tenancy Architecture
Use a **shared database, shared schema** model with `tenant_id` on every table. Enforce row-level isolation at the application layer via middleware.

### Required Tables

#### Core Tenancy & Identity
```sql
CREATE TABLE tenants (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  name            VARCHAR(255) NOT NULL,
  slug            VARCHAR(100) UNIQUE NOT NULL,
  plan            ENUM('starter','professional','enterprise') DEFAULT 'starter',
  region          VARCHAR(100),
  industry        VARCHAR(100),
  logo_url        TEXT,
  settings        JSON,
  status          ENUM('active','suspended','trial') DEFAULT 'trial',
  trial_ends_at   DATETIME,
  created_at      DATETIME DEFAULT NOW(),
  updated_at      DATETIME DEFAULT NOW() ON UPDATE NOW()
);

CREATE TABLE users (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  tenant_id       CHAR(36) NOT NULL,
  email           VARCHAR(255) NOT NULL,
  password_hash   VARCHAR(255) NOT NULL,
  first_name      VARCHAR(100),
  last_name       VARCHAR(100),
  role            ENUM('superadmin','admin','compliance_officer','risk_manager','auditor','viewer') DEFAULT 'viewer',
  mfa_secret      VARCHAR(100),
  mfa_enabled     BOOLEAN DEFAULT FALSE,
  last_login_at   DATETIME,
  is_active       BOOLEAN DEFAULT TRUE,
  created_at      DATETIME DEFAULT NOW(),
  UNIQUE KEY uq_tenant_email (tenant_id, email),
  FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);

CREATE TABLE sessions (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  user_id         CHAR(36) NOT NULL,
  tenant_id       CHAR(36) NOT NULL,
  token_hash      VARCHAR(255) NOT NULL UNIQUE,
  ip_address      VARCHAR(45),
  user_agent      TEXT,
  expires_at      DATETIME NOT NULL,
  created_at      DATETIME DEFAULT NOW(),
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

CREATE TABLE audit_logs (
  id              BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  tenant_id       CHAR(36) NOT NULL,
  user_id         CHAR(36),
  action          VARCHAR(100) NOT NULL,
  resource_type   VARCHAR(100),
  resource_id     CHAR(36),
  old_values      JSON,
  new_values      JSON,
  ip_address      VARCHAR(45),
  created_at      DATETIME DEFAULT NOW(),
  INDEX idx_tenant_created (tenant_id, created_at),
  INDEX idx_resource (resource_type, resource_id)
);
```

#### Compliance Frameworks & Controls
```sql
CREATE TABLE regulatory_frameworks (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  code            VARCHAR(50) NOT NULL UNIQUE,
  name            VARCHAR(255) NOT NULL,
  description     TEXT,
  version         VARCHAR(50),
  issuing_body    VARCHAR(255),
  regions         JSON,
  industries      JSON,
  effective_date  DATE,
  is_global       BOOLEAN DEFAULT FALSE,
  created_at      DATETIME DEFAULT NOW()
);

CREATE TABLE framework_requirements (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  framework_id    CHAR(36) NOT NULL,
  parent_id       CHAR(36),
  reference_code  VARCHAR(100) NOT NULL,
  title           VARCHAR(500) NOT NULL,
  description     TEXT,
  guidance        TEXT,
  requirement_type ENUM('mandatory','recommended','optional') DEFAULT 'mandatory',
  category        VARCHAR(255),
  tags            JSON,
  sort_order      INT DEFAULT 0,
  FOREIGN KEY (framework_id) REFERENCES regulatory_frameworks(id) ON DELETE CASCADE,
  FOREIGN KEY (parent_id) REFERENCES framework_requirements(id) ON DELETE SET NULL,
  INDEX idx_framework (framework_id)
);

CREATE TABLE tenant_frameworks (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  tenant_id       CHAR(36) NOT NULL,
  framework_id    CHAR(36) NOT NULL,
  status          ENUM('active','inactive','in_review') DEFAULT 'active',
  target_date     DATE,
  owner_id        CHAR(36),
  notes           TEXT,
  activated_at    DATETIME DEFAULT NOW(),
  UNIQUE KEY uq_tenant_framework (tenant_id, framework_id),
  FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
  FOREIGN KEY (framework_id) REFERENCES regulatory_frameworks(id)
);

CREATE TABLE controls (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  tenant_id       CHAR(36) NOT NULL,
  control_id      VARCHAR(100) NOT NULL,
  title           VARCHAR(500) NOT NULL,
  description     TEXT,
  type            ENUM('preventive','detective','corrective','deterrent','compensating') DEFAULT 'preventive',
  category        VARCHAR(255),
  frequency       ENUM('continuous','daily','weekly','monthly','quarterly','annually','ad_hoc'),
  owner_id        CHAR(36),
  status          ENUM('active','inactive','under_review') DEFAULT 'active',
  effectiveness   ENUM('effective','partially_effective','ineffective','not_tested') DEFAULT 'not_tested',
  automation_level ENUM('manual','semi_automated','automated') DEFAULT 'manual',
  last_tested_at  DATETIME,
  tags            JSON,
  created_at      DATETIME DEFAULT NOW(),
  updated_at      DATETIME DEFAULT NOW() ON UPDATE NOW(),
  FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
  INDEX idx_tenant_status (tenant_id, status)
);

CREATE TABLE control_framework_mappings (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  tenant_id       CHAR(36) NOT NULL,
  control_id      CHAR(36) NOT NULL,
  requirement_id  CHAR(36) NOT NULL,
  coverage        ENUM('full','partial','none') DEFAULT 'partial',
  notes           TEXT,
  mapped_at       DATETIME DEFAULT NOW(),
  UNIQUE KEY uq_control_req (control_id, requirement_id),
  FOREIGN KEY (control_id) REFERENCES controls(id) ON DELETE CASCADE,
  FOREIGN KEY (requirement_id) REFERENCES framework_requirements(id) ON DELETE CASCADE
);
```

#### Risk Management
```sql
CREATE TABLE risk_categories (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  tenant_id       CHAR(36) NOT NULL,
  name            VARCHAR(255) NOT NULL,
  description     TEXT,
  color           VARCHAR(7),
  parent_id       CHAR(36),
  FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);

CREATE TABLE risks (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  tenant_id       CHAR(36) NOT NULL,
  risk_id         VARCHAR(100) NOT NULL,
  title           VARCHAR(500) NOT NULL,
  description     TEXT,
  category_id     CHAR(36),
  owner_id        CHAR(36),
  status          ENUM('open','mitigated','accepted','transferred','closed') DEFAULT 'open',
  likelihood      TINYINT UNSIGNED CHECK (likelihood BETWEEN 1 AND 5),
  impact          TINYINT UNSIGNED CHECK (impact BETWEEN 1 AND 5),
  inherent_score  TINYINT UNSIGNED GENERATED ALWAYS AS (likelihood * impact) STORED,
  residual_likelihood TINYINT UNSIGNED,
  residual_impact TINYINT UNSIGNED,
  residual_score  TINYINT UNSIGNED GENERATED ALWAYS AS (residual_likelihood * residual_impact) STORED,
  target_date     DATE,
  treatment       ENUM('mitigate','accept','transfer','avoid'),
  tags            JSON,
  review_date     DATE,
  created_at      DATETIME DEFAULT NOW(),
  updated_at      DATETIME DEFAULT NOW() ON UPDATE NOW(),
  FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
  FOREIGN KEY (category_id) REFERENCES risk_categories(id) ON DELETE SET NULL,
  INDEX idx_tenant_status (tenant_id, status),
  INDEX idx_tenant_score (tenant_id, inherent_score)
);

CREATE TABLE risk_treatments (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  tenant_id       CHAR(36) NOT NULL,
  risk_id         CHAR(36) NOT NULL,
  title           VARCHAR(500) NOT NULL,
  description     TEXT,
  type            ENUM('control','action','acceptance','transfer'),
  control_id      CHAR(36),
  owner_id        CHAR(36),
  status          ENUM('planned','in_progress','completed','cancelled') DEFAULT 'planned',
  due_date        DATE,
  cost_estimate   DECIMAL(15,2),
  created_at      DATETIME DEFAULT NOW(),
  FOREIGN KEY (risk_id) REFERENCES risks(id) ON DELETE CASCADE
);

CREATE TABLE risk_control_mappings (
  risk_id         CHAR(36) NOT NULL,
  control_id      CHAR(36) NOT NULL,
  tenant_id       CHAR(36) NOT NULL,
  PRIMARY KEY (risk_id, control_id),
  FOREIGN KEY (risk_id) REFERENCES risks(id) ON DELETE CASCADE,
  FOREIGN KEY (control_id) REFERENCES controls(id) ON DELETE CASCADE
);
```

#### Audit Management
```sql
CREATE TABLE audits (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  tenant_id       CHAR(36) NOT NULL,
  audit_id        VARCHAR(100) NOT NULL,
  title           VARCHAR(500) NOT NULL,
  type            ENUM('internal','external','regulatory','certification') DEFAULT 'internal',
  framework_id    CHAR(36),
  lead_auditor_id CHAR(36),
  status          ENUM('planned','in_progress','review','completed','cancelled') DEFAULT 'planned',
  scope           TEXT,
  objectives      TEXT,
  planned_start   DATE,
  planned_end     DATE,
  actual_start    DATE,
  actual_end      DATE,
  opinion         ENUM('clean','qualified','adverse','disclaimer'),
  summary         TEXT,
  created_at      DATETIME DEFAULT NOW(),
  FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
  FOREIGN KEY (framework_id) REFERENCES regulatory_frameworks(id) ON DELETE SET NULL
);

CREATE TABLE audit_findings (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  tenant_id       CHAR(36) NOT NULL,
  audit_id        CHAR(36) NOT NULL,
  finding_id      VARCHAR(100) NOT NULL,
  title           VARCHAR(500) NOT NULL,
  description     TEXT,
  severity        ENUM('critical','high','medium','low','informational') DEFAULT 'medium',
  status          ENUM('open','in_remediation','remediated','accepted','closed') DEFAULT 'open',
  control_id      CHAR(36),
  requirement_id  CHAR(36),
  recommendation  TEXT,
  management_response TEXT,
  owner_id        CHAR(36),
  due_date        DATE,
  closed_at       DATETIME,
  created_at      DATETIME DEFAULT NOW(),
  FOREIGN KEY (audit_id) REFERENCES audits(id) ON DELETE CASCADE,
  FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);
```

#### Evidence & Documents
```sql
CREATE TABLE evidence (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  tenant_id       CHAR(36) NOT NULL,
  title           VARCHAR(500) NOT NULL,
  description     TEXT,
  type            ENUM('document','screenshot','log','certificate','report','policy','procedure','other'),
  file_name       VARCHAR(500),
  file_path       TEXT,
  file_size       BIGINT UNSIGNED,
  mime_type       VARCHAR(100),
  hash_sha256     VARCHAR(64),
  uploaded_by     CHAR(36),
  valid_from      DATE,
  valid_until     DATE,
  is_expired      BOOLEAN GENERATED ALWAYS AS (valid_until IS NOT NULL AND valid_until < CURDATE()) STORED,
  tags            JSON,
  created_at      DATETIME DEFAULT NOW(),
  FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
  INDEX idx_tenant_expired (tenant_id, is_expired)
);

CREATE TABLE control_evidence (
  control_id      CHAR(36) NOT NULL,
  evidence_id     CHAR(36) NOT NULL,
  tenant_id       CHAR(36) NOT NULL,
  mapped_at       DATETIME DEFAULT NOW(),
  PRIMARY KEY (control_id, evidence_id),
  FOREIGN KEY (control_id) REFERENCES controls(id) ON DELETE CASCADE,
  FOREIGN KEY (evidence_id) REFERENCES evidence(id) ON DELETE CASCADE
);

CREATE TABLE policies (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  tenant_id       CHAR(36) NOT NULL,
  title           VARCHAR(500) NOT NULL,
  content         LONGTEXT,
  version         VARCHAR(50) DEFAULT '1.0',
  status          ENUM('draft','under_review','approved','published','retired') DEFAULT 'draft',
  category        VARCHAR(255),
  owner_id        CHAR(36),
  approver_id     CHAR(36),
  approved_at     DATETIME,
  effective_date  DATE,
  review_date     DATE,
  created_at      DATETIME DEFAULT NOW(),
  updated_at      DATETIME DEFAULT NOW() ON UPDATE NOW(),
  FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);
```

#### Vendor Risk Management
```sql
CREATE TABLE vendors (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  tenant_id       CHAR(36) NOT NULL,
  name            VARCHAR(255) NOT NULL,
  category        VARCHAR(100),
  criticality     ENUM('critical','high','medium','low') DEFAULT 'medium',
  status          ENUM('active','inactive','under_review','offboarded') DEFAULT 'active',
  primary_contact VARCHAR(255),
  contact_email   VARCHAR(255),
  website         VARCHAR(500),
  data_shared     JSON,
  risk_score      TINYINT UNSIGNED,
  last_assessed   DATE,
  next_assessment DATE,
  created_at      DATETIME DEFAULT NOW(),
  FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);
```

#### Incident Management
```sql
CREATE TABLE incidents (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  tenant_id       CHAR(36) NOT NULL,
  incident_id     VARCHAR(100) NOT NULL,
  title           VARCHAR(500) NOT NULL,
  description     TEXT,
  type            ENUM('data_breach','system_failure','policy_violation','fraud','physical','other'),
  severity        ENUM('critical','high','medium','low') DEFAULT 'medium',
  status          ENUM('reported','investigating','contained','resolved','closed') DEFAULT 'reported',
  reporter_id     CHAR(36),
  owner_id        CHAR(36),
  detected_at     DATETIME,
  reported_at     DATETIME DEFAULT NOW(),
  contained_at    DATETIME,
  resolved_at     DATETIME,
  regulatory_notification_required BOOLEAN DEFAULT FALSE,
  notified_at     DATETIME,
  root_cause      TEXT,
  lessons_learned TEXT,
  created_at      DATETIME DEFAULT NOW(),
  FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
);
```

#### Compliance Data Ingestion
```sql
CREATE TABLE ingestion_sources (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  name            VARCHAR(255) NOT NULL,
  type            ENUM('json','csv','xml','api','manual') DEFAULT 'json',
  url             TEXT,
  schema_version  VARCHAR(50),
  last_ingested   DATETIME,
  is_active       BOOLEAN DEFAULT TRUE,
  created_at      DATETIME DEFAULT NOW()
);

CREATE TABLE ingestion_jobs (
  id              CHAR(36) PRIMARY KEY DEFAULT (UUID()),
  source_id       CHAR(36),
  tenant_id       CHAR(36),
  status          ENUM('pending','running','completed','failed') DEFAULT 'pending',
  records_processed INT UNSIGNED DEFAULT 0,
  records_failed  INT UNSIGNED DEFAULT 0,
  error_log       TEXT,
  started_at      DATETIME,
  completed_at    DATETIME,
  created_at      DATETIME DEFAULT NOW(),
  FOREIGN KEY (source_id) REFERENCES ingestion_sources(id) ON DELETE SET NULL
);
```

---

## PART 2 — BACKEND (Node.js / Express)

### Project Structure
```
/grc-platform
├── /server
│   ├── app.js                    # Express app factory
│   ├── server.js                 # HTTP server entrypoint
│   ├── /config
│   │   ├── database.js           # MariaDB pool config
│   │   ├── constants.js          # App-wide constants
│   │   └── regions.js            # Supported regulatory regions
│   ├── /middleware
│   │   ├── auth.js               # JWT + session verification
│   │   ├── tenant.js             # Tenant resolution & isolation
│   │   ├── rbac.js               # Role-based access control
│   │   ├── rateLimiter.js        # Per-tenant rate limiting
│   │   ├── validator.js          # Input validation helper
│   │   └── errorHandler.js       # Centralized error handler
│   ├── /routes
│   │   ├── auth.routes.js
│   │   ├── tenants.routes.js
│   │   ├── users.routes.js
│   │   ├── frameworks.routes.js
│   │   ├── controls.routes.js
│   │   ├── risks.routes.js
│   │   ├── audits.routes.js
│   │   ├── findings.routes.js
│   │   ├── evidence.routes.js
│   │   ├── policies.routes.js
│   │   ├── vendors.routes.js
│   │   ├── incidents.routes.js
│   │   ├── ingestion.routes.js
│   │   ├── reports.routes.js
│   │   └── dashboard.routes.js
│   ├── /controllers              # Business logic (mirrors routes)
│   ├── /models                   # DB query abstractions per entity
│   ├── /services
│   │   ├── ingestion.service.js  # Regulatory data ingestion engine
│   │   ├── compliance.service.js # Gap analysis & scoring
│   │   ├── notification.service.js
│   │   ├── report.service.js     # PDF/CSV report generation
│   │   └── scheduler.service.js  # Cron jobs (review reminders, etc.)
│   └── /utils
│       ├── crypto.js             # Hashing, encryption helpers
│       ├── pagination.js
│       └── logger.js             # Winston structured logger
├── /public                       # Frontend static files
├── /uploads                      # Evidence file storage
├── /ingestion-data               # Seeded framework JSON files
├── .env.example
├── package.json
└── README.md
```

### Critical Backend Requirements

**1. Authentication & Sessions**
- Implement JWT access tokens (15-minute expiry) + refresh tokens (7-day expiry, stored as hashed value in `sessions` table)
- Support TOTP-based MFA (use `speakeasy` or `otplib`)
- All tokens must be invalidated on password change or manual logout
- Track all login attempts; lock account after 5 failed attempts within 15 minutes

**2. Tenant Middleware** (`middleware/tenant.js`)
- Extract tenant from subdomain (`tenant.slug.yourdomain.com`) OR from JWT claim
- Attach `req.tenant` and `req.tenantId` to every request
- Every DB query MUST include `WHERE tenant_id = ?` enforcement — never allow cross-tenant data access
- Implement a `TenantQuery` wrapper class that automatically appends tenant_id

**3. RBAC Middleware** (`middleware/rbac.js`)
- Roles hierarchy: `superadmin > admin > compliance_officer > risk_manager > auditor > viewer`
- Define granular permission matrix: e.g., `risks:create`, `controls:delete`, `audits:read`
- Apply `requirePermission('risks:create')` decorators on route handlers

**4. All API Routes Must:**
- Validate and sanitize all inputs (use `express-validator`)
- Return consistent JSON envelope: `{ success: bool, data: any, meta: {}, errors: [] }`
- Paginate all list endpoints: `?page=1&limit=25&sort=created_at&order=desc`
- Support filtering via query params: `?status=open&owner_id=xxx&date_from=xxx`
- Log all mutations to `audit_logs` table automatically

**5. Ingestion Service** (`services/ingestion.service.js`)
Build a regulatory framework ingestion engine that:
- Reads JSON files from `/ingestion-data/frameworks/` (see seeded formats below)
- Parses and upserts into `regulatory_frameworks` and `framework_requirements`
- Supports formats: flat requirement list, hierarchical tree, CSV with columns
- Maps requirements to relevant tenant regions automatically on tenant signup
- Provides a REST endpoint `POST /api/ingestion/run` to trigger re-ingestion
- Supports ingestion from external URLs (fetch + parse)
- Idempotent: re-running same source must update, not duplicate

**6. Compliance Scoring Service** (`services/compliance.service.js`)
Calculate for each tenant+framework combination:
- `coverage_score`: % of requirements with at least one mapped control
- `effectiveness_score`: avg effectiveness rating of mapped controls
- `evidence_score`: % of controls with at least one valid, non-expired evidence item
- `overall_score`: weighted average of above three
- Expose via `GET /api/dashboard/compliance-score?framework_id=xxx`

**7. File Upload** (evidence)
- Use `multer` for multipart uploads
- Validate MIME type and file size (max 50MB)
- Store files in `/uploads/{tenant_id}/{year}/{month}/`
- Generate SHA-256 hash of file content on upload
- Store only relative path in DB; never expose absolute server paths

**8. Report Generation** (`services/report.service.js`)
Generate downloadable reports:
- Compliance gap analysis (by framework)
- Risk register export
- Audit findings summary
- Evidence expiry report
Use `pdfkit` for PDF and `fast-csv` for CSV exports.

**9. Scheduler** (`services/scheduler.service.js`)
Use `node-cron` for recurring jobs:
- Daily: Check for expiring evidence, controls due for review, risks past target date
- Weekly: Send compliance score digest to tenant admins
- Monthly: Auto-generate compliance health report for each active tenant

---

## PART 3 — REGULATORY FRAMEWORK SEED DATA FORMAT

Create JSON seed files in `/ingestion-data/frameworks/`. Each file follows this schema:

```json
{
  "code": "ISO27001-2022",
  "name": "ISO/IEC 27001:2022",
  "version": "2022",
  "issuing_body": "ISO/IEC",
  "description": "Information security management systems standard",
  "regions": ["global"],
  "industries": ["all"],
  "effective_date": "2022-10-25",
  "is_global": true,
  "requirements": [
    {
      "reference_code": "4",
      "title": "Context of the Organization",
      "requirement_type": "mandatory",
      "category": "Organizational Context",
      "children": [
        {
          "reference_code": "4.1",
          "title": "Understanding the organization and its context",
          "description": "The organization shall determine external and internal issues...",
          "guidance": "Consider PEST analysis, SWOT analysis...",
          "requirement_type": "mandatory"
        }
      ]
    }
  ]
}
```

**Seed these frameworks at minimum:**
1. `ISO27001-2022.json` — Information Security (Global)
2. `SOC2-2017.json` — SOC 2 Type II Trust Services Criteria (USA)
3. `GDPR.json` — EU General Data Protection Regulation (EU/EEA)
4. `HIPAA.json` — Health Insurance Portability and Accountability Act (USA)
5. `PCIDSS-4.json` — PCI Data Security Standard v4.0 (Global)
6. `NIST-CSF-2.json` — NIST Cybersecurity Framework 2.0 (USA/Global)
7. `CCPA.json` — California Consumer Privacy Act (USA-CA)
8. `MAS-TRM.json` — MAS Technology Risk Management (Singapore)
9. `FCA-SYSC.json` — FCA Senior Management Arrangements (UK)
10. `PDPA-TH.json` — Personal Data Protection Act (Thailand)

---

## PART 4 — FRONTEND APPLICATION

### Architecture
Single-page application using vanilla JS module pattern. All pages are rendered client-side by swapping content in `#app-container`. No page reloads after initial load.

### Application Shell (`/public/index.html`)
```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>GRC Platform</title>
  <link rel="stylesheet" href="/css/main.css">
</head>
<body>
  <div id="app">
    <nav id="sidebar"></nav>
    <main id="app-container"></main>
  </div>
  <div id="modal-overlay" class="hidden"></div>
  <div id="toast-container"></div>
  <script src="/js/app.js" type="module"></script>
</body>
</html>
```

### Required Pages / Views

**1. Authentication Views**
- `/login` — Email + password + MFA code field (conditional)
- `/register` — Tenant signup: org name, industry, region, admin email/password
- `/forgot-password` and `/reset-password/:token`

**2. Dashboard** (`/dashboard`)
- Tenant-level compliance health scorecard (overall % per framework)
- Risk heatmap (5x5 grid: likelihood vs impact, color-coded)
- KPI cards: Open Risks, Overdue Controls, Active Audits, Expiring Evidence
- Recent activity feed
- Framework coverage chart (donut chart per active framework)
- Upcoming review calendar widget

**3. Compliance Management** (`/compliance`)
- Framework picker: list all available frameworks, filter by region/industry
- Activate/deactivate frameworks for tenant
- Per-framework requirement tree view (collapsible hierarchy)
- Per-requirement: compliance status badge, mapped controls list, evidence count
- Gap analysis view: requirements with no controls (colored RED), partial (AMBER), covered (GREEN)
- Bulk assign controls to requirements

**4. Risk Register** (`/risks`)
- Filterable/sortable risk table
- Risk heatmap visual (interactive: click cell to filter risks)
- Add/Edit risk modal with full form (title, description, category, likelihood, impact, treatment, owner, due date)
- Risk detail page: treatments, linked controls, history, comments
- Risk import via CSV

**5. Controls Library** (`/controls`)
- Searchable control catalog table
- Add/Edit control modal
- Per-control: linked requirements (across all frameworks), linked evidence, test history
- Control effectiveness workflow: mark test result, attach evidence

**6. Audit Management** (`/audits`)
- Audit list with status pipeline view (Planned → In Progress → Review → Complete)
- Create audit wizard: select framework, scope, dates, assign auditors
- Audit workspace: requirements checklist, add findings inline
- Findings list with severity badges, owner assignment, due dates
- Finding remediation tracking

**7. Evidence Repository** (`/evidence`)
- File upload interface (drag & drop)
- Evidence table: file name, type, valid dates, linked controls count, expiry status
- Filter by: type, expiry status, linked control, uploader
- Expiry warning banner for evidence expiring within 30 days

**8. Policy Manager** (`/policies`)
- Policy list with status workflow (Draft → Review → Approved → Published)
- Rich text editor for policy content (use `Quill.js` from CDN)
- Policy approval workflow UI
- Version history view

**9. Vendor Risk** (`/vendors`)
- Vendor directory table
- Add/Edit vendor form
- Vendor risk score display
- Assessment scheduling

**10. Incidents** (`/incidents`)
- Incident log table
- Report incident form
- Incident timeline/status tracker
- Regulatory notification flag + timestamp

**11. Reports** (`/reports`)
- Report builder: select report type, framework, date range
- Download buttons: PDF and CSV
- Scheduled report configuration

**12. Settings** (`/settings`)
- Organization profile
- User management (invite, role assignment, deactivate)
- MFA setup wizard
- API key management (for external integrations)
- Data ingestion configuration: add custom framework source URLs
- Notification preferences

**13. Super Admin Portal** (`/superadmin`) — separate module
- Tenant list, create/suspend tenants
- Trigger framework ingestion jobs globally
- System health metrics

### Frontend CSS Design System
Build a professional dark-theme design system in `/public/css/main.css`:
```css
:root {
  --color-bg-primary: #0f1117;
  --color-bg-secondary: #1a1d27;
  --color-bg-card: #1e2130;
  --color-bg-elevated: #252839;
  --color-border: #2d3148;
  --color-border-subtle: #1f2235;
  --color-accent: #4f6ef7;
  --color-accent-hover: #6b85ff;
  --color-accent-muted: rgba(79,110,247,0.12);
  --color-text-primary: #e8eaf0;
  --color-text-secondary: #8b8fa8;
  --color-text-muted: #565a72;
  --color-success: #22c55e;
  --color-warning: #f59e0b;
  --color-danger: #ef4444;
  --color-info: #3b82f6;
  --color-critical: #dc2626;
  --sidebar-width: 240px;
  --header-height: 60px;
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --shadow-card: 0 1px 3px rgba(0,0,0,0.4);
  --transition: 150ms ease;
}
```

### Frontend JavaScript Modules
Implement as ES modules:
- `app.js` — Router, auth guard, app bootstrap
- `api.js` — Fetch wrapper: auto-attach auth headers, handle token refresh, error normalization
- `router.js` — Hash-based SPA router (`/#/dashboard`, `/#/risks`, etc.)
- `store.js` — Lightweight reactive state store (no library)
- `components/sidebar.js` — Navigation with role-based menu items
- `components/modal.js` — Reusable modal manager
- `components/toast.js` — Toast notification system
- `components/table.js` — Reusable sortable/paginated data table component
- `components/heatmap.js` — 5x5 risk heatmap SVG renderer
- `components/charts.js` — Donut and bar charts using Canvas API (no library)
- `views/` — One file per page view

---

## PART 5 — SECURITY REQUIREMENTS

Implement ALL of the following without exception:

1. **SQL Injection Prevention**: Use parameterized queries exclusively. Never concatenate user input into SQL strings.
2. **XSS Prevention**: Sanitize all user-generated content before rendering to DOM. Use `textContent` not `innerHTML` for user data. Escape HTML in server-rendered content.
3. **CSRF Protection**: Implement CSRF tokens for all state-changing requests (use `csurf` package).
4. **Rate Limiting**: Per-tenant and per-IP rate limiting on all endpoints. Auth endpoints: 10 req/min. API endpoints: 100 req/min per tenant.
5. **Security Headers**: Use `helmet.js` — enforce CSP, HSTS, X-Frame-Options, X-Content-Type-Options.
6. **Password Security**: bcrypt with cost factor 12. Enforce minimum 12 characters, complexity rules.
7. **File Upload Security**: Validate magic bytes (not just extension), scan for embedded scripts, restrict file types to: PDF, DOCX, XLSX, PNG, JPG, TXT, CSV.
8. **Tenant Isolation**: Every single database query must be validated to include `tenant_id`. Add an integration test that proves cross-tenant data leakage is impossible.
9. **Secrets Management**: All credentials in `.env` file. Never hardcode. Provide `.env.example` with all required variables documented.
10. **Error Handling**: Never expose stack traces or internal errors to API consumers. Log internally with Winston; return generic error messages externally.
11. **Audit Trail**: Every create/update/delete operation must write to `audit_logs` with before/after values.
12. **Session Security**: Secure, HttpOnly, SameSite cookies. Rotate refresh tokens on each use.

---

## PART 6 — ENVIRONMENT CONFIGURATION

### `.env.example`
```env
# Server
NODE_ENV=production
PORT=3000
HOST=0.0.0.0
APP_URL=https://yourdomain.com
APP_NAME=GRC Platform

# Database
DB_HOST=localhost
DB_PORT=3306
DB_NAME=grc_platform
DB_USER=grc_user
DB_PASSWORD=CHANGE_ME_STRONG_PASSWORD
DB_POOL_MIN=5
DB_POOL_MAX=20

# Auth
JWT_ACCESS_SECRET=CHANGE_ME_256BIT_RANDOM_STRING
JWT_REFRESH_SECRET=CHANGE_ME_DIFFERENT_256BIT_STRING
JWT_ACCESS_EXPIRY=15m
JWT_REFRESH_EXPIRY=7d

# Encryption
ENCRYPTION_KEY=CHANGE_ME_32_CHAR_KEY
ENCRYPTION_ALGORITHM=aes-256-gcm

# File Storage
UPLOAD_DIR=./uploads
MAX_FILE_SIZE_MB=50
ALLOWED_MIME_TYPES=application/pdf,image/png,image/jpeg,...

# Email (for notifications)
SMTP_HOST=smtp.yourdomain.com
SMTP_PORT=587
SMTP_USER=noreply@yourdomain.com
SMTP_PASS=CHANGE_ME
SMTP_FROM=GRC Platform <noreply@yourdomain.com>

# Logging
LOG_LEVEL=info
LOG_DIR=./logs

# Ingestion
INGESTION_FRAMEWORKS_DIR=./ingestion-data/frameworks
INGESTION_CRON_SCHEDULE=0 2 * * 0

# Rate Limiting
RATE_LIMIT_AUTH_WINDOW_MS=60000
RATE_LIMIT_AUTH_MAX=10
RATE_LIMIT_API_WINDOW_MS=60000
RATE_LIMIT_API_MAX=100
```

---

## PART 7 — PACKAGE DEPENDENCIES

### `package.json` dependencies
```json
{
  "dependencies": {
    "express": "^4.18.x",
    "mariadb": "^3.x",
    "bcrypt": "^5.x",
    "jsonwebtoken": "^9.x",
    "express-validator": "^7.x",
    "helmet": "^7.x",
    "cors": "^2.x",
    "multer": "^1.x",
    "csurf": "^1.x",
    "express-rate-limit": "^7.x",
    "otplib": "^12.x",
    "qrcode": "^1.x",
    "node-cron": "^3.x",
    "winston": "^3.x",
    "pdfkit": "^0.x",
    "fast-csv": "^4.x",
    "uuid": "^9.x",
    "dotenv": "^16.x",
    "compression": "^1.x",
    "morgan": "^1.x"
  },
  "devDependencies": {
    "nodemon": "^3.x",
    "jest": "^29.x",
    "supertest": "^6.x"
  }
}
```

---

## PART 8 — DELIVERABLES CHECKLIST

You must produce ALL of the following files, fully implemented:

**Database**
- [ ] `/server/config/database.js` — MariaDB connection pool
- [ ] `/migrations/001_initial_schema.sql` — Complete schema from Part 1
- [ ] `/migrations/002_indexes.sql` — Performance indexes
- [ ] `/migrations/003_seed_superadmin.sql` — Initial superadmin user

**Backend Core**
- [ ] `server.js` — HTTP server with graceful shutdown
- [ ] `app.js` — Express app with all middleware registered
- [ ] All middleware files (auth, tenant, rbac, rateLimiter, validator, errorHandler)
- [ ] All route files with full CRUD endpoints
- [ ] All controller files with business logic
- [ ] All model files with parameterized DB queries

**Services**
- [ ] `ingestion.service.js` — Full ingestion engine
- [ ] `compliance.service.js` — Scoring algorithms
- [ ] `report.service.js` — PDF + CSV generation
- [ ] `scheduler.service.js` — Cron job definitions
- [ ] `notification.service.js` — Email notifications

**Seed Data**
- [ ] All 10 regulatory framework JSON files in `/ingestion-data/frameworks/`
- [ ] Each with at minimum 15–30 requirements (with hierarchy)

**Frontend**
- [ ] `/public/index.html` — App shell
- [ ] `/public/css/main.css` — Complete design system (dark theme)
- [ ] `/public/js/app.js` — Router, bootstrap
- [ ] `/public/js/api.js` — API client
- [ ] All component files
- [ ] All view files (all 13 pages listed in Part 4)

**Configuration**
- [ ] `.env.example` — All variables documented
- [ ] `package.json` — All dependencies listed
- [ ] `README.md` — Setup instructions, architecture overview, API reference summary

---

## PART 9 — IMPLEMENTATION QUALITY STANDARDS

- All async operations must use `async/await` with proper `try/catch`
- Database connections must use connection pooling (never create connections per request)
- All API responses follow the envelope format: `{ success, data, meta, errors }`
- Every list endpoint must support: `page`, `limit`, `sort`, `order`, and entity-specific filters
- Frontend API calls handle: loading state, success state, error state with user-visible messages
- All forms have client-side validation before API submission
- The UI must be responsive (mobile breakpoints at 768px and 1024px)
- Implement proper `Content-Security-Policy` headers that work with the SPA
- All file uploads must be streamed (not buffered in memory for large files)
- Write at minimum 20 integration tests covering: auth, tenant isolation, CRUD operations, ingestion

---

## EXECUTION INSTRUCTIONS

1. Start with the **database schema** — run migrations in order
2. Build the **Express app skeleton** with middleware stack
3. Implement **authentication** routes and middleware first (everything depends on it)
4. Implement **tenant middleware** and prove isolation works before continuing
5. Build **ingestion service** and seed all 10 framework JSON files
6. Implement remaining **API routes** module by module
7. Build **frontend design system** (CSS variables, base components)
8. Implement **frontend SPA** view by view, wiring to real API
9. Implement **compliance scoring** and **dashboard** last (depends on all other data)
10. Run security checklist — validate every item in Part 5 is implemented
11. Write integration tests
12. Write `README.md` with full setup guide

**Output each file completely — no placeholders, no `// TODO` comments, no truncated code. Every file must be production-ready and immediately executable.**
