Skip to main content

webscheduler-database

WebScheduler database schema and migration rules — all 22 runtime tables (identity, scheduling, availability, settings, notifications, audit, custom fields), canonical relationships, compatibility rules, timezone integrity (UTC storage, display conversion via TimezoneService), migration base requirement, and schema-drift safety. Use whenever you're writing or modifying SQL, queries, migrations, models, or anything that reads/writes `xs_*` tables, or anywhere datetimes are stored or converted. Triggers on phrases like "schema", "table", "column", "migration", "xs_", "foreign key", "relationship", "UTC", "timezone", "TimezoneService", "start_at", "stored_timezone", "MigrationBase", "schema drift", "SQLite", "MariaDB", "MySQL".

Informations de source

Dépôt
niloc95/xscheduler_ci4
Dernière activité de la source
24 juillet 2026 à 12:05
Langue détectée de SKILL.md
anglais
Étoiles
1
Forks
0

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
webscheduler-database
description
WebScheduler database schema and migration rules — all 22 runtime tables (identity, scheduling, availability, settings, notifications, audit, custom fields), canonical relationships, compatibility rules, timezone integrity (UTC storage, display conversion via TimezoneService), migration base requirement, and schema-drift safety. Use whenever you're writing or modifying SQL, queries, migrations, models, or anything that reads/writes `xs_*` tables, or anywhere datetimes are stored or converted. Triggers on phrases like "schema", "table", "column", "migration", "xs_", "foreign key", "relationship", "UTC", "timezone", "TimezoneService", "start_at", "stored_timezone", "MigrationBase", "schema drift", "SQLite", "MariaDB", "MySQL".
# WebScheduler — Database Schema & Migration Rules ## 1. Runtime DB Conventions - **Prefix:** `xs_` - **Runtime DB:** MySQL/MariaDB only - **SQLite is not supported** as runtime DB - Runtime schema is authoritative - Preferred charset/collation for installs: `utf8mb4` / `utf8mb4_unicode_ci` - **Total application tables: 23** ## 2. Table Catalog by Domain ### 2.1 Identity Tables #### `xs_users` Columns: `id`, `name`, `title` (nullable, added 2026-04-23), `email`, `phone`, `password_hash`, `role`, `created_at`, `updated_at`, `color`, `reset_token`, `reset_expires`, `status`, `profile_image`, `bio` (text, nullable, added 2026-04-23), `education` (text, nullable, added 2026-04-23), `qualifications` (text, nullable, added 2026-04-23), `slug` (unique, nullable, added 2026-04-23), `last_login`, `notify_on_appointments` Notes: - `status` is canonical active-state field - `notify_on_appointments` controls provider/staff appointment notices - `slug` is unique per provider; used in public booking URL `/booking/{serviceSlug}/{providerSlug}` - `title`, `bio`, `education`, `qualifications` are public profile fields for provider profile pages #### `xs_user_roles` Columns: `id`, `user_id`, `role`, `created_at` Notes: - **Authoritative role membership table** - Backfilled from `xs_users.role` in migration `2026-04-08-000001_CreateUserRolesTable.php` #### `xs_customers` Columns: `id`, `hash`, `first_name`, `last_name`, `email`, `phone`, `address`, `notes`, `created_at`, `updated_at`, `custom_fields` Notes: - `hash` is 64-char unique slug for public routes - Index `idx_customers_hash` is present - `custom_fields` stores JSON map in text field (legacy; per-appointment custom fields now also stored in `xs_appointment_custom_fields`) - `email` has unique index `idx_customers_email_unique` (added 2026-04-30) ### 2.2 Scheduling Tables #### `xs_services` Columns: `id`, `name`, `slug` (unique, nullable, added 2026-04-23), `description`, `duration_min`, `buffer_before`, `buffer_after`, `price`, `created_at`, `updated_at`, `category_id`, `active` Notes: - `slug` used in public booking URL `/booking/{serviceSlug}` and `/booking/{serviceSlug}/{providerSlug}` #### `xs_categories` Columns: `id`, `name`, `description`, `color`, `created_at`, `updated_at`, `active` #### `xs_appointments` Columns: `id`, `provider_id`, `service_id`, `start_at`, `end_at`, `stored_timezone`, `status`, `notes`, `hash`, `public_token`, `public_token_expires_at`, `created_at`, `updated_at`, `reminder_sent`, `customer_id`, `location_id`, `location_name`, `location_address`, `location_contact`, `delivery_mode`, `video_link`, `payment_status`, `payment_amount`, `payment_reference` Notes: - Customer linkage is `customer_id → xs_customers.id` - **Do not use deprecated appointment `user_id` linkage in new logic** — caught by grep check - `delivery_mode` (`onsite`/`online_zoom`/`online_jitsi`, nullable→treated as `onsite`) — see `scheduling` skill §13 - `payment_status` ENUM (`none`/`pending`/`paid`/`failed`/`refunded`), `payment_amount` DECIMAL(10,2), `payment_reference` — written by `PaymentService` #### `xs_blocked_times` Columns: `id`, `provider_id`, `start_at`, `end_at`, `reason`, `created_at`, `updated_at` ### 2.3 Availability and Location Tables #### `xs_business_hours` Columns: `id`, `provider_id`, `weekday`, `start_time`, `end_time`, `breaks_json`, `created_at`, `updated_at` Notes: - Runtime uses **`weekday`**, not `day_of_week` - **NO global-only rows.** Every row has a `provider_id`. Querying without a `provider_id` filter returns an arbitrary provider's row — never a "global" hour. See `scheduling` skill §8. #### `xs_provider_schedules` Columns: `id`, `provider_id`, `day_of_week`, `start_time`, `end_time`, `break_start`, `break_end`, `is_active`, `created_at`, `updated_at` Notes: - Runtime does **not** include `location_id` #### `xs_locations` Columns: `id`, `provider_id`, `name`, `address`, `city` (nullable, added 2026-04-23), `area` (nullable, added 2026-04-23), `contact_number`, `is_primary`, `is_active`, `created_at`, `updated_at` #### `xs_location_days` Columns: `id`, `location_id`, `day_of_week` Notes: - Runtime currently exposes **only these 3 columns** - Treat as schema-incomplete for location-hours redesign work #### `xs_providers_services` Columns: `provider_id`, `service_id`, `created_at` #### `xs_provider_staff_assignments` Columns: `id`, `provider_id`, `staff_id`, `assigned_at`, `assigned_by`, `status` ### 2.4 Settings Table #### `xs_settings` Columns: `id`, `setting_key`, `setting_value`, `setting_type`, `created_at`, `updated_at` Notes: - Typed key-value store - Key namespaces: `general.*`, `localization.*`, `booking.*`, `calendar.*`, `notifications.*`, `branding.*`, `security.*` - Runtime may omit `updated_by` in some environments - **Read via `SettingModel::getByKeys(['key'])`** — `getValue()` does not exist ### 2.5 Notification Tables #### `xs_business_notification_rules` Columns: `id`, `business_id`, `event_type`, `channel`, `is_enabled`, `reminder_offset_minutes`, `created_at`, `updated_at` #### `xs_business_integrations` Columns: `id`, `business_id`, `channel`, `provider_name`, `encrypted_config`, `metadata`, `is_active`, `health_status`, `last_tested_at`, `created_at`, `updated_at` Notes: - `channel` ENUM: `email`, `sms`, `whatsapp`, `webhook`, `google_calendar`, `stripe`, `zoom`, `slack`, `jitsi`, `payfast` (expanded 2026-05-20) - `metadata` — nullable TEXT, added 2026-05-20 (webhook last-delivery tracking) - Unique index: `uniq_integration_business_channel_provider` on `(business_id, channel, provider_name)` — replaced original `uniq_integration_business_channel` to allow multiple webhook endpoints per business - `encrypted_config` — AES-encrypted JSON. For Google Calendar includes `client_id`, `client_secret`, `access_token`, `refresh_token`, `token_expiry`. Credentials are admin-configured via UI, never read from .env. #### `xs_message_templates` Columns: `id`, `business_id`, `event_type`, `channel`, `provider`, `provider_template_id`, `locale`, `recipient_class`, `subject`, `body`, `is_active`, `created_at`, `updated_at` Notes: - `recipient_class` separates customer vs internal templates #### `xs_notification_queue` Columns: `id`, `business_id`, `channel`, `event_type`, `appointment_id`, `recipient_type`, `recipient_user_id`, `status`, `attempts`, `max_attempts`, `run_after`, `locked_at`, `lock_token`, `last_error`, `sent_at`, `idempotency_key`, `correlation_id`, `created_at`, `updated_at`, `reminder_offset_minutes`, `schedule_fingerprint` Notes: - Uses `attempts`/`max_attempts` (not legacy `attempt_count`) - Includes `locked_at`, `lock_token`, `correlation_id` - Internal rows resolve recipient from `xs_users` at dispatch - Reminder rows include `reminder_offset_minutes` and `schedule_fingerprint` (added 2026-04-21 migration) - Dispatcher cancels a reminder row if `schedule_fingerprint` no longer matches the live appointment #### `xs_notification_delivery_logs` Columns: `id`, `business_id`, `queue_id`, `correlation_id`, `channel`, `event_type`, `appointment_id`, `recipient`, `provider`, `status`, `attempt`, `error_message`, `created_at`, `updated_at` #### `xs_notification_opt_outs` Columns: `id`, `business_id`, `channel`, `recipient`, `reason`, `created_at`, `updated_at` ### 2.6 Custom Fields Table #### `xs_appointment_custom_fields` Columns: `id`, `appointment_id`, `field_key`, `value` (text, nullable), `created_at`, `updated_at` Notes: - Added 2026-04-30 (`CreateAppointmentCustomFieldsTable` migration) - Unique index on `(appointment_id, field_key)` — `idx_appt_custom_field_unique` - FK: `appointment_id → xs_appointments.id` ON DELETE CASCADE - Stores per-appointment custom field values; replaces reliance on `xs_customers.custom_fields` for appointment-scoped data - Backfilled from legacy customer custom fields on migration - Model: `App\Models\AppointmentCustomFieldModel` ### 2.7 Audit Table #### `xs_audit_logs` Columns: `id`, `user_id`, `action`, `target_type`, `target_id`, `old_value`, `new_value`, `ip_address`, `user_agent`, `created_at` Notes: - Verify table name as `xs_audit_logs` in mixed environments #### `xs_api_keys` Columns: `id`, `business_id` (default `1`), `user_id`, `name`, `key_prefix` (UNIQUE), `key_hash`, `scopes` (JSON text, nullable), `last_used_at`, `last_used_ip`, `expires_at`, `revoked_at`, `created_by`, `created_at`, `updated_at` Notes: - Model: `App\Models\ApiKeyModel` (`generate()`, `verify()`, `findActiveByPrefix()`, `touch()`, `revoke()`) - External API bearer tokens. **Only `key_prefix` and `password_hash()` of the secret are stored** — never the plaintext. Verification is an indexed lookup on `key_prefix` followed by `password_verify()`. - Every key is bound to an `xs_users` row; that user supplies the roles the token request runs under (see `api-contract` §Authentication). - `revoked_at` is a soft revocation; `expires_at` NULL means no expiry. `scopes` NULL means "inherit the bound user's role permissions". - `business_id` is **forward-compatibility only** — there is no businesses table and every row resolves to `1`. - Indexes: UNIQUE on `key_prefix`; composite `(user_id, revoked_at)` ### 2.8 Payment Table #### `xs_payment_transactions`
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub