array_filter([ 'pos' => env('FRONTDESK_API_KEY_POS'), 'crm' => env('FRONTDESK_API_KEY_CRM'), 'care' => env('FRONTDESK_API_KEY_CARE'), 'lab' => env('FRONTDESK_API_KEY_LAB'), ]), 'visitor_types' => [ 'visitor' => 'Visitor', 'contractor' => 'Contractor', 'vendor' => 'Vendor', 'interview_candidate' => 'Interview Candidate', 'delivery' => 'Delivery Personnel', ], 'visit_purposes' => [ 'meeting' => 'Business meeting', 'interview' => 'Job interview', 'delivery' => 'Delivery or pickup', 'maintenance' => 'Maintenance or repairs', 'sales' => 'Sales or vendor visit', 'training' => 'Training or workshop', 'personal' => 'Personal visit', 'other' => 'Other', ], 'visit_statuses' => [ 'scheduled' => 'Scheduled', 'expected' => 'Expected', 'waiting' => 'Waiting', 'checked_in' => 'Checked In', 'checked_out' => 'Checked Out', 'cancelled' => 'Cancelled', 'overdue' => 'Overdue', ], 'watchlist_statuses' => [ 'allowed' => 'Allowed', 'requires_approval' => 'Requires Approval', 'blacklisted' => 'Blacklisted', ], 'audit_actions' => [ 'visit.checked_in' => 'Visit checked in', 'visit.checked_out' => 'Visit checked out', 'visit.awaiting_approval' => 'Visit awaiting approval', 'visit.scheduled' => 'Visit scheduled', 'visit.waiting' => 'Visitor waiting', 'visit.cancelled' => 'Visit cancelled', 'visit.deleted' => 'Visit archived', 'visit.restored' => 'Visit restored', 'visitor.deleted' => 'Visitor archived', 'visitor.restored' => 'Visitor restored', 'watchlist.blocked_attempt' => 'Blocked check-in attempt', 'watchlist.flagged_checkin' => 'Flagged visitor check-in', 'watchlist.entry_created' => 'Watchlist entry added', 'watchlist.entry_removed' => 'Watchlist entry removed', 'badge.expired' => 'Badge expired', 'employee.signed_in' => 'Employee signed in', 'employee.signed_out' => 'Employee signed out', 'employee.stepped_out' => 'Employee stepped out', 'employee.stepped_in' => 'Employee returned', ], 'roles' => [ 'super_admin' => 'Super Administrator', 'org_admin' => 'Organization Administrator', 'branch_admin' => 'Branch Administrator', 'receptionist' => 'Receptionist', 'security_officer' => 'Security Officer', 'host' => 'Host', 'auditor' => 'Auditor', ], 'device_types' => [ 'reception_computer' => 'Reception Computer', 'kiosk' => 'Visitor Kiosk', 'tablet' => 'Tablet', 'badge_printer' => 'Badge Printer', 'qr_scanner' => 'QR Scanner', 'camera' => 'Camera', 'signature_pad' => 'Signature Pad', ], /* | Device types that receive a server-generated token for unattended API/kiosk access. */ 'device_token_types' => ['kiosk', 'badge_printer', 'qr_scanner'], /* | Contextual copy for the register / edit device forms (keyed by device type). */ 'device_registration_hints' => [ 'reception_computer' => 'Tracked for your team only. Staff sign in on this machine — no device token or automatic connection is created.', 'kiosk' => 'A device token is created after registration. Open the kiosk URL on your tablet to run self-service check-in without staff login.', 'tablet' => 'Tracked for inventory. Use Visitor Kiosk if this tablet should run unattended check-in.', 'badge_printer' => 'A device token is created for unattended printing. The printer connects when your print agent sends requests with that token.', 'qr_scanner' => 'A device token is created for unattended scanning. The scanner connects when it calls Frontdesk with that token.', 'camera' => 'Tracked for inventory at this reception desk or branch — no device token is issued.', 'signature_pad' => 'Tracked for inventory at this reception desk or branch — no device token is issued.', ], 'notification_channels' => [ 'email' => 'Email (platform SMTP)', 'sms' => 'SMS', ], 'billing' => [ 'email_cost_ghs' => (float) env('FRONTDESK_EMAIL_COST_GHS', 0.0135), 'sms_cost_per_segment_ghs' => (float) env('FRONTDESK_SMS_COST_PER_SEGMENT_GHS', 0.05), 'sms_segment_length' => (int) env('FRONTDESK_SMS_SEGMENT_LENGTH', 160), ], 'plans' => [ 'free' => [ 'label' => 'Free', 'price_minor' => 0, 'max_branches' => 1, 'max_kiosk_devices' => 1, 'free_emails_per_month' => (int) env('FRONTDESK_FREE_EMAILS_PER_MONTH', 100), 'features' => [ 'check_in', 'hosts', 'badges', 'watchlist', ], ], 'pro' => [ 'label' => 'Pro', 'price_minor' => (int) env('FRONTDESK_PRO_PRICE_MINOR', 10000), 'max_branches' => null, 'max_kiosk_devices' => null, 'free_emails_per_month' => env('FRONTDESK_PRO_FREE_EMAILS_PER_MONTH') !== null ? (int) env('FRONTDESK_PRO_FREE_EMAILS_PER_MONTH') : null, 'features' => [ 'check_in', 'hosts', 'badges', 'watchlist', 'integrations', 'webhooks', 'scheduled_reports', 'custom_badge_templates', ], ], ], 'notification_events' => [ 'visitor_arrived' => 'Visitor arrived (checked in)', 'visitor_checked_out' => 'Visitor checked out', 'visitor_expected' => 'Visitor expected today', 'visitor_waiting' => 'Visitor waiting in reception', 'visit_cancelled' => 'Visit cancelled', 'approval_needed' => 'Approval required', 'watchlist_alert' => 'Watchlist / security alerts', 'badge_expired' => 'Expired badge while checked in', 'employee_overdue_return' => 'Employee overdue to return from step-out', ], 'default_notification_events' => [ 'visitor_arrived' => true, 'visitor_checked_out' => true, 'visitor_expected' => true, 'visitor_waiting' => true, 'visit_cancelled' => true, 'approval_needed' => true, 'watchlist_alert' => true, 'badge_expired' => true, 'employee_overdue_return' => true, ], 'kiosk' => [ 'inactivity_reset_seconds' => (int) env('FRONTDESK_KIOSK_RESET_SECONDS', 120), 'default_visit_duration_minutes' => 60, ], 'employee_presence_statuses' => [ 'off_site' => 'Off site', 'on_site' => 'On site', 'stepped_out' => 'Stepped out', ], 'employee_step_out_reasons' => [ 'lunch' => 'Lunch', 'client_visit' => 'Client / external meeting', 'errand' => 'Bank / errands', 'personal' => 'Personal', 'other' => 'Other', ], 'employee_presence_events' => [ 'sign_in' => 'Sign in', 'sign_out' => 'Sign out', 'step_out' => 'Step out', 'step_in' => 'Return', ], 'badge' => [ 'default_expiry_hours' => 8, 'qr_url_path' => '/q', 'employee_qr_url_path' => '/eq', ], 'default_badge_template' => [ 'show_photo' => true, 'show_qr' => true, 'show_host' => true, 'show_company' => true, 'show_type' => true, 'primary_color' => '#0d9488', 'footer_text' => '', ], 'webhook_events' => [ 'visit.checked_in', 'visit.checked_out', 'visit.awaiting_approval', 'employee.signed_in', 'employee.signed_out', 'employee.stepped_out', 'employee.stepped_in', ], 'integrations' => [ 'care' => 'Ladill Care', 'lab' => 'Ladill Lab', 'pos' => 'Ladill POS', 'crm' => 'Ladill CRM', 'queue' => 'Ladill Queue', ], 'queue' => [ 'api_url' => env('QUEUE_API_URL', 'https://queue.ladill.com/api/v1'), 'api_key' => env('QUEUE_API_KEY_FRONTDESK'), ], 'printers' => [ 'default_driver' => env('FRONTDESK_PRINTER_DRIVER', 'pdf'), 'drivers' => ['pdf', 'zebra', 'brother', 'dymo'], ], /* |-------------------------------------------------------------------------- | Visitor type workflows (Phase 4) |-------------------------------------------------------------------------- | Config-driven fields, badge expiry overrides, and approval requirements. */ 'visitor_type_config' => [ 'visitor' => [ 'requires_approval' => false, 'badge_expiry_hours' => null, 'details_key' => null, 'fields' => [], ], 'contractor' => [ 'requires_approval' => false, 'badge_expiry_hours' => 12, 'details_key' => 'contractor_details', 'fields' => [ ['name' => 'contract_company', 'label' => 'Contract company', 'type' => 'text', 'required' => true], ['name' => 'supervisor', 'label' => 'Site supervisor', 'type' => 'text', 'required' => true], ['name' => 'contract_start', 'label' => 'Contract start', 'type' => 'date', 'required' => false], ['name' => 'contract_end', 'label' => 'Contract end', 'type' => 'date', 'required' => false], ['name' => 'safety_induction_completed', 'label' => 'Safety induction completed', 'type' => 'checkbox', 'required' => true], ['name' => 'insurance_reference', 'label' => 'Insurance reference', 'type' => 'text', 'required' => false], ['name' => 'permit_number', 'label' => 'Permit number', 'type' => 'text', 'required' => false], ['name' => 'equipment_carried', 'label' => 'Equipment carried', 'type' => 'textarea', 'required' => false], ], ], 'delivery' => [ 'requires_approval' => false, 'badge_expiry_hours' => 2, 'details_key' => 'delivery_details', 'fields' => [ ['name' => 'courier_company', 'label' => 'Courier company', 'type' => 'text', 'required' => true], ['name' => 'recipient', 'label' => 'Recipient', 'type' => 'text', 'required' => true], ['name' => 'tracking_number', 'label' => 'Tracking number', 'type' => 'text', 'required' => false], ['name' => 'package_description', 'label' => 'Package description', 'type' => 'text', 'required' => false], ['name' => 'delivery_photo', 'label' => 'Delivery photo', 'type' => 'photo', 'required' => false], ['name' => 'delivery_signature', 'label' => 'Signature', 'type' => 'signature', 'required' => false], ], ], 'vendor' => [ 'requires_approval' => true, 'badge_expiry_hours' => null, 'details_key' => 'contractor_details', 'fields' => [ ['name' => 'vendor_company', 'label' => 'Vendor company', 'type' => 'text', 'required' => true], ['name' => 'service_type', 'label' => 'Service / product', 'type' => 'text', 'required' => true], ['name' => 'purchase_order', 'label' => 'PO number', 'type' => 'text', 'required' => false], ], ], 'interview_candidate' => [ 'requires_approval' => true, 'badge_expiry_hours' => null, 'details_key' => 'contractor_details', 'fields' => [ ['name' => 'position_applied', 'label' => 'Position applied for', 'type' => 'text', 'required' => true], ['name' => 'interviewer', 'label' => 'Interviewer', 'type' => 'text', 'required' => false], ['name' => 'scheduled_interview_at', 'label' => 'Interview time', 'type' => 'datetime-local', 'required' => false], ], ], ], ];