416 lines
11 KiB
Markdown
416 lines
11 KiB
Markdown
|
|
# Customer Data Management (GDPR)
|
||
|
|
|
||
|
|
This document covers procedures for handling customer data in compliance with GDPR and data protection regulations.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Data Storage Overview
|
||
|
|
|
||
|
|
Customer data is stored across multiple systems:
|
||
|
|
|
||
|
|
| System | Data Stored | Retention | Notes |
|
||
|
|
| ----------------------- | ----------------------------------------------------- | --------------------------- | ---------------------------- |
|
||
|
|
| **Portal (PostgreSQL)** | User accounts, ID mappings, audit logs, notifications | Active account lifetime | Auth data only |
|
||
|
|
| **WHMCS** | Billing, invoices, payment methods, addresses | Legal requirement (7 years) | System of record for billing |
|
||
|
|
| **Salesforce** | CRM data, orders, cases, contacts | Business records | System of record for CRM |
|
||
|
|
| **Redis** | Sessions, cache, rate limits | TTL-based (minutes to days) | Temporary data |
|
||
|
|
|
||
|
|
### Portal Database Tables with PII
|
||
|
|
|
||
|
|
| Table | PII Fields | Purpose |
|
||
|
|
| ---------------------------- | ------------------------------------ | -------------------- |
|
||
|
|
| `users` | `email`, `passwordHash`, `mfaSecret` | Authentication |
|
||
|
|
| `id_mappings` | Links to WHMCS/Salesforce IDs | Identity federation |
|
||
|
|
| `audit_logs` | `ipAddress`, `userAgent`, `userId` | Security audit trail |
|
||
|
|
| `residence_card_submissions` | Document images | ID verification |
|
||
|
|
| `notifications` | User notifications | In-app messaging |
|
||
|
|
| `sim_call_history_*` | Phone numbers, call details | Usage records |
|
||
|
|
| `sim_sms_history` | Phone numbers, SMS details | Usage records |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Data Subject Rights
|
||
|
|
|
||
|
|
Under GDPR, customers have the following rights:
|
||
|
|
|
||
|
|
| Right | Portal Support | Notes |
|
||
|
|
| ---------------------- | ------------------ | ------------------------- |
|
||
|
|
| Right of Access | Manual export | See Data Export section |
|
||
|
|
| Right to Rectification | WHMCS self-service | Customer updates in WHMCS |
|
||
|
|
| Right to Erasure | Manual process | See Data Deletion section |
|
||
|
|
| Right to Portability | Manual export | See Data Export section |
|
||
|
|
| Right to Object | Manual process | Opt-out of processing |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Data Deletion Procedures
|
||
|
|
|
||
|
|
### Overview
|
||
|
|
|
||
|
|
Complete customer data deletion requires coordination across all systems:
|
||
|
|
|
||
|
|
1. Portal database deletion
|
||
|
|
2. WHMCS account handling
|
||
|
|
3. Salesforce record handling
|
||
|
|
4. Redis cache clearing
|
||
|
|
5. Audit trail retention
|
||
|
|
|
||
|
|
### Pre-Deletion Checklist
|
||
|
|
|
||
|
|
- [ ] Verify customer identity (authentication or CS verification)
|
||
|
|
- [ ] Check for active subscriptions (must be cancelled first)
|
||
|
|
- [ ] Check for unpaid invoices (must be settled first)
|
||
|
|
- [ ] Check legal retention requirements (invoices, tax records)
|
||
|
|
- [ ] Document the deletion request with timestamp
|
||
|
|
|
||
|
|
### Step 1: Portal Database Deletion
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- 1. Get user information
|
||
|
|
SELECT u.id, u.email, im.whmcs_client_id, im.sf_account_id
|
||
|
|
FROM users u
|
||
|
|
LEFT JOIN id_mappings im ON u.id = im.user_id
|
||
|
|
WHERE u.email = 'customer@example.com';
|
||
|
|
|
||
|
|
-- 2. Delete notifications
|
||
|
|
DELETE FROM notifications WHERE user_id = '<user_id>';
|
||
|
|
|
||
|
|
-- 3. Delete residence card submissions
|
||
|
|
DELETE FROM residence_card_submissions WHERE user_id = '<user_id>';
|
||
|
|
|
||
|
|
-- 4. Delete SIM usage data (if applicable)
|
||
|
|
-- Note: Check if SIM account is linked to this user first
|
||
|
|
DELETE FROM sim_usage_daily WHERE account IN (
|
||
|
|
SELECT account FROM sim_voice_options WHERE account = '<sim_account>'
|
||
|
|
);
|
||
|
|
DELETE FROM sim_call_history_domestic WHERE account = '<sim_account>';
|
||
|
|
DELETE FROM sim_call_history_international WHERE account = '<sim_account>';
|
||
|
|
DELETE FROM sim_sms_history WHERE account = '<sim_account>';
|
||
|
|
DELETE FROM sim_voice_options WHERE account = '<sim_account>';
|
||
|
|
|
||
|
|
-- 5. Delete ID mapping (cascades from user deletion)
|
||
|
|
-- The id_mappings table has onDelete: Cascade
|
||
|
|
|
||
|
|
-- 6. Delete user (cascades audit_logs user reference to NULL, deletes id_mapping)
|
||
|
|
DELETE FROM users WHERE id = '<user_id>';
|
||
|
|
```
|
||
|
|
|
||
|
|
**Using the Mappings Service:**
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// Delete mapping programmatically (clears cache too)
|
||
|
|
await mappingsService.deleteMapping(userId);
|
||
|
|
```
|
||
|
|
|
||
|
|
### Step 2: Audit Log Handling
|
||
|
|
|
||
|
|
Audit logs may need to be retained for security compliance. Options:
|
||
|
|
|
||
|
|
**Option A: Anonymize (Recommended)**
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- Anonymize audit logs (keeps security trail, removes PII)
|
||
|
|
UPDATE audit_logs
|
||
|
|
SET user_id = NULL,
|
||
|
|
ip_address = 'ANONYMIZED',
|
||
|
|
user_agent = 'ANONYMIZED',
|
||
|
|
details = jsonb_set(
|
||
|
|
COALESCE(details, '{}'::jsonb),
|
||
|
|
'{anonymized}',
|
||
|
|
'true'::jsonb
|
||
|
|
)
|
||
|
|
WHERE user_id = '<user_id>';
|
||
|
|
```
|
||
|
|
|
||
|
|
**Option B: Delete (If Legally Permitted)**
|
||
|
|
|
||
|
|
```sql
|
||
|
|
DELETE FROM audit_logs WHERE user_id = '<user_id>';
|
||
|
|
```
|
||
|
|
|
||
|
|
### Step 3: Redis Cache Clearing
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Clear user-specific cache keys
|
||
|
|
redis-cli KEYS "user:*:<user_id>*" | xargs redis-cli DEL
|
||
|
|
redis-cli KEYS "session:*:<user_id>*" | xargs redis-cli DEL
|
||
|
|
redis-cli KEYS "mapping:*:<user_id>*" | xargs redis-cli DEL
|
||
|
|
|
||
|
|
# Clear refresh token families
|
||
|
|
redis-cli KEYS "refresh:user:<user_id>*" | xargs redis-cli DEL
|
||
|
|
redis-cli KEYS "refresh:family:*" | xargs redis-cli DEL # May need filtering
|
||
|
|
|
||
|
|
# Clear rate limit records
|
||
|
|
redis-cli KEYS "auth-login:*" | xargs redis-cli DEL # Clears by IP, not user
|
||
|
|
```
|
||
|
|
|
||
|
|
### Step 4: WHMCS Account Handling
|
||
|
|
|
||
|
|
WHMCS does not support full account deletion. Options:
|
||
|
|
|
||
|
|
**Option A: Close Account (Recommended)**
|
||
|
|
|
||
|
|
1. Cancel all active services
|
||
|
|
2. Set account status to "Closed"
|
||
|
|
3. Anonymize personal fields via WHMCS Admin
|
||
|
|
4. Document closure date
|
||
|
|
|
||
|
|
**Option B: Anonymize via API**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Update client to anonymized data
|
||
|
|
curl -X POST "$WHMCS_API_URL" \
|
||
|
|
-d "identifier=$WHMCS_API_IDENTIFIER" \
|
||
|
|
-d "secret=$WHMCS_API_SECRET" \
|
||
|
|
-d "action=UpdateClient" \
|
||
|
|
-d "clientid=<whmcs_client_id>" \
|
||
|
|
-d "firstname=Deleted" \
|
||
|
|
-d "lastname=User" \
|
||
|
|
-d "email=deleted_<whmcs_client_id>@deleted.local" \
|
||
|
|
-d "address1=Deleted" \
|
||
|
|
-d "city=Deleted" \
|
||
|
|
-d "state=Deleted" \
|
||
|
|
-d "postcode=000-0000" \
|
||
|
|
-d "phonenumber=000-0000-0000" \
|
||
|
|
-d "status=Closed" \
|
||
|
|
-d "responsetype=json"
|
||
|
|
```
|
||
|
|
|
||
|
|
### Step 5: Salesforce Record Handling
|
||
|
|
|
||
|
|
Salesforce records often have legal retention requirements:
|
||
|
|
|
||
|
|
**For Personal Data:**
|
||
|
|
|
||
|
|
1. Work with Salesforce Admin
|
||
|
|
2. Consider anonymization vs deletion
|
||
|
|
3. Check integration impact (linked Orders, Cases)
|
||
|
|
|
||
|
|
**Anonymization Approach:**
|
||
|
|
|
||
|
|
- Update Account name to "Deleted Account - [ID]"
|
||
|
|
- Clear personal fields (phone, address if not needed)
|
||
|
|
- Keep transactional records with anonymized references
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Data Export Procedures
|
||
|
|
|
||
|
|
### Customer Data Export Request
|
||
|
|
|
||
|
|
When a customer requests their data:
|
||
|
|
|
||
|
|
#### 1. Portal Data Export
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- Export user data
|
||
|
|
SELECT
|
||
|
|
u.id,
|
||
|
|
u.email,
|
||
|
|
u.email_verified,
|
||
|
|
u.created_at,
|
||
|
|
u.last_login_at,
|
||
|
|
im.whmcs_client_id,
|
||
|
|
im.sf_account_id
|
||
|
|
FROM users u
|
||
|
|
LEFT JOIN id_mappings im ON u.id = im.user_id
|
||
|
|
WHERE u.email = 'customer@example.com';
|
||
|
|
|
||
|
|
-- Export audit log (security events)
|
||
|
|
SELECT
|
||
|
|
action,
|
||
|
|
resource,
|
||
|
|
success,
|
||
|
|
created_at
|
||
|
|
FROM audit_logs
|
||
|
|
WHERE user_id = '<user_id>'
|
||
|
|
ORDER BY created_at DESC;
|
||
|
|
|
||
|
|
-- Export notifications
|
||
|
|
SELECT
|
||
|
|
type,
|
||
|
|
title,
|
||
|
|
message,
|
||
|
|
read,
|
||
|
|
created_at
|
||
|
|
FROM notifications
|
||
|
|
WHERE user_id = '<user_id>'
|
||
|
|
ORDER BY created_at DESC;
|
||
|
|
|
||
|
|
-- Export SIM usage history (if applicable)
|
||
|
|
SELECT
|
||
|
|
call_date,
|
||
|
|
call_time,
|
||
|
|
called_to,
|
||
|
|
duration_sec,
|
||
|
|
charge_yen
|
||
|
|
FROM sim_call_history_domestic
|
||
|
|
WHERE account = '<sim_account>'
|
||
|
|
ORDER BY call_date DESC;
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 2. WHMCS Data Export
|
||
|
|
|
||
|
|
Request via WHMCS Admin:
|
||
|
|
|
||
|
|
- Client Details
|
||
|
|
- Invoices
|
||
|
|
- Services/Subscriptions
|
||
|
|
- Tickets/Support History
|
||
|
|
- Transaction History
|
||
|
|
|
||
|
|
#### 3. Salesforce Data Export
|
||
|
|
|
||
|
|
Request via Salesforce Admin:
|
||
|
|
|
||
|
|
- Account record
|
||
|
|
- Contact record
|
||
|
|
- Order history
|
||
|
|
- Case history
|
||
|
|
- Opportunities
|
||
|
|
|
||
|
|
### Export Format
|
||
|
|
|
||
|
|
Provide data in machine-readable format:
|
||
|
|
|
||
|
|
- JSON for structured data
|
||
|
|
- CSV for tabular data
|
||
|
|
- PDF for documents (invoices)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## PII Handling During Debugging
|
||
|
|
|
||
|
|
### Safe Logging Practices
|
||
|
|
|
||
|
|
The BFF uses Pino with automatic PII redaction. Sensitive fields are sanitized:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"email": "cust***@example.com",
|
||
|
|
"password": "[REDACTED]",
|
||
|
|
"token": "[REDACTED]",
|
||
|
|
"authorization": "[REDACTED]"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### What NOT to Log
|
||
|
|
|
||
|
|
- Full email addresses (use masked version)
|
||
|
|
- Passwords or password hashes
|
||
|
|
- JWT tokens
|
||
|
|
- API keys or secrets
|
||
|
|
- Credit card numbers
|
||
|
|
- Full phone numbers
|
||
|
|
- Full addresses
|
||
|
|
- ID document contents
|
||
|
|
|
||
|
|
### Safe Debug Queries
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- Use ID instead of email for lookups
|
||
|
|
SELECT * FROM users WHERE id = '<uuid>';
|
||
|
|
|
||
|
|
-- Mask PII in query results
|
||
|
|
SELECT
|
||
|
|
id,
|
||
|
|
CONCAT(LEFT(email, 3), '***', SUBSTRING(email FROM POSITION('@' IN email))) as masked_email,
|
||
|
|
created_at
|
||
|
|
FROM users
|
||
|
|
WHERE id = '<uuid>';
|
||
|
|
```
|
||
|
|
|
||
|
|
### Production Debugging
|
||
|
|
|
||
|
|
When investigating production issues:
|
||
|
|
|
||
|
|
1. **Use correlation IDs** - Search logs by request ID, not user email
|
||
|
|
2. **Access minimal data** - Only query what's needed
|
||
|
|
3. **Document access** - Note why you accessed customer data
|
||
|
|
4. **Use anonymized exports** - When sharing data for analysis
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Data Retention Policies
|
||
|
|
|
||
|
|
### Recommended Retention Periods
|
||
|
|
|
||
|
|
| Data Type | Retention | Justification |
|
||
|
|
| ------------------------ | ---------- | ---------------------- |
|
||
|
|
| Active user accounts | Indefinite | Active service |
|
||
|
|
| Closed accounts (portal) | 30 days | Grace period |
|
||
|
|
| Audit logs | 2 years | Security compliance |
|
||
|
|
| Session data (Redis) | 24 hours | Active sessions |
|
||
|
|
| Rate limit data | 15 minutes | Operational |
|
||
|
|
| Invoices | 7 years | Tax/legal requirement |
|
||
|
|
| Support cases | 5 years | Service history |
|
||
|
|
| Call/SMS history | 6 months | Billing reconciliation |
|
||
|
|
|
||
|
|
### Automated Cleanup
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- Delete expired notifications (30 days after expiry)
|
||
|
|
DELETE FROM notifications
|
||
|
|
WHERE expires_at < NOW() - INTERVAL '30 days';
|
||
|
|
|
||
|
|
-- Anonymize old audit logs (over 2 years)
|
||
|
|
UPDATE audit_logs
|
||
|
|
SET ip_address = 'EXPIRED',
|
||
|
|
user_agent = 'EXPIRED'
|
||
|
|
WHERE created_at < NOW() - INTERVAL '2 years'
|
||
|
|
AND ip_address != 'EXPIRED';
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Compliance Checklist
|
||
|
|
|
||
|
|
### Monthly Review
|
||
|
|
|
||
|
|
- [ ] Review data access logs for unusual patterns
|
||
|
|
- [ ] Verify automated cleanup jobs are running
|
||
|
|
- [ ] Check for pending deletion requests
|
||
|
|
- [ ] Review new data collection points
|
||
|
|
|
||
|
|
### Quarterly Review
|
||
|
|
|
||
|
|
- [ ] Audit third-party data sharing
|
||
|
|
- [ ] Review retention policies
|
||
|
|
- [ ] Update data inventory if schema changed
|
||
|
|
- [ ] Staff training on data handling
|
||
|
|
|
||
|
|
### Annual Review
|
||
|
|
|
||
|
|
- [ ] Full data protection impact assessment
|
||
|
|
- [ ] Policy review and updates
|
||
|
|
- [ ] Vendor compliance verification
|
||
|
|
- [ ] Documentation updates
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Emergency Data Breach Response
|
||
|
|
|
||
|
|
If a data breach is suspected:
|
||
|
|
|
||
|
|
1. **Contain** - Isolate affected systems
|
||
|
|
2. **Assess** - Determine scope and data exposed
|
||
|
|
3. **Notify** - Inform DPO/legal within 24 hours
|
||
|
|
4. **Report** - GDPR requires notification within 72 hours
|
||
|
|
5. **Remediate** - Fix vulnerability and prevent recurrence
|
||
|
|
6. **Document** - Full incident report
|
||
|
|
|
||
|
|
See [Incident Response](./incident-response.md) for general incident procedures.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Related Documents
|
||
|
|
|
||
|
|
- [Incident Response](./incident-response.md)
|
||
|
|
- [Database Operations](./database-operations.md)
|
||
|
|
- [Logging Guide](./logging.md)
|
||
|
|
- [Security Monitoring](./security-monitoring.md)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Last Updated:** December 2025
|