# GRC Platform

A production-ready, multi-tenant Governance, Risk & Compliance (GRC) SaaS platform.

## Stack

- **Frontend**: HTML5 + CSS3 + Vanilla JavaScript (ES modules, no framework)
- **Backend**: Node.js + Express.js
- **Database**: MariaDB 10.6+
- **Auth**: JWT access tokens (15 min) + rotating refresh tokens (7 day), TOTP MFA

## Features

- Multi-tenant architecture with row-level tenant isolation
- 10 pre-loaded regulatory frameworks (ISO 27001, SOC 2, GDPR, HIPAA, NIST CSF, PCI DSS, CCPA, MAS TRM, FCA SYSC, PDPA TH)
- Compliance scoring engine (coverage 40%, effectiveness 35%, evidence 25%)
- Risk register with 5×5 heatmap
- Controls library with framework mapping
- Audit management with findings tracker
- Evidence repository with file upload and expiry tracking
- Policy manager with approval workflow
- Vendor risk directory
- Incident management
- PDF and CSV report generation
- RBAC: superadmin > admin > compliance_officer > risk_manager > auditor > viewer

## Prerequisites

- Node.js ≥ 18
- MariaDB 10.6+ (or MySQL 8.0+)

## Setup

### 1. Install dependencies

```bash
npm install
```

### 2. Configure environment

```bash
cp .env.example .env
```

Edit `.env` and set:

```
DB_HOST=localhost
DB_PORT=3306
DB_USER=grc_user
DB_PASSWORD=your_password
DB_NAME=grc_platform

JWT_SECRET=<64-char random hex>
JWT_REFRESH_SECRET=<64-char random hex>
ENCRYPTION_KEY=<64-char random hex>

PORT=3000
NODE_ENV=development
```

Generate secure secrets:
```bash
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
```

### 3. Create database and run migrations

```sql
CREATE DATABASE grc_platform CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'grc_user'@'localhost' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON grc_platform.* TO 'grc_user'@'localhost';
FLUSH PRIVILEGES;
```

```bash
mysql -u grc_user -p grc_platform < migrations/001_initial_schema.sql
mysql -u grc_user -p grc_platform < migrations/002_indexes.sql
mysql -u grc_user -p grc_platform < migrations/003_seed_superadmin.sql
```

### 4. Load regulatory frameworks

```bash
INGEST_ON_START=true npm start
```

Or trigger manually via the Super Admin portal → Run Framework Ingestion.

### 5. Start the server

```bash
# Development (with auto-reload)
npm run dev

# Production
npm start
```

The app is available at `http://localhost:3000`.

## First Login

After running the seed migration, the default super admin credentials are:

- **Email**: `superadmin@grc-platform.internal`
- **Password**: `SuperAdmin123!`

Change this immediately after first login.

## Creating Your First Organization

1. Navigate to `http://localhost:3000/#/register`
2. Fill in your organization details
3. Activate compliance frameworks from the Compliance → Framework Library tab
4. Add risks, controls, and evidence

## Running Tests

Tests require a separate test database. Set `TEST_DB_NAME` in `.env` or the tests will use the main database.

```bash
npm test
```

```bash
npm run test:coverage
```

## Project Structure

```
grc-platform/
├── migrations/          # SQL schema migrations
├── ingestion-data/      # Regulatory framework JSON seeds
│   └── frameworks/
├── public/              # Frontend SPA (served as static files)
│   ├── index.html
│   ├── css/main.css
│   └── js/
│       ├── app.js       # Bootstrap, router setup, auth guard
│       ├── api.js       # API client with auto token refresh
│       ├── router.js    # Hash-based SPA router
│       ├── store.js     # Reactive state store
│       ├── components/  # Shared UI components
│       └── views/       # Page views (one per route)
├── server/
│   ├── app.js           # Express app configuration
│   ├── server.js        # HTTP server + scheduler startup
│   ├── config/          # DB pool, constants, regions
│   ├── controllers/     # Request handlers
│   ├── middleware/       # Auth, RBAC, tenant isolation, validation
│   ├── models/          # Data access layer
│   ├── routes/          # Express routers
│   ├── services/        # Business logic (compliance scoring, reports, etc.)
│   └── utils/           # Crypto, logging, pagination
├── tests/               # Integration tests (Jest + Supertest)
├── logs/                # Winston log output
└── uploads/             # Evidence file storage
```

## Security

- All passwords hashed with bcrypt (cost factor 12)
- Refresh tokens stored as SHA-256 hashes
- File uploads validated by magic bytes before accepting
- All SQL queries parameterized (no string concatenation)
- Row-level tenant isolation enforced at middleware layer
- Rate limiting per tenant/IP (100 req/min API, 10 req/min auth)
- Helmet.js security headers (CSP, HSTS, X-Frame-Options)
- Account lockout after 5 failed login attempts in 15 minutes

## Environment Variables

| Variable | Description | Default |
|---|---|---|
| `PORT` | HTTP server port | `3000` |
| `NODE_ENV` | Environment | `development` |
| `DB_HOST` | MariaDB host | `localhost` |
| `DB_PORT` | MariaDB port | `3306` |
| `DB_USER` | Database user | — |
| `DB_PASSWORD` | Database password | — |
| `DB_NAME` | Database name | `grc_platform` |
| `JWT_SECRET` | Access token signing key | — |
| `JWT_REFRESH_SECRET` | Refresh token signing key | — |
| `ENCRYPTION_KEY` | AES-256-GCM key (hex) | — |
| `JWT_EXPIRES_IN` | Access token TTL | `15m` |
| `JWT_REFRESH_EXPIRES_IN` | Refresh token TTL | `7d` |
| `UPLOAD_DIR` | File upload directory | `./uploads` |
| `MAX_FILE_SIZE_MB` | Max upload file size | `50` |
| `INGEST_ON_START` | Run ingestion on startup | `false` |
| `SMTP_HOST` | Email server host | — |
| `SMTP_PORT` | Email server port | `587` |
| `SMTP_USER` | Email username | — |
| `SMTP_PASS` | Email password | — |
| `EMAIL_FROM` | Sender address | — |
