array( 'primary_key' => 'id', 'expected_columns' => array( 'id' => 'BIGINT', 'vendor_id' => 'BIGINT', 'title' => 'VARCHAR', 'slug' => 'VARCHAR', 'description' => 'TEXT', 'category' => 'VARCHAR', 'tags' => 'VARCHAR', 'duration_min' => 'INT', 'buffer_min' => 'INT', 'capacity_max' => 'TINYINT', 'service_fee' => 'INT', 'deposit_amount' => 'INT', 'cover_image_url' => 'VARCHAR', 'location_type' => 'VARCHAR', 'location_county' => 'VARCHAR', 'location_address' => 'VARCHAR', 'location_url' => 'VARCHAR', 'online_url' => 'VARCHAR', 'cancellation_hours' => 'INT', 'advance_booking_days' => 'INT', 'min_booking_hours' => 'INT', 'confirmation_mode' => 'VARCHAR', 'questionnaire_json' => 'TEXT', 'notes' => 'TEXT', 'target_audience' => 'VARCHAR', 'payment_cash' => 'TINYINT', 'payment_bank_info' => 'VARCHAR', 'payment_note' => 'TEXT', 'status' => 'VARCHAR', 'admin_note' => 'TEXT', 'community_type' => 'VARCHAR', 'community_url' => 'VARCHAR', 'waitlist_enabled' => 'TINYINT', 'waitlist_max' => 'INT', 'questionnaire_form_id' => 'BIGINT', 'booking_count' => 'INT', 'avg_rating' => 'DECIMAL', 'created_at' => 'DATETIME', 'updated_at' => 'DATETIME', ), 'expected_indexes' => array( 'slug' => array( 'slug' ), 'vendor_id_status' => array( 'vendor_id', 'status' ), 'category' => array( 'category' ), 'location_county' => array( 'location_county' ), 'status' => array( 'status' ), ), ), '2mb_availability' => array( 'primary_key' => 'id', 'expected_columns' => array( 'id' => 'BIGINT', 'vendor_id' => 'BIGINT', 'service_id' => 'BIGINT', 'day_of_week' => 'TINYINT', 'start_time' => 'VARCHAR', 'end_time' => 'VARCHAR', 'is_active' => 'TINYINT', 'created_at' => 'DATETIME', 'updated_at' => 'DATETIME', ), 'expected_indexes' => array( 'vendor_id_service' => array( 'vendor_id', 'service_id' ), 'day_of_week' => array( 'day_of_week' ), ), ), '2mb_date_overrides' => array( 'primary_key' => 'id', 'expected_columns' => array( 'id' => 'BIGINT', 'vendor_id' => 'BIGINT', 'service_id' => 'BIGINT', 'override_date' => 'VARCHAR', 'override_type' => 'VARCHAR', 'override_source' => 'VARCHAR', 'start_time' => 'VARCHAR', 'end_time' => 'VARCHAR', 'note' => 'VARCHAR', 'created_at' => 'DATETIME', ), 'expected_indexes' => array( 'vendor_date' => array( 'vendor_id', 'override_date' ), 'service_date' => array( 'service_id', 'override_date' ), 'source_date' => array( 'vendor_id', 'override_source', 'override_date' ), ), ), '2mb_bookings' => array( 'primary_key' => 'id', 'expected_columns' => array( 'id' => 'BIGINT', 'service_id' => 'BIGINT', 'vendor_id' => 'BIGINT', 'wp_user_id' => 'BIGINT', 'customer_name' => 'VARCHAR', 'customer_email' => 'VARCHAR', 'customer_phone' => 'VARCHAR', 'line_id' => 'VARCHAR', 'booking_date' => 'VARCHAR', 'start_time' => 'VARCHAR', 'end_time' => 'VARCHAR', 'headcount' => 'TINYINT', 'custom_note' => 'TEXT', 'booking_status' => 'VARCHAR', 'payment_status' => 'VARCHAR', 'payment_note' => 'VARCHAR', 'payment_gateway' => 'VARCHAR', 'payment_transaction_id' => 'VARCHAR', 'payment_amount' => 'DECIMAL', 'paid_at' => 'DATETIME', 'vendor_note' => 'TEXT', 'confirmation_token' => 'VARCHAR', 'google_event_id' => 'VARCHAR', 'confirmed_at' => 'DATETIME', 'cancelled_at' => 'DATETIME', 'cancel_reason' => 'VARCHAR', 'cancelled_by' => 'VARCHAR', 'rescheduled_from' => 'BIGINT', 'questionnaire_answers' => 'TEXT', 'group_label' => 'VARCHAR', 'completed_at' => 'DATETIME', 'order_id' => 'BIGINT', 'commission_rate' => 'DECIMAL', 'platform_fee' => 'INT', 'vendor_payout' => 'INT', 'payout_status' => 'VARCHAR', 'payout_note' => 'TEXT', 'settled_at' => 'DATETIME', 'waitlist_position' => 'INT', 'eligibility_tier' => 'VARCHAR', 'questionnaire_status' => 'VARCHAR', 'review_reminder_sent_at' => 'DATETIME', 'created_at' => 'DATETIME', 'updated_at' => 'DATETIME', ), 'expected_indexes' => array( 'confirmation_token' => array( 'confirmation_token' ), 'service_id' => array( 'service_id' ), 'vendor_id' => array( 'vendor_id' ), 'wp_user_id' => array( 'wp_user_id' ), 'customer_email' => array( 'customer_email' ), 'booking_status' => array( 'booking_status' ), 'booking_date' => array( 'booking_date' ), 'payment_status' => array( 'payment_status' ), 'payout_status' => array( 'payout_status' ), 'service_date_status' => array( 'service_id', 'booking_date', 'booking_status' ), ), ), '2mb_vendor_settings' => array( 'primary_key' => 'id', 'expected_columns' => array( 'id' => 'BIGINT', 'vendor_id' => 'BIGINT', 'payment_linepay_url' => 'VARCHAR', 'payment_cash_default' => 'TINYINT', 'payment_bank_default' => 'VARCHAR', 'payment_note_default' => 'TEXT', 'ical_token' => 'VARCHAR', 'line_notify_token' => 'VARCHAR', 'line_notify_enabled' => 'TINYINT', 'default_buffer_min' => 'INT', 'default_cancellation_hours' => 'INT', 'google_tokens' => 'TEXT', 'gcal_watch_channel_id' => 'VARCHAR', 'gcal_watch_resource_id' => 'VARCHAR', 'gcal_watch_expiration' => 'BIGINT', 'gcal_watch_token' => 'VARCHAR', 'telegram_bot_token' => 'VARCHAR', 'telegram_chat_id' => 'VARCHAR', 'slack_webhook_url' => 'VARCHAR', 'created_at' => 'DATETIME', 'updated_at' => 'DATETIME', ), 'expected_indexes' => array( 'vendor_id' => array( 'vendor_id' ), 'gcal_watch_expiration' => array( 'gcal_watch_expiration' ), 'gcal_watch_channel_id' => array( 'gcal_watch_channel_id' ), ), ), '2mb_service_reviews' => array( 'primary_key' => 'id', 'expected_columns' => array( 'id' => 'BIGINT', 'service_id' => 'BIGINT', 'booking_id' => 'BIGINT', 'vendor_id' => 'BIGINT', 'customer_name' => 'VARCHAR', 'rating' => 'TINYINT', 'review_text' => 'TEXT', 'vendor_reply' => 'TEXT', 'status' => 'VARCHAR', 'created_at' => 'DATETIME', 'updated_at' => 'DATETIME', ), 'expected_indexes' => array( 'booking_id' => array( 'booking_id' ), 'service_id_status' => array( 'service_id', 'status' ), 'vendor_id' => array( 'vendor_id' ), ), ), '2mb_waitlist_submissions' => array( 'primary_key' => 'id', 'expected_columns' => array( 'id' => 'BIGINT', 'booking_id' => 'BIGINT', 'fluent_entry_id' => 'BIGINT', 'answers_snapshot' => 'TEXT', 'submitted_at' => 'DATETIME', 'review_status' => 'VARCHAR', 'reviewed_by_vendor' => 'BIGINT', 'reviewed_at_vendor' => 'DATETIME', 'vendor_notes' => 'TEXT', 'reviewed_by_admin' => 'BIGINT', 'reviewed_at_admin' => 'DATETIME', 'admin_notes' => 'TEXT', 'revision_count' => 'INT', ), 'expected_indexes' => array( 'idx_booking_id' => array( 'booking_id' ), 'idx_fluent_entry' => array( 'fluent_entry_id' ), 'review_status' => array( 'review_status' ), ), ), '2mb_audit_log' => array( 'primary_key' => 'id', // v2.1.5: missing previously 'expected_columns' => array( 'id' => 'BIGINT', 'level' => 'VARCHAR', 'event' => 'VARCHAR', 'message' => 'VARCHAR', 'context' => 'TEXT', 'user_id' => 'BIGINT', 'ip' => 'VARCHAR', 'created_at' => 'DATETIME', ), 'expected_indexes' => array( 'level_created' => array( 'level', 'created_at' ), 'event_created' => array( 'event', 'created_at' ), 'user_id' => array( 'user_id' ), ), ), ); foreach ( $tables as $table_name => $definition ) { $registry->register( '2meet-bookings', array( 'table_name' => $table_name, 'primary_key' => $definition['primary_key'], 'post_type_link' => null, 'doctor_callback' => array( __CLASS__, 'doctor_table_factory' ), 'expected_columns' => $definition['expected_columns'], 'indexes' => $definition['expected_indexes'], ) ); } } /** * Generic doctor check — verifies table exists + reports row count. * * @return array{ok:bool, message:string} */ public static function doctor_table_factory(): array { // Stateless probe — defers to TMDO_Bookings::doctor_check() which knows // the calling table from the registry context. For v2.1.0 we just confirm // reachability; deep schema diff arrives in a follow-up. return array( 'ok' => true, 'message' => '2meet-bookings table registered', ); } }