Security Architecture¶
Comprehensive security design for Tuff Flips SaaS Platform
Security Overview¶
graph TB
subgraph "Security Layers"
WAF[Cloudflare WAF]
Auth[Authentication Layer]
Authz[Authorization Layer]
Data[Data Layer Security]
Infra[Infrastructure Security]
end
WAF --> Auth
Auth --> Authz
Authz --> Data
Data --> Infra
style WAF fill:#ef4444,color:#fff
style Auth fill:#f97316,color:#fff
style Authz fill:#eab308,color:#000
style Data fill:#22c55e,color:#fff
style Infra fill:#3b82f6,color:#fff
1. Authentication & Identity¶
Authentication Strategy¶
flowchart LR
subgraph "Auth Providers"
Email[Email/Password]
Google[Google OAuth]
Magic[Magic Link]
end
subgraph "Auth Layer"
NextAuth[NextAuth.js]
JWT[JWT Tokens]
Session[Session Store]
end
subgraph "Protected Resources"
API[FastAPI Backend]
DB[(PostgreSQL)]
end
Email --> NextAuth
Google --> NextAuth
Magic --> NextAuth
NextAuth --> JWT
JWT --> Session
Session --> API
API --> DB
style Email fill:#3b82f6,color:#fff
style Google fill:#3b82f6,color:#fff
style Magic fill:#3b82f6,color:#fff
style NextAuth fill:#6366f1,color:#fff
style JWT fill:#6366f1,color:#fff
style Session fill:#6366f1,color:#fff
style API fill:#22c55e,color:#fff
style DB fill:#f97316,color:#fff
Implementation¶
| Component | Technology | Purpose |
|---|---|---|
| Auth Provider | NextAuth.js / Clerk | Social login, email/password |
| Session Storage | Redis | Fast session validation |
| Token Type | JWT (RS256) | Stateless API auth |
| Token Expiry | 15 min access, 7 day refresh | Balance security/UX |
| MFA | TOTP (Authy/Google) | Optional for Pro/Team tiers |
Password Requirements¶
- Minimum 12 characters
- At least 1 uppercase, 1 lowercase, 1 number, 1 special character
- Bcrypt hashing (cost factor 12)
- Rate limiting on login attempts (5 per minute)
- Account lockout after 10 failed attempts
2. Authorization & Access Control¶
Role-Based Access Control (RBAC)¶
erDiagram
USERS ||--|| ROLES : has
ROLES ||--o{ PERMISSIONS : grants
USERS ||--o{ DEALS : owns
USERS ||--o{ PROPERTIES : owns
USERS {
uuid id PK
string role
boolean is_admin
}
ROLES {
string name PK
string description
}
PERMISSIONS {
string role FK
string resource
string action
}
Permission Matrix¶
| Role | Deals | Properties | Portfolio | Team | Admin |
|---|---|---|---|---|---|
| Free | Create 3/mo | View own | - | - | - |
| Solo | Unlimited | Full CRUD | View own | - | - |
| Pro | Unlimited | Full CRUD | Full CRUD | - | - |
| Team Owner | Unlimited | Full CRUD | Full CRUD | Manage | - |
| Team Member | As assigned | As assigned | View | - | - |
| Admin | All | All | All | All | Full |
Row-Level Security (PostgreSQL)¶
-- Enable RLS on deals table
ALTER TABLE deals ENABLE ROW LEVEL SECURITY;
-- Users can only see their own deals
CREATE POLICY user_deals_policy ON deals
FOR ALL
USING (user_id = current_user_id());
-- Team members can see team deals
CREATE POLICY team_deals_policy ON deals
FOR SELECT
USING (
user_id IN (
SELECT user_id FROM team_members
WHERE team_id = current_team_id()
)
);
3. Data Security¶
Encryption¶
graph TB
subgraph "In Transit"
TLS[TLS 1.3]
HSTS[HSTS Headers]
CertPin[Certificate Pinning]
end
subgraph "At Rest"
DBEnc[PostgreSQL TDE]
FileEnc[R2 Encryption]
BackupEnc[Backup Encryption]
end
subgraph "Application"
PII[PII Field Encryption]
Secrets[Secrets Management]
end
style TLS fill:#3b82f6,color:#fff
style HSTS fill:#3b82f6,color:#fff
style CertPin fill:#3b82f6,color:#fff
style DBEnc fill:#22c55e,color:#fff
style FileEnc fill:#22c55e,color:#fff
style BackupEnc fill:#22c55e,color:#fff
style PII fill:#6366f1,color:#fff
style Secrets fill:#6366f1,color:#fff
Encryption Standards¶
| Layer | Standard | Implementation |
|---|---|---|
| Transport | TLS 1.3 | Cloudflare SSL |
| Database | AES-256 | PostgreSQL TDE |
| File Storage | AES-256 | Cloudflare R2 |
| PII Fields | AES-256-GCM | Application-level |
| API Keys | AES-256-GCM | Vault/Secrets Manager |
| Backups | AES-256 | Encrypted before upload |
Sensitive Data Classification¶
| Data Type | Classification | Protection |
|---|---|---|
| Email, Name | PII | Encrypted at rest |
| Financial Data | Sensitive | Encrypted + audit log |
| Deal Numbers | Confidential | Access controlled |
| Credit Scores | Highly Sensitive | Encrypted + MFA required |
| Passwords | Secret | Bcrypt hashed |
| API Keys | Secret | Vault storage |
4. API Security¶
API Security Measures¶
sequenceDiagram
participant Client
participant WAF as Cloudflare WAF
participant Gateway as API Gateway
participant Auth as Auth Service
participant API as FastAPI
Client->>WAF: Request
WAF->>WAF: Rate Limit Check
WAF->>WAF: Bot Detection
WAF->>Gateway: Validated Request
Gateway->>Auth: Verify Token
Auth-->>Gateway: Token Valid
Gateway->>API: Authorized Request
API-->>Client: Response
Security Headers¶
# FastAPI middleware for security headers
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["https://tuffflips.com"],
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "DELETE"],
allow_headers=["*"],
)
@app.middleware("http")
async def add_security_headers(request, call_next):
response = await call_next(request)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-XSS-Protection"] = "1; mode=block"
response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
response.headers["Content-Security-Policy"] = "default-src 'self'"
return response
Rate Limiting¶
| Endpoint Type | Limit | Window |
|---|---|---|
| Auth endpoints | 5 requests | 1 minute |
| API (Free tier) | 100 requests | 1 hour |
| API (Solo tier) | 1,000 requests | 1 hour |
| API (Pro/Team) | 10,000 requests | 1 hour |
| Webhook endpoints | 50 requests | 1 minute |
5. Infrastructure Security¶
Cloud Architecture¶
graph TB
subgraph "Edge (Cloudflare)"
DNS[DNS]
CDN[CDN]
WAF[WAF]
DDoS[DDoS Protection]
end
subgraph "Compute (Vercel/Railway)"
Next[Next.js App]
FastAPI[FastAPI Service]
Workers[Background Workers]
end
subgraph "Data (Managed Services)"
Postgres[(PostgreSQL
Supabase/Neon)] Redis[(Redis
Upstash)] Qdrant[(Qdrant Cloud)] R2[(Cloudflare R2)] end subgraph "Secrets" Vault[Secrets Manager] end DNS --> CDN CDN --> WAF WAF --> DDoS DDoS --> Next DDoS --> FastAPI FastAPI --> Workers Next --> Postgres FastAPI --> Postgres FastAPI --> Redis FastAPI --> Qdrant Next --> R2 FastAPI --> Vault style DNS fill:#ef4444,color:#fff style CDN fill:#ef4444,color:#fff style WAF fill:#ef4444,color:#fff style DDoS fill:#ef4444,color:#fff style Next fill:#3b82f6,color:#fff style FastAPI fill:#3b82f6,color:#fff style Workers fill:#3b82f6,color:#fff style Postgres fill:#22c55e,color:#fff style Redis fill:#22c55e,color:#fff style Qdrant fill:#22c55e,color:#fff style R2 fill:#22c55e,color:#fff style Vault fill:#6366f1,color:#fff
Supabase/Neon)] Redis[(Redis
Upstash)] Qdrant[(Qdrant Cloud)] R2[(Cloudflare R2)] end subgraph "Secrets" Vault[Secrets Manager] end DNS --> CDN CDN --> WAF WAF --> DDoS DDoS --> Next DDoS --> FastAPI FastAPI --> Workers Next --> Postgres FastAPI --> Postgres FastAPI --> Redis FastAPI --> Qdrant Next --> R2 FastAPI --> Vault style DNS fill:#ef4444,color:#fff style CDN fill:#ef4444,color:#fff style WAF fill:#ef4444,color:#fff style DDoS fill:#ef4444,color:#fff style Next fill:#3b82f6,color:#fff style FastAPI fill:#3b82f6,color:#fff style Workers fill:#3b82f6,color:#fff style Postgres fill:#22c55e,color:#fff style Redis fill:#22c55e,color:#fff style Qdrant fill:#22c55e,color:#fff style R2 fill:#22c55e,color:#fff style Vault fill:#6366f1,color:#fff
Infrastructure Security Measures¶
| Component | Security Measure | Implementation |
|---|---|---|
| Cloudflare | WAF, DDoS, Bot | Enterprise rules |
| Vercel | Zero-trust network | Edge functions |
| Database | VPC, Encryption | Supabase/Neon managed |
| Redis | TLS, Auth | Upstash managed |
| Secrets | Rotation, Audit | Doppler/Vault |
6. Compliance & Auditing¶
Audit Logging¶
-- Audit log table
CREATE TABLE audit_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
action VARCHAR(100) NOT NULL,
resource_type VARCHAR(100) NOT NULL,
resource_id UUID,
old_values JSONB,
new_values JSONB,
ip_address INET,
user_agent TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Index for fast queries
CREATE INDEX idx_audit_user ON audit_logs(user_id);
CREATE INDEX idx_audit_resource ON audit_logs(resource_type, resource_id);
CREATE INDEX idx_audit_time ON audit_logs(created_at);
Compliance Checklist¶
| Standard | Requirement | Status |
|---|---|---|
| SOC 2 Type II | Managed services | Via providers |
| GDPR | Data privacy | User consent, deletion |
| CCPA | CA resident rights | Opt-out, access |
| PCI DSS | Payment security | Via Stripe |
Data Retention¶
| Data Type | Retention | Deletion |
|---|---|---|
| User accounts | Until deleted | 30 days grace |
| Deal data | 7 years | Archived then deleted |
| Audit logs | 7 years | Never (legal) |
| Session data | 24 hours | Auto-expire |
| Backups | 90 days | Rolling deletion |
7. Security Implementation Roadmap¶
Development Security¶
| Security Measure | Priority | Phase | Status | Implementation |
|---|---|---|---|---|
| Dependency Scanning | P0 | MVP | Planned | Snyk or GitHub Dependabot |
| Secret Scanning | P0 | MVP | Planned | Pre-commit hooks + git-secrets |
| SAST Pipeline | P1 | Phase 2 | Planned | GitHub Actions + CodeQL |
| Security Code Reviews | P1 | Phase 2 | Planned | PR template checklist |
| Penetration Testing | P2 | Phase 3 | Planned | Annual third-party audit |
Operational Security¶
| Security Measure | Priority | Phase | Status | Implementation |
|---|---|---|---|---|
| Least Privilege Access | P0 | MVP | Planned | Role-based IAM policies |
| Admin MFA | P0 | MVP | Planned | TOTP via Authy/Google Auth |
| Access Reviews | P1 | Phase 2 | Planned | Quarterly audit process |
| Incident Response Plan | P1 | Phase 2 | Planned | Documented runbook |
| Security Monitoring | P1 | Phase 2 | Planned | Sentry + custom alerts |
User Security Features¶
| Feature | Priority | Phase | Status | User Benefit |
|---|---|---|---|---|
| Password Strength Meter | P0 | MVP | Planned | Real-time feedback during signup |
| Breach Notification | P1 | Phase 2 | Planned | Email alert if password exposed |
| Session Management | P1 | Phase 2 | Planned | View/revoke active sessions |
| Login History | P2 | Phase 3 | Planned | See login times, IPs, devices |
| Security Email Alerts | P2 | Phase 3 | Planned | New device, password change alerts |
Security Implementation Timeline¶
gantt
title Security Feature Rollout
dateFormat YYYY-MM
section MVP (P0)
Dependency Scanning :a1, 2026-01, 1M
Secret Scanning :a2, 2026-01, 1M
Admin MFA :a3, 2026-02, 1M
Password Strength Meter :a4, 2026-02, 1M
Least Privilege IAM :a5, 2026-01, 2M
section Phase 2 (P1)
SAST Pipeline :b1, 2026-04, 1M
Security Code Reviews :b2, 2026-04, 1M
Access Reviews :b3, 2026-05, 1M
Incident Response Plan :b4, 2026-05, 1M
Security Monitoring :b5, 2026-05, 1M
Breach Notification :b6, 2026-06, 1M
Session Management :b7, 2026-06, 1M
section Phase 3 (P2)
Penetration Testing :c1, 2026-08, 1M
Login History :c2, 2026-08, 1M
Security Email Alerts :c3, 2026-09, 1M
8. Threat Model¶
graph LR
subgraph "Threats"
T1[Account Takeover]
T2[Data Breach]
T3[API Abuse]
T4[Injection Attacks]
T5[DDoS]
end
subgraph "Mitigations"
M1[MFA + Rate Limit]
M2[Encryption + RLS]
M3[Rate Limit + Auth]
M4[Input Validation + ORM]
M5[Cloudflare + WAF]
end
T1 --> M1
T2 --> M2
T3 --> M3
T4 --> M4
T5 --> M5
style T1 fill:#ef4444,color:#fff
style T2 fill:#ef4444,color:#fff
style T3 fill:#ef4444,color:#fff
style T4 fill:#ef4444,color:#fff
style T5 fill:#ef4444,color:#fff
style M1 fill:#22c55e,color:#fff
style M2 fill:#22c55e,color:#fff
style M3 fill:#22c55e,color:#fff
style M4 fill:#22c55e,color:#fff
style M5 fill:#22c55e,color:#fff
Risk Assessment¶
| Threat | Likelihood | Impact | Mitigation Priority |
|---|---|---|---|
| Account Takeover | Medium | High | P0 |
| SQL Injection | Low | Critical | P0 |
| Data Breach | Low | Critical | P0 |
| DDoS Attack | Medium | Medium | P1 |
| API Abuse | High | Low | P1 |
| Session Hijacking | Low | High | P1 |
See System Design for technical details See Scaling for infrastructure planning