feat: Add kiosk management, artist selection, and schedule management

- Add KiosksManagement component with full CRUD for kiosks
- Add ScheduleManagement for staff schedules with break reminders
- Update booking flow to allow artist selection by customers
- Add staff_services API for assigning services to artists
- Update staff management UI with service assignment dialog
- Add auto-break reminder when schedule >= 8 hours
- Update availability API to filter artists by service
- Add kiosk management to Aperture dashboard
- Clean up ralphy artifacts and logs
This commit is contained in:
Marco Gallegos
2026-01-21 13:02:06 -06:00
parent 24e5af3860
commit d27354fd5a
71 changed files with 3353 additions and 2701 deletions

View File

@@ -1,7 +1,29 @@
import { Resend } from 'resend'
const resend = new Resend(process.env.RESEND_API_KEY!)
/**
* @description Email service integration using Resend API for transactional emails
* @audit BUSINESS RULE: Sends HTML-formatted emails with PDF receipt attachments
* @audit SECURITY: Requires RESEND_API_KEY environment variable for authentication
* @audit PERFORMANCE: Uses Resend SDK for reliable email delivery
* @audit AUDIT: Email send results logged for delivery tracking
*/
/** Resend client instance configured with API key */
const resendClient = new Resend(process.env.RESEND_API_KEY!)
/**
* @description Interface defining data required for receipt email
* @property {string} to - Recipient email address
* @property {string} customerName - Customer's first name for personalization
* @property {string} bookingId - UUID of the booking for receipt generation
* @property {string} serviceName - Name of the booked service
* @property {string} date - Formatted date of the appointment
* @property {string} time - Formatted time of the appointment
* @property {string} location - Name and address of the salon location
* @property {string} staffName - Assigned staff member name
* @property {number} price - Total price of the service in MXN
* @property {string} pdfUrl - URL path to the generated PDF receipt
*/
interface ReceiptEmailData {
to: string
customerName: string
@@ -15,7 +37,16 @@ interface ReceiptEmailData {
pdfUrl: string
}
/** @description Send receipt email to customer */
/**
* @description Sends a receipt confirmation email with PDF attachment to the customer
* @param {ReceiptEmailData} data - Email data including customer details and booking information
* @returns {Promise<{ success: boolean; data?: any; error?: any }>} - Result of email send operation
* @example sendReceiptEmail({ to: 'customer@email.com', customerName: 'Ana', bookingId: '...', serviceName: 'Manicure', date: '2026-01-21', time: '10:00', location: 'ANCHOR:23 Saltillo', staffName: 'Maria', price: 1500, pdfUrl: '/receipts/...' })
* @audit BUSINESS RULE: Sends branded HTML email with ANCHOR:23 styling and Spanish content
* @audit Validate: Attaches PDF receipt with booking ID in filename
* @audit PERFORMANCE: Single API call to Resend with HTML content and attachment
* @audit AUDIT: Email sending logged for customer communication tracking
*/
export async function sendReceiptEmail(data: ReceiptEmailData) {
try {
const emailHtml = `
@@ -75,7 +106,7 @@ export async function sendReceiptEmail(data: ReceiptEmailData) {
</html>
`
const { data: result, error } = await resend.emails.send({
const { data: result, error } = await resendClient.emails.send({
from: 'ANCHOR:23 <noreply@anchor23.mx>',
to: data.to,
subject: 'Confirmación de Reserva - ANCHOR:23',
@@ -99,4 +130,4 @@ export async function sendReceiptEmail(data: ReceiptEmailData) {
console.error('Email service error:', error)
return { success: false, error }
}
}
}