tutorials
saasstartupgdprpostgresql

Database Compliance for SaaS Startups: The Minimum Viable Compliance Stack

Minimum viable compliance for SaaS startups on PostgreSQL. GDPR deletion, audit trails, and investor-ready evidence.

RL
Robert Langner
Managing Director, NILS Software GmbH · · 4 min read

The Five Pillars of Minimum Viable Compliance

1. Know Where PII Lives

Before you can protect or delete data, you need to know where it is.

SELECT pgcomply.quick_setup();
-- Scans all tables, detects PII patterns, creates registry

2. Delete on Request

When user-123 asks for deletion:

SELECT pgcomply.forget('user-123');
SELECT * FROM pgcomply.verify_forget('user-123');

3. Prove You Did It

The audit trail logs every compliance operation:

SELECT * FROM pgcomply.audit_log WHERE event_type = 'forget_complete';

4. Protect from Unauthorized Access

-- Mask PII for non-admin roles
SELECT pgcomply.mask('users', 'email', 'partial', ARRAY['postgres']);

-- Enable RLS on PII tables
SELECT pgcomply.enable_rls('users', 'user_id');

5. Clean Up Old Data

SELECT pgcomply.retain('sessions', 'created_at', '30 days');
SELECT pgcomply.schedule_jobs(install := true);

When to Level Up

| Stage | Users | Add | |-------|-------|-----| | Pre-seed | < 100 | quick_setup(), forget() | | Seed | 100 - 1k | Masking, retention policies | | Series A | 1k - 10k | Consent tracking, health checks | | Series B | 10k+ | Pro dashboard, access reviews, SOC 2 evidence |

Real-World Scenario: Your First DSAR

It's Tuesday morning. You receive an email: "I'd like a copy of all my personal data and then I'd like it deleted. — Jane, jane@example.com"

Without pgcomply, this triggers a fire drill: which tables have Jane's data? How do you export it? How do you delete it without breaking foreign keys? Can you prove you did it?

With pgcomply, it's three commands:

-- 1. Find all of Jane's data
SELECT pgcomply.inspect('jane@example.com');

-- 2. Export for data portability (Article 20)
SELECT pgcomply.export_user_data('jane@example.com', 'json');
-- Send this JSON to Jane

-- 3. Delete everything (Article 17)
SELECT pgcomply.forget('jane@example.com');

-- 4. Prove it's gone
SELECT * FROM pgcomply.verify_forget('jane@example.com');

Total time: under 30 seconds. Without automation, this takes 1-4 hours per request, and you'll miss a table.

The B2B Sales Question

Enterprise customers will ask about your data handling before signing. Common questions during sales due diligence:

| Question | Without pgcomply | With pgcomply | |----------|-----------------|---------------| | "Can you delete our data on termination?" | "We think so, let me check with engineering" | SELECT pgcomply.forget('tenant-xyz'); — done, verified, audited | | "Where is our PII stored?" | "Let me ask the team" | SELECT * FROM pgcomply.classification_map(); — full inventory | | "Do you have an audit trail?" | "We have application logs" | SELECT pgcomply.verify_audit(); — cryptographically verified | | "How do you handle breach notification?" | "We'd figure it out" | SELECT pgcomply.report_breach(...) — structured process |

These answers close deals. Vague answers lose them.

Integrating with Your Stack

Next.js / Node.js

// api/gdpr/delete/route.ts
import { pool } from '@/lib/db';

export async function POST(req: Request) {
  const { userId } = await req.json();
  
  // Export before deletion (keep copy for 30 days)
  const exportResult = await pool.query(
    'SELECT pgcomply.export_user_data($1, $2)', [userId, 'json']
  );
  
  // Delete all PII
  await pool.query('SELECT pgcomply.forget($1)', [userId]);
  
  // Verify
  const verify = await pool.query(
    'SELECT * FROM pgcomply.verify_forget($1)', [userId]
  );
  
  return Response.json({ deleted: true, verification: verify.rows });
}

Django / Python

# views.py
from django.db import connection

def handle_deletion_request(request, user_id):
    with connection.cursor() as cursor:
        cursor.execute("SELECT pgcomply.forget(%s)", [user_id])
        cursor.execute("SELECT * FROM pgcomply.verify_forget(%s)", [user_id])
        verification = cursor.fetchall()
    
    return JsonResponse({'deleted': True, 'verified': len(verification) == 0})

Summary

Start with quick_setup() on day one. It takes 2 seconds and gives you the five pillars. Then add masking, consent, and monitoring as you grow. Compliance scales with your product — do not over-engineer it at the start, but do not ignore it either.

Frequently Asked Questions

When does a SaaS startup need to worry about GDPR?
From day one if you have any EU users. GDPR applies to any organization processing personal data of EU residents, regardless of company size or location. The penalties are up to 4% of global revenue or 20 million EUR — but for startups, the real risk is losing a B2B deal because you cannot answer compliance questions.
What is the biggest compliance risk for early-stage SaaS?
Inability to handle a deletion request. If a user emails asking you to delete their data and you cannot do it reliably within 30 days, that is a GDPR violation. This is the most common complaint filed with DPAs and the easiest to prevent with a PII registry and forget() function.

Related Articles