| name | twinmind-data-handling |
| description | Handle data privacy, GDPR compliance, and data retention for TwinMind.
Use when implementing data protection, handling user data requests,
or ensuring compliance with privacy regulations.
Trigger with phrases like "twinmind GDPR", "twinmind data privacy",
"twinmind data retention", "twinmind user data", "twinmind compliance".
|
| allowed-tools | Read, Write, Edit |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
TwinMind Data Handling
Overview
Data privacy, retention, and compliance procedures for TwinMind meeting transcriptions.
Prerequisites
- Understanding of GDPR/CCPA requirements
- TwinMind account with admin access
- Database access for data management
- Legal/compliance team consultation
Data Classification
| Data Type | Classification | Retention | Notes |
|---|
| Audio recordings | Not stored | 0 | TwinMind deletes immediately |
| Transcripts | Sensitive | Configurable | Contains meeting content |
| Summaries | Sensitive | Same as transcript | Derived from transcript |
| Action items | Business | Configurable | May contain PII |
| Speaker data | PII | Same as transcript | Names, voice profiles |
| Usage logs | Internal | 90 days | For debugging |
| Billing data | Business | 7 years | Legal requirement |
Instructions
Step 1: Configure Data Retention Policies
export interface RetentionPolicy {
transcripts: {
defaultDays: number;
maxDays: number;
autoDelete: boolean;
};
summaries: {
defaultDays: number;
linkedToTranscript: boolean;
};
actionItems: {
defaultDays: number;
deleteOnComplete: boolean;
};
userProfiles: {
retainAfterDeletion: number;
};
}
const defaultRetentionPolicy: RetentionPolicy = {
transcripts: {
defaultDays: 90,
maxDays: 365,
autoDelete: true,
},
summaries: {
defaultDays: 90,
linkedToTranscript: true,
},
actionItems: {
defaultDays: 180,
deleteOnComplete: false,
},
userProfiles: {
retainAfterDeletion: 30,
},
};
export async (): <> {
client = ();
client.(, {
: policy..,
: policy..,
: policy..,
});
.();
}
(): <{
: ;
: ;
: ;
}> {
client = ();
policy = ();
cutoffDate = ();
cutoffDate.(cutoffDate.() - policy..);
expiredTranscripts = client.(, {
: {
: cutoffDate.(),
: ,
},
});
transcriptsDeleted = ;
( transcript expiredTranscripts.) {
client.();
transcriptsDeleted++;
}
{
transcriptsDeleted,
: transcriptsDeleted,
: ,
};
}
Step 2: Implement PII Redaction
export interface PIIPattern {
name: string;
pattern: RegExp;
replacement: string;
}
const defaultPIIPatterns: PIIPattern[] = [
{
name: 'SSN',
pattern: /\b\d{3}-\d{2}-\d{4}\b/g,
replacement: '[SSN REDACTED]',
},
{
name: 'Credit Card',
pattern: /\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/g,
replacement: '[CARD REDACTED]',
},
{
name: 'Email',
pattern: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g,
replacement: '[EMAIL REDACTED]',
},
{
name: 'Phone',
pattern: /\b(\+\d{1,2}\s?)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}\b/g,
replacement: '[PHONE REDACTED]',
},
{
name: 'IP Address',
pattern: /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g,
replacement: '[IP REDACTED]',
},
];
export function redactPII(
text: string,
patterns: [] = defaultPIIPatterns
): {
: ;
: <{ : ; : }>;
} {
redactedText = text;
: <{ : ; : }> = [];
( pattern patterns) {
matches = text.(pattern.);
(matches && matches. > ) {
redactedText = redactedText.(pattern., pattern.);
redactions.({ : pattern., : matches. });
}
}
{ redactedText, redactions };
}
(): <> {
client = ();
client.(, {
: ,
: defaultPIIPatterns.( ({
: p.,
: p..,
: p..,
})),
});
}
Step 3: Implement GDPR Data Subject Requests
export interface DataSubjectRequest {
type: 'access' | 'rectification' | 'erasure' | 'portability';
subjectEmail: string;
requestedAt: Date;
deadline: Date;
status: 'pending' | 'in_progress' | 'completed' | 'rejected';
}
export class GDPRHandler {
private client = getTwinMindClient();
async handleAccessRequest(email: string): Promise<{
transcripts: any[];
summaries: any[];
actionItems: any[];
profile: any;
}> {
const [transcripts, profile] = await Promise.all([
this.client.get('/transcripts', {
params: { participant_email: email, : },
}),
..(, { : { email } }),
]);
summaries = [];
actionItems = [];
( transcript transcripts.) {
[summary, actions] = .([
..().( ),
..().( []),
]);
(summary) summaries.(summary.);
actionItems.(...(actions. || []));
}
{
: transcripts.,
summaries,
actionItems,
: profile.,
};
}
(: ): <{
: ;
: ;
}> {
data = .(email);
transcriptsDeleted = ;
( transcript data.) {
..();
transcriptsDeleted++;
}
(data.?.) {
..();
}
{
transcriptsDeleted,
: !!data.?.,
};
}
(: ): <> {
data = .(email);
exportData = {
: ().(),
: email,
: {
: data.,
: data..( ({
: t.,
: t.,
: t.,
: t.,
: t.,
: t.,
})),
: data.,
: data.,
},
};
.(.(exportData, , ));
}
(: <, | >): <> {
: = {
...request,
: (.() + * * * * ),
: ,
};
result = db..(dsr);
({
: ,
: dsr,
});
result.;
}
}
Step 4: Implement Consent Management
export interface ConsentRecord {
userId: string;
purposes: {
transcription: boolean;
aiProcessing: boolean;
storage: boolean;
sharing: boolean;
marketing: boolean;
};
consentedAt: Date;
method: 'explicit' | 'implied';
ipAddress?: string;
version: string;
}
export class ConsentManager {
async recordConsent(
userId: string,
purposes: ConsentRecord['purposes'],
method: 'explicit' | 'implied',
ipAddress?: string
): Promise<void> {
const record: ConsentRecord = {
userId,
purposes,
consentedAt: new Date(),
method,
ipAddress,
version: process.. || ,
};
db..(record);
client = ();
client.(, {
: purposes.,
: purposes.,
: purposes.,
});
}
(: ): < | > {
db..({ userId });
}
(: , : []): <> {
current = .(userId);
(!current) {
();
}
updated = { ...current. };
( purpose purposes) {
updated[purpose keyof updated] = ;
}
.(userId, updated, );
(.(updated).( !v)) {
gdpr = ();
gdpr.(userId);
}
}
(: , : keyof []): <> {
consent = .(userId);
consent?.[purpose] ?? ;
}
}
() {
(: , : , : ) => {
userId = req.?.;
(!userId) {
res.().({ : });
}
consentManager = ();
hasConsent = consentManager.(userId, purpose);
(!hasConsent) {
res.().({
: ,
: purpose,
: ,
});
}
();
};
}
Step 5: Data Anonymization
import crypto from 'crypto';
export interface AnonymizationConfig {
hashSalt: string;
preserveStructure: boolean;
preserveTimestamps: boolean;
}
export function anonymizeTranscript(
transcript: Transcript,
config: AnonymizationConfig
): Transcript {
return {
...transcript,
id: hashId(transcript.id, config.hashSalt),
text: redactPII(transcript.text).redactedText,
speakers: transcript.speakers?.map((speaker, index) => ({
...speaker,
id: hashId(speaker.id, config.hashSalt),
name: `Speaker ${index + 1}`,
})),
segments: transcript.segments?.map(segment => ({
...segment,
speaker_id: hashId(segment. || , config.),
: (segment.).,
})),
};
}
(): {
crypto.(, salt).(id).().(, );
}
(): <[]> {
client = ();
: = {
: process..!,
: ,
: ,
};
transcripts = client.(, {
: {
: dateRange..(),
: dateRange..(),
},
});
transcripts..( (t, config));
}
Output
- Data retention policy configuration
- PII redaction implementation
- GDPR request handlers
- Consent management system
- Data anonymization utilities
Compliance Checklist
## GDPR Compliance Checklist
### Data Processing
- [ ] Lawful basis documented for all processing
- [ ] Data minimization principle applied
- [ ] Purpose limitation enforced
- [ ] Accuracy mechanisms in place
### Data Subject Rights
- [ ] Right to access implemented
- [ ] Right to rectification implemented
- [ ] Right to erasure implemented
- [ ] Right to data portability implemented
- [ ] Right to object implemented
### Security
- [ ] Encryption at rest enabled
- [ ] Encryption in transit (TLS 1.3)
- [ ] Access controls implemented
- [ ] Audit logging enabled
### Documentation
- [ ] Privacy policy updated
- [ ] Data processing records maintained
- [ ] DPA signed with TwinMind
- [ ] DPIA conducted if required
### Breach Response
- [ ] Breach notification procedure documented
- [ ] 72-hour notification capability
- [ ] Incident response team identified
TwinMind Privacy Features
TwinMind provides these built-in privacy protections:
- No audio storage: Audio processed in real-time and immediately deleted
- On-device processing: Option for local transcription (no data sent to cloud)
- Encrypted storage: All transcripts encrypted with user-controlled keys
- Data residency: Choose data storage region (EU, US, APAC)
- Automatic deletion: Configurable retention periods
Error Handling
| Issue | Cause | Solution |
|---|
| DSR deadline missed | Processing delay | Automate DSR handling |
| PII not redacted | Pattern not matched | Update patterns |
| Consent invalid | Version mismatch | Re-request consent |
| Data not deleted | Cascade failure | Verify deletion |
Resources
Next Steps
For enterprise access control, see twinmind-enterprise-rbac.