AfricanComplex — Platform Operations Policy
INTERNAL DOCUMENT — NOT CUSTOMER-FACING
This policy governs internal platform operations, data lifecycle, and
administrative procedures. It is the source of truth for developers and
operations staff on retention, storage, security, and incident handling.
Last Updated: [DATE]
Owner: Engineering / Operations
1. Purpose
This document defines internal operational rules for the AfricanComplex platform and OrbitApex delivery service. It ensures that development, deployment, and operational practices align with the commitments made in our legal documents (Privacy Policy, Terms of Service, Merchant Agreement, Driver Agreement).
2. Data Retention Schedule
All retention periods must match the Privacy Policy. If a conflict exists, the Privacy Policy governs and this document must be updated.
2.1 User Data
| Data Type |
Retention |
Storage |
Deletion Method |
| Account information |
Active + 3 years |
Neon (Postgres) |
Anonymize, then hard delete |
| Customer order history |
7 years |
Neon |
Anonymize PII, retain order records |
| Merchant store data |
Active + 3 years |
Neon |
Archive, then anonymize |
| Driver profile data |
Active + 3 years |
Neon |
Anonymize, then hard delete |
2.2 Financial Data
| Data Type |
Retention |
Storage |
Deletion Method |
| Payment records |
7 years |
Neon + Stripe |
Retain (tax/financial compliance) |
| Merchant payout records |
7 years |
Neon + Stripe |
Retain |
| Driver earning records |
7 years |
Neon + Stripe |
Retain |
| Subscription billing records |
7 years |
Neon + Stripe |
Retain |
| Refund records |
7 years |
Neon + Stripe |
Retain |
2.3 Compliance Data
| Data Type |
Retention |
Storage |
Deletion Method |
| Driver SSN (encrypted) |
Active + 7 years |
Neon (AES-256-GCM) |
Secure delete (overwrite + delete) |
| Driver W-9 forms |
Active + 7 years |
Cloudflare R2 |
Delete from R2 |
| Background check results |
Active + 1 year |
Neon |
Hard delete |
| Audit logs |
7 years |
Neon |
Retain (compliance) |
2.4 Operational Data
| Data Type |
Retention |
Storage |
Deletion Method |
| Driver location (delivery) |
90 days |
Neon |
Hard delete |
| Push notification tokens |
Until deregistered |
Neon |
Hard delete on deregister |
| Support tickets |
3 years after resolution |
Neon |
Anonymize |
| Support attachments |
3 years after resolution |
Cloudflare R2 |
Delete from R2 |
3. Cloudflare R2 Storage Lifecycle
3.1 Buckets
| Bucket / Prefix |
Content |
Access |
/products/ |
Product images |
Public (CDN) |
/stores/ |
Store logos, banners |
Public (CDN) |
/profiles/ |
User profile photos |
Public (CDN) |
/drivers/documents/ |
License, insurance, registration |
Private (signed URLs, 15min expiry) |
/drivers/vehicles/ |
Vehicle photos |
Private (signed URLs) |
/deliveries/ |
Delivery proof photos |
Private (signed URLs) |
/refunds/ |
Refund evidence photos |
Private (signed URLs) |
/support/ |
Support ticket attachments |
Private (signed URLs) |
3.2 Signed URL Policy
- All private files accessed via signed URLs only
- Signed URL expiry: 15 minutes (900 seconds)
- Signed URLs generated server-side, never exposed in client code
- No direct public access to private prefixes
3.3 Upload Limits
| File Type |
Max Size |
Allowed MIME Types |
| Product images |
10 MB |
image/jpeg, image/png, image/webp |
| Profile photos |
5 MB |
image/jpeg, image/png |
| Driver documents |
10 MB |
image/jpeg, image/png, application/pdf |
| Delivery photos |
10 MB |
image/jpeg, image/png |
| Support attachments |
10 MB |
image/jpeg, image/png, application/pdf |
3.4 Retention and Cleanup
R2 cleanup cron runs weekly. Deletes files whose associated database records have exceeded retention:
| Prefix |
Retention |
Trigger |
/drivers/documents/ |
Driver active + 3 years |
Driver deactivation + 3yr |
/deliveries/ |
90 days after delivery |
delivery.delivered_at + 90d |
/refunds/ |
3 years after resolution |
refund.resolved_at + 3yr |
/support/ |
3 years after resolution |
ticket.resolved_at + 3yr |
/products/ |
When product hard-deleted |
product deletion event |
/profiles/ |
When account deleted |
account deletion event |
4. Encryption Standards
4.1 In Transit
- All API traffic: TLS 1.2+ (enforced by Cloudflare and Railway)
- All database connections: SSL required (Neon enforces this)
- Mobile app API calls: HTTPS only (certificate pinning recommended post-MVP)
4.2 At Rest
- Database: Neon provides encryption at rest by default
- SSN field: Application-level AES-256-GCM encryption before database storage
- R2: Cloudflare provides encryption at rest by default
- Encryption key stored in environment variable
ENCRYPTION_KEY, never in code
4.3 Key Management
ENCRYPTION_KEY: 32-byte key, base64 encoded, generated via openssl rand -base64 32
- Stored in Railway environment variables (not in repo, not in
.env files committed to git)
- Key rotation procedure: [TO BE DEFINED — requires re-encryption migration]
5. Admin Access Controls
5.1 Role Hierarchy
SUPER_ADMIN → full system access
└── ADMIN → platform management, approvals, refunds
└── SUPPORT_AGENT → tickets, basic dispute resolution
5.2 Access Rules
| Action |
Required Role |
2FA Required |
| View audit logs |
ADMIN+ |
Yes |
| Approve/reject merchants |
ADMIN+ |
Yes |
| Approve/reject drivers |
ADMIN+ |
Yes |
| Process refunds |
ADMIN+ |
Yes |
| Manage service areas |
SUPER_ADMIN |
Yes |
| Manage platform settings |
SUPER_ADMIN |
Yes |
| Manage user roles |
SUPER_ADMIN |
Yes |
| Database admin access |
SUPER_ADMIN |
Yes |
| Assign support tickets |
SUPPORT_AGENT+ |
No |
5.3 Audit Logging
Every admin action is logged to audit_logs with:
- Admin user ID
- Action type (enum)
- Target type and ID
- JSON details (before/after state where applicable)
- Timestamp
Audit logs are immutable. No admin can delete or modify audit log entries.
5.4 Admin Access Review
- Quarterly: Review all ADMIN and SUPER_ADMIN accounts
- Remove access for inactive admins (no login in 90 days)
- Verify 2FA is enabled for all elevated roles
- Document review in internal records
6. Incident Response
6.1 Severity Levels
| Level |
Definition |
Response Time |
| P0 — Critical |
Platform down, data breach, payment processing failure |
Immediate (within 15 minutes) |
| P1 — High |
Major feature broken, security vulnerability, payout failure |
Within 1 hour |
| P2 — Medium |
Non-critical feature broken, performance degradation |
Within 4 hours |
| P3 — Low |
Minor bug, cosmetic issue |
Next business day |
6.2 Data Breach Response
If a data breach is suspected or confirmed:
- Contain — Identify and isolate the affected system
- Assess — Determine what data was exposed and how many users affected
- Notify — Alert SUPER_ADMIN and legal counsel immediately
- Remediate — Fix the vulnerability
- Communicate — Notify affected users within 72 hours (or as required by applicable law)
- Document — Create incident report with timeline, impact, and remediation
- Review — Post-incident review within 7 days
[ATTORNEY NOTE: State-specific breach notification timelines vary. California requires notification "in the most expedient time possible." Other states have specific day counts. Verify requirements.]
6.3 Payment Incident Response
If Stripe payout discrepancies are detected:
- Pause affected transfers
- Run reconciliation check (see
docs/finance-reconciliation.md)
- Contact Stripe support if platform-side reconciliation doesn't resolve
- Document resolution in audit log
7. Backup and Recovery
7.1 Database Backups
- Provider: Neon handles automated backups
- Frequency: Continuous (point-in-time recovery)
- Retention: Per Neon plan (Pro: 7 days point-in-time, 30 days history)
- Recovery: Restore to any point within retention window via Neon dashboard
7.2 R2 Storage
- Backups: Cloudflare R2 provides 99.999999999% durability (11 nines)
- No separate backup required for R2 objects at MVP scale
- Critical files (driver documents, delivery proofs): consider cross-region replication post-MVP
7.3 Application Code
- Source: GitHub repository (main branch protected)
- Deployment: Railway auto-deploys from main
- Rollback: Railway supports instant rollback to previous deployment
8. Environment Management
8.1 Environments
| Environment |
Purpose |
Database |
Deployed To |
| Local |
Development |
Docker Compose (local Postgres) |
localhost |
| Preview |
PR review |
Neon branch database |
Railway preview |
| Staging |
Pre-production testing |
Neon staging branch |
Railway staging |
| Production |
Live platform |
Neon production |
Railway production |
8.2 Secret Management
- All secrets stored in Railway environment variables (production)
- Local development uses
.env.local (git-ignored)
- Never commit secrets to the repository
.env.example contains variable names only (no values)
- Stripe test keys for development, live keys for production only
8.3 Environment Variable Validation
All environment variables validated at application startup via Zod schema (packages/shared/env.ts). Missing or malformed variables cause immediate startup failure with clear error messages.
9. Deployment Procedures
9.1 Standard Deployment
- Feature branch → PR against
develop
- CI passes (lint, type-check, tests, Prisma validate)
- Code review + approval
- Squash merge into
develop
develop → main via release PR (weekly or milestone-based)
- Railway auto-deploys from
main
9.2 Database Migrations
- Create migration:
prisma migrate dev --name description
- Review generated SQL
- Test migration on Neon branch database
- Include migration in PR
- Migration runs automatically on deploy via
prisma migrate deploy
9.3 Rollback
- Application: Railway instant rollback (one click)
- Database: Migrations are forward-only. If a migration must be reversed, create a new migration that undoes the change. Never manually edit the database in production.
10. Monitoring and Alerting
10.1 Application Monitoring
| Tool |
Purpose |
| Sentry |
Error tracking and crash reporting |
| Railway metrics |
CPU, memory, request volume |
| Neon metrics |
Database performance, connection count |
10.2 Alerts
| Condition |
Severity |
Notify |
| Application error rate > 5% |
P1 |
Engineering team |
| API response time p95 > 2s |
P2 |
Engineering team |
| Database connection pool exhausted |
P1 |
Engineering team |
| Stripe webhook failures |
P1 |
Engineering team |
| Payout discrepancy > $1.00 |
P1 |
Engineering + Finance |
| Failed login attempts > 100/hour |
P2 |
Security |
11. Document History
| Date |
Change |
Author |
| [DATE] |
Initial draft |
[AUTHOR] |