/
opt
/
mawid
/
apps
/
api
/
src
/
patients
/
/opt/mawid/apps/api/src/patients
mkdir
upload
Name
Size
Mode
Actions
patients.controller.ts
1462
0644
edit
dl
rm
patients.gdpr.spec.ts
4139
0644
edit
dl
rm
patients.module.ts
269
0644
edit
dl
rm
patients.service.ts
4266
0644
edit
dl
rm
Edit:
/opt/mawid/apps/api/src/patients/patients.gdpr.spec.ts
(4139B)
/** * KVKK/GDPR endpoints (PROJECT_PLAN Phase 7 task 4): export returns everything * we hold; delete-on-request removes every row keyed to the patient. * Requires docker-compose postgres. */ import { PrismaService } from '../prisma/prisma.service'; import { PatientsService } from './patients.service'; process.env.DATABASE_URL ??= 'postgresql://mawid:mawid@localhost:5432/mawid'; describe('Patients GDPR', () => { const prisma = new PrismaService(); const service = new PatientsService(prisma); let clinicId: string; let patientId: string; let appointmentId: string; let conversationId: string; beforeAll(async () => { const clinic = await prisma.clinic.create({ data: { name: `gdpr-e2e-${Date.now()}`, phone: '+900000000094' }, }); clinicId = clinic.id; const svc = await prisma.service.create({ data: { clinicId, name: { ar: 'x', tr: 'x', en: 'x' }, durationMinutes: 30 }, }); const staff = await prisma.staff.create({ data: { clinicId, name: 'Dr. G' } }); const patient = await prisma.patient.create({ data: { clinicId, waPhone: `+90593${Date.now().toString().slice(-7)}`, name: 'GDPR Patient', notes: 'sensitive note', }, }); patientId = patient.id; const startsAt = new Date(Date.now() + 48 * 3600_000); const appointment = await prisma.appointment.create({ data: { clinicId, patientId, staffId: staff.id, serviceId: svc.id, startsAt, endsAt: new Date(startsAt.getTime() + 30 * 60_000), status: 'pending', source: 'whatsapp', }, }); appointmentId = appointment.id; await prisma.reminderJob.create({ data: { appointmentId, kind: 'h24', scheduledFor: new Date(startsAt.getTime() - 24 * 3600_000) }, }); const entry = await prisma.waitlistEntry.create({ data: { clinicId, patientId, serviceId: svc.id, preferredWindow: {} }, }); await prisma.slotHold.create({ data: { clinicId, waitlistEntryId: entry.id, staffId: staff.id, serviceId: svc.id, startsAt, endsAt: new Date(startsAt.getTime() + 30 * 60_000), expiresAt: new Date(Date.now() + 20 * 60_000), }, }); const conversation = await prisma.conversation.create({ data: { clinicId, patientId } }); conversationId = conversation.id; await prisma.message.create({ data: { conversationId, direction: 'inbound', type: 'text', body: 'merhaba gdpr' }, }); }); afterAll(async () => { await prisma.clinic.delete({ where: { id: clinicId } }).catch(() => {}); await prisma.$disconnect(); }); it('export returns the patient with appointments, waitlist and full transcripts', async () => { const data = await service.exportData(clinicId, patientId); expect(data.patient.name).toBe('GDPR Patient'); expect(data.patient.notes).toBe('sensitive note'); expect(data.appointments).toHaveLength(1); expect(data.waitlistEntries).toHaveLength(1); expect(data.conversations).toHaveLength(1); expect(data.conversations[0].messages[0].body).toBe('merhaba gdpr'); }); it('delete-on-request removes every row keyed to the patient and audits without PII', async () => { const result = await service.deleteData(clinicId, patientId, 'owner:test'); expect(result.deleted).toBe(true); expect(await prisma.patient.findUnique({ where: { id: patientId } })).toBeNull(); expect(await prisma.appointment.count({ where: { patientId } })).toBe(0); expect(await prisma.reminderJob.count({ where: { appointmentId } })).toBe(0); expect(await prisma.waitlistEntry.count({ where: { patientId } })).toBe(0); expect(await prisma.conversation.count({ where: { patientId } })).toBe(0); expect(await prisma.message.count({ where: { conversationId } })).toBe(0); const audit = await prisma.auditLog.findFirst({ where: { clinicId, action: 'patient:data_deleted' }, }); expect(audit).not.toBeNull(); expect(JSON.stringify(audit!.meta)).not.toContain('GDPR Patient'); // no PII in audit }); });
Save
cmd:
run