diff --git a/src/lib/server/services/appointment-service.ts b/src/lib/server/services/appointment-service.ts index bbdbe7f..6be65e3 100644 --- a/src/lib/server/services/appointment-service.ts +++ b/src/lib/server/services/appointment-service.ts @@ -489,21 +489,24 @@ export class AppointmentService { /** * Add appointment to existing client tunnel */ - public async addAppointmentToTunnel(appointmentData: { - emailHash: string; - tunnelId: string; - channelId: string; - agentId: string; - appointmentDate: string; - duration: number; - clientEmail: string; - clientLanguage?: string; - encryptedAppointment: { - encryptedPayload: string; - iv: string; - authTag: string; - }; - }): Promise { + public async addAppointmentToTunnel( + appointmentData: { + emailHash: string; + tunnelId: string; + channelId: string; + agentId: string; + appointmentDate: string; + duration: number; + clientEmail: string; + clientLanguage?: string; + encryptedAppointment: { + encryptedPayload: string; + iv: string; + authTag: string; + }; + }, + staffCreated = false, + ): Promise { const log = logger.setContext("AppointmentService"); log.info("Adding appointment to existing tunnel", { @@ -547,8 +550,11 @@ export class AppointmentService { throw new NotFoundError("Active channel not found"); } - const initialStatus = channelResult[0].requiresConfirmation ? "NEW" : "CONFIRMED"; - const requiresConfirmation = channelResult[0].requiresConfirmation || false; + const initialStatus = + channelResult[0].requiresConfirmation && !staffCreated ? "NEW" : "CONFIRMED"; + const requiresConfirmation = staffCreated + ? false + : channelResult[0].requiresConfirmation || false; // Create encrypted appointment const appointmentResult = await db @@ -597,6 +603,7 @@ export class AppointmentService { */ public async createNewClientWithAppointment( clientData: ClientTunnelData, + staffCreated = false, ): Promise { const log = logger.setContext("AppointmentService"); @@ -693,8 +700,11 @@ export class AppointmentService { throw new NotFoundError("Channel not found"); } - const initialStatus = channelResult[0].requiresConfirmation ? "NEW" : "CONFIRMED"; - const requiresConfirmation = channelResult[0].requiresConfirmation || false; + const initialStatus = + channelResult[0].requiresConfirmation && !staffCreated ? "NEW" : "CONFIRMED"; + const requiresConfirmation = staffCreated + ? false + : channelResult[0].requiresConfirmation || false; // 4. Create encrypted appointment const appointmentResult = await tx diff --git a/src/routes/api/tenants/[id]/appointments/staff-create/+server.ts b/src/routes/api/tenants/[id]/appointments/staff-create/+server.ts index 425b280..92e737d 100644 --- a/src/routes/api/tenants/[id]/appointments/staff-create/+server.ts +++ b/src/routes/api/tenants/[id]/appointments/staff-create/+server.ts @@ -321,7 +321,7 @@ export const POST: RequestHandler = async ({ params, request, locals }) => { encryptedAppointment: validatedData.encryptedAppointment, }; - result = await appointmentService.addAppointmentToTunnel(appointmentData); + result = await appointmentService.addAppointmentToTunnel(appointmentData, true); } else { // New client - create tunnel and appointment isNewClient = true; @@ -360,7 +360,7 @@ export const POST: RequestHandler = async ({ params, request, locals }) => { clientEncryptedTunnelKey: validatedData.clientEncryptedTunnelKey, }; - result = await appointmentService.createNewClientWithAppointment(clientData); + result = await appointmentService.createNewClientWithAppointment(clientData, true); // For new clients with email: initiate PIN reset flow if (validatedData.clientEmail && !validatedData.hasNoEmail) { @@ -397,7 +397,7 @@ export const POST: RequestHandler = async ({ params, request, locals }) => { validatedData.channelId, validatedData.clientEmail, validatedData.clientLanguage, - !!result.requiresConfirmation, + false, ); } catch (error) { logger.error("Failed to send appointment notification", { diff --git a/src/routes/api/tenants/[id]/appointments/staff-create/__tests__/staff-create.test.ts b/src/routes/api/tenants/[id]/appointments/staff-create/__tests__/staff-create.test.ts index 082e18f..bb4c1b3 100644 --- a/src/routes/api/tenants/[id]/appointments/staff-create/__tests__/staff-create.test.ts +++ b/src/routes/api/tenants/[id]/appointments/staff-create/__tests__/staff-create.test.ts @@ -102,30 +102,33 @@ describe("POST /api/tenants/[id]/appointments/staff-create", () => { expect(data.id).toBe("appointment-123"); expect(data.isNewClient).toBe(true); expect(data.pinResetToken).toBe("reset-token-123"); - expect(mockAppointmentService.createNewClientWithAppointment).toHaveBeenCalledWith({ - tunnelId: "tunnel-123", - channelId: "channel-123", - agentId: "agent-123", - appointmentDate: "2026-01-15T14:00:00.000Z", - duration: 30, - emailHash, - clientEmail: "test@example.com", - clientLanguage: "de", - clientPublicKey: "public-key", - privateKeyShare: "private-key-share", - encryptedAppointment: { - encryptedPayload: "encrypted-payload", - iv: "iv", - authTag: "auth-tag", - }, - staffKeyShares: [ - { - userId: "staff-123", - encryptedTunnelKey: "encrypted-for-staff", + expect(mockAppointmentService.createNewClientWithAppointment).toHaveBeenCalledWith( + { + tunnelId: "tunnel-123", + channelId: "channel-123", + agentId: "agent-123", + appointmentDate: "2026-01-15T14:00:00.000Z", + duration: 30, + emailHash, + clientEmail: "test@example.com", + clientLanguage: "de", + clientPublicKey: "public-key", + privateKeyShare: "private-key-share", + encryptedAppointment: { + encryptedPayload: "encrypted-payload", + iv: "iv", + authTag: "auth-tag", }, - ], - clientEncryptedTunnelKey: "encrypted-tunnel-key", - }); + staffKeyShares: [ + { + userId: "staff-123", + encryptedTunnelKey: "encrypted-for-staff", + }, + ], + clientEncryptedTunnelKey: "encrypted-tunnel-key", + }, + true, + ); expect(mockPinResetService.createResetToken).toHaveBeenCalledWith(emailHash, 60); }); }); @@ -235,21 +238,24 @@ describe("POST /api/tenants/[id]/appointments/staff-create", () => { expect(data.id).toBe("appointment-789"); expect(data.isNewClient).toBe(false); expect(data.pinResetToken).toBeUndefined(); - expect(mockAppointmentService.addAppointmentToTunnel).toHaveBeenCalledWith({ - emailHash, - tunnelId: "tunnel-789", - channelId: "channel-123", - agentId: "agent-123", - appointmentDate: "2026-01-15T14:00:00.000Z", - duration: 30, - clientEmail: "existing@example.com", - clientLanguage: "de", - encryptedAppointment: { - encryptedPayload: "encrypted-payload", - iv: "iv", - authTag: "auth-tag", + expect(mockAppointmentService.addAppointmentToTunnel).toHaveBeenCalledWith( + { + emailHash, + tunnelId: "tunnel-789", + channelId: "channel-123", + agentId: "agent-123", + appointmentDate: "2026-01-15T14:00:00.000Z", + duration: 30, + clientEmail: "existing@example.com", + clientLanguage: "de", + encryptedAppointment: { + encryptedPayload: "encrypted-payload", + iv: "iv", + authTag: "auth-tag", + }, }, - }); + true, + ); }); }); @@ -468,7 +474,7 @@ describe("POST /api/tenants/[id]/appointments/staff-create", () => { "channel-123", "test@example.com", "de", - true, + false, ); });