feat: establish NekoNest Cloud control and relay
This commit is contained in:
@@ -0,0 +1,240 @@
|
||||
CREATE TABLE `accounts` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`auth_subject` text NOT NULL,
|
||||
`email` text NOT NULL,
|
||||
`display_name` text NOT NULL,
|
||||
`status` text DEFAULT 'active' NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_accounts_auth_subject` ON `accounts` (`auth_subject`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_accounts_email` ON `accounts` (`email`);--> statement-breakpoint
|
||||
CREATE TABLE `audit_events` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`actor_id` text NOT NULL,
|
||||
`action` text NOT NULL,
|
||||
`target_type` text NOT NULL,
|
||||
`target_id` text NOT NULL,
|
||||
`reason` text NOT NULL,
|
||||
`before_json` text,
|
||||
`after_json` text,
|
||||
`correlation_id` text NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_audit_target_time` ON `audit_events` (`target_type`,`target_id`,`created_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_audit_actor_time` ON `audit_events` (`actor_id`,`created_at`);--> statement-breakpoint
|
||||
CREATE TABLE `beta_programs` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`state` text NOT NULL,
|
||||
`capacity_slots` integer,
|
||||
`starts_at` text NOT NULL,
|
||||
`ends_at` text,
|
||||
`grace_days` integer DEFAULT 7 NOT NULL,
|
||||
`created_by` text NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`retired_at` text
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_beta_state_time` ON `beta_programs` (`state`,`starts_at`);--> statement-breakpoint
|
||||
CREATE TABLE `entitlement_grants` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`account_id` text NOT NULL,
|
||||
`host_id` text,
|
||||
`source` text NOT NULL,
|
||||
`source_ref` text,
|
||||
`capacity_slots` integer,
|
||||
`starts_at` text NOT NULL,
|
||||
`ends_at` text,
|
||||
`state` text DEFAULT 'scheduled' NOT NULL,
|
||||
`reason` text NOT NULL,
|
||||
`created_by` text NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`revoked_at` text,
|
||||
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`host_id`) REFERENCES `hosts`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_grants_account_state_time` ON `entitlement_grants` (`account_id`,`state`,`starts_at`);--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_grants_source_ref` ON `entitlement_grants` (`source`,`source_ref`);--> statement-breakpoint
|
||||
CREATE TABLE `hosts` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`account_id` text NOT NULL,
|
||||
`name` text NOT NULL,
|
||||
`os` text NOT NULL,
|
||||
`lifecycle` text DEFAULT 'active' NOT NULL,
|
||||
`slot_state` text DEFAULT 'active' NOT NULL,
|
||||
`connection_state` text DEFAULT 'unknown' NOT NULL,
|
||||
`daemon_version` text,
|
||||
`recovery_fingerprint` text,
|
||||
`last_seen_at` text,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`deactivated_at` text,
|
||||
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_hosts_account_lifecycle` ON `hosts` (`account_id`,`lifecycle`);--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_hosts_recovery_fingerprint` ON `hosts` (`recovery_fingerprint`);--> statement-breakpoint
|
||||
CREATE TABLE `idempotency_records` (
|
||||
`scope` text NOT NULL,
|
||||
`key` text NOT NULL,
|
||||
`request_hash` text NOT NULL,
|
||||
`response_json` text NOT NULL,
|
||||
`status_code` integer NOT NULL,
|
||||
`expires_at` text NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY(`scope`, `key`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_idempotency_expires` ON `idempotency_records` (`expires_at`);--> statement-breakpoint
|
||||
CREATE TABLE `invoices` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`order_id` text NOT NULL,
|
||||
`invoice_type` text DEFAULT 'commercial' NOT NULL,
|
||||
`invoice_number` text,
|
||||
`amount_minor` integer NOT NULL,
|
||||
`tax_minor` integer,
|
||||
`currency` text NOT NULL,
|
||||
`status` text DEFAULT 'draft' NOT NULL,
|
||||
`document_ref` text,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (`order_id`) REFERENCES `orders`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_invoices_order` ON `invoices` (`order_id`);--> statement-breakpoint
|
||||
CREATE TABLE `launch_gates` (
|
||||
`key` text PRIMARY KEY NOT NULL,
|
||||
`priority` text NOT NULL,
|
||||
`category` text NOT NULL,
|
||||
`title` text NOT NULL,
|
||||
`status` text DEFAULT 'blocked' NOT NULL,
|
||||
`owner` text,
|
||||
`evidence_url` text,
|
||||
`notes` text DEFAULT '' NOT NULL,
|
||||
`reviewed_at` text,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_launch_gates_status` ON `launch_gates` (`priority`,`status`);--> statement-breakpoint
|
||||
CREATE TABLE `orders` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`account_id` text NOT NULL,
|
||||
`client_order_id` text NOT NULL,
|
||||
`kind` text DEFAULT 'purchase' NOT NULL,
|
||||
`price_version_id` text NOT NULL,
|
||||
`slot_quantity` integer NOT NULL,
|
||||
`term_start` text NOT NULL,
|
||||
`term_end` text NOT NULL,
|
||||
`amount_minor` integer NOT NULL,
|
||||
`currency` text NOT NULL,
|
||||
`status` text DEFAULT 'draft' NOT NULL,
|
||||
`quote_expires_at` text NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`price_version_id`) REFERENCES `price_versions`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_orders_account_client` ON `orders` (`account_id`,`client_order_id`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_orders_account_status` ON `orders` (`account_id`,`status`);--> statement-breakpoint
|
||||
CREATE TABLE `pairing_requests` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`account_id` text NOT NULL,
|
||||
`requested_name` text NOT NULL,
|
||||
`os` text NOT NULL,
|
||||
`code_hash` text NOT NULL,
|
||||
`status` text DEFAULT 'waiting' NOT NULL,
|
||||
`expires_at` text NOT NULL,
|
||||
`claimed_host_id` text,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`claimed_at` text,
|
||||
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`claimed_host_id`) REFERENCES `hosts`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_pairing_code_hash` ON `pairing_requests` (`code_hash`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_pairing_account_status` ON `pairing_requests` (`account_id`,`status`);--> statement-breakpoint
|
||||
CREATE TABLE `payment_attempts` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`order_id` text NOT NULL,
|
||||
`provider` text NOT NULL,
|
||||
`provider_payment_ref` text,
|
||||
`provider_event_id` text,
|
||||
`amount_minor` integer NOT NULL,
|
||||
`currency` text NOT NULL,
|
||||
`status` text DEFAULT 'created' NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (`order_id`) REFERENCES `orders`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_payments_provider_event` ON `payment_attempts` (`provider`,`provider_event_id`);--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_payments_provider_ref` ON `payment_attempts` (`provider`,`provider_payment_ref`);--> statement-breakpoint
|
||||
CREATE TABLE `price_versions` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`product_code` text DEFAULT 'host_slot' NOT NULL,
|
||||
`billing_period` text NOT NULL,
|
||||
`unit_slots` integer DEFAULT 1 NOT NULL,
|
||||
`amount_minor` integer NOT NULL,
|
||||
`currency` text DEFAULT 'CNY' NOT NULL,
|
||||
`tax_mode` text DEFAULT 'undecided' NOT NULL,
|
||||
`quote_ttl_seconds` integer DEFAULT 900 NOT NULL,
|
||||
`status` text DEFAULT 'draft' NOT NULL,
|
||||
`effective_from` text NOT NULL,
|
||||
`effective_to` text,
|
||||
`created_by` text NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_prices_catalog` ON `price_versions` (`product_code`,`billing_period`,`status`);--> statement-breakpoint
|
||||
CREATE TABLE `provisioning_operations` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`tenant_id` text NOT NULL,
|
||||
`operation` text NOT NULL,
|
||||
`idempotency_key` text NOT NULL,
|
||||
`correlation_id` text NOT NULL,
|
||||
`target_generation` integer NOT NULL,
|
||||
`status` text DEFAULT 'requested' NOT NULL,
|
||||
`error_code` text,
|
||||
`error_detail` text,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_operations_idempotency` ON `provisioning_operations` (`tenant_id`,`idempotency_key`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_operations_status` ON `provisioning_operations` (`status`);--> statement-breakpoint
|
||||
CREATE TABLE `refunds` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`payment_attempt_id` text NOT NULL,
|
||||
`invoice_id` text,
|
||||
`amount_minor` integer NOT NULL,
|
||||
`currency` text NOT NULL,
|
||||
`reason` text NOT NULL,
|
||||
`status` text DEFAULT 'requested' NOT NULL,
|
||||
`entitlement_effect` text DEFAULT 'pending' NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (`payment_attempt_id`) REFERENCES `payment_attempts`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`invoice_id`) REFERENCES `invoices`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_refunds_payment` ON `refunds` (`payment_attempt_id`);--> statement-breakpoint
|
||||
CREATE TABLE `tenant_instances` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`account_id` text NOT NULL,
|
||||
`slug` text NOT NULL,
|
||||
`lifecycle` text DEFAULT 'requested' NOT NULL,
|
||||
`desired_generation` integer DEFAULT 1 NOT NULL,
|
||||
`active_generation` integer,
|
||||
`runtime_version` text,
|
||||
`last_health_at` text,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_tenants_account` ON `tenant_instances` (`account_id`);--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_tenants_slug` ON `tenant_instances` (`slug`);
|
||||
@@ -0,0 +1,46 @@
|
||||
CREATE TABLE `cloud_schema_migrations` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`applied_at` text NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `device_credentials` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`host_id` text NOT NULL,
|
||||
`token_hash` text NOT NULL,
|
||||
`status` text DEFAULT 'active' NOT NULL,
|
||||
`issued_at` text NOT NULL,
|
||||
`expires_at` text,
|
||||
`last_used_at` text,
|
||||
`revoked_at` text,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (`host_id`) REFERENCES `hosts`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_device_credentials_token_hash` ON `device_credentials` (`token_hash`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_device_credentials_host_status` ON `device_credentials` (`host_id`,`status`);--> statement-breakpoint
|
||||
CREATE TABLE `pairing_claim_attempts` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`pairing_request_id` text NOT NULL,
|
||||
`source_hash` text NOT NULL,
|
||||
`outcome` text NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_pairing_claim_attempts_target_time` ON `pairing_claim_attempts` (`pairing_request_id`,`created_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_pairing_claim_attempts_source_time` ON `pairing_claim_attempts` (`source_hash`,`created_at`);--> statement-breakpoint
|
||||
CREATE TABLE `pairing_claim_rate_limits` (
|
||||
`source_hash` text NOT NULL,
|
||||
`window_start` text NOT NULL,
|
||||
`attempts` integer DEFAULT 1 NOT NULL,
|
||||
`updated_at` text NOT NULL,
|
||||
PRIMARY KEY(`source_hash`, `window_start`)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `hosts` ADD `ed25519_public` text;--> statement-breakpoint
|
||||
ALTER TABLE `hosts` ADD `x25519_public` text;--> statement-breakpoint
|
||||
ALTER TABLE `hosts` ADD `identity_fingerprint` text;--> statement-breakpoint
|
||||
ALTER TABLE `hosts` ADD `claimed_at` text;--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_hosts_identity_fingerprint` ON `hosts` (`identity_fingerprint`);--> statement-breakpoint
|
||||
ALTER TABLE `pairing_requests` ADD `failed_attempts` integer DEFAULT 0 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `pairing_requests` ADD `locked_at` text;--> statement-breakpoint
|
||||
ALTER TABLE `pairing_requests` ADD `last_attempt_at` text;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE `hosts` ADD `claim_request_id` text;
|
||||
@@ -0,0 +1,40 @@
|
||||
ALTER TABLE `provisioning_operations` ADD `requested_by` text DEFAULT 'system:legacy' NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `reason` text DEFAULT 'legacy provisioning request' NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `lifecycle_before` text DEFAULT 'requested' NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `payload_version` integer DEFAULT 1 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `lease_owner` text;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `lease_token_hash` text;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `lease_expires_at` text;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `attempt_count` integer DEFAULT 0 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `max_attempts` integer DEFAULT 5 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `started_at` text;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `completed_at` text;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `completion_hash` text;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `observed_generation` integer;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `result_runtime_ref` text;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `result_runtime_version` text;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `result_relay_origin` text;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `result_secret_bundle_ref` text;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `health_status` text;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `health_checked_at` text;--> statement-breakpoint
|
||||
UPDATE `provisioning_operations`
|
||||
SET `status` = 'canceled',
|
||||
`error_code` = 'legacy_duplicate_active_operation',
|
||||
`error_detail` = 'Migration kept only the newest active operation for this tenant.',
|
||||
`completed_at` = CURRENT_TIMESTAMP,
|
||||
`updated_at` = CURRENT_TIMESTAMP
|
||||
WHERE `status` IN ('requested', 'leased')
|
||||
AND `id` <> (
|
||||
SELECT newer.`id`
|
||||
FROM `provisioning_operations` AS newer
|
||||
WHERE newer.`tenant_id` = `provisioning_operations`.`tenant_id`
|
||||
AND newer.`status` IN ('requested', 'leased')
|
||||
ORDER BY newer.`created_at` DESC, newer.`id` DESC
|
||||
LIMIT 1
|
||||
);--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_operations_one_active_tenant` ON `provisioning_operations` (`tenant_id`) WHERE "provisioning_operations"."status" IN ('requested', 'leased');--> statement-breakpoint
|
||||
CREATE INDEX `idx_operations_lease_expiry` ON `provisioning_operations` (`status`,`lease_expires_at`);--> statement-breakpoint
|
||||
ALTER TABLE `tenant_instances` ADD `runtime_ref` text;--> statement-breakpoint
|
||||
ALTER TABLE `tenant_instances` ADD `relay_origin` text;--> statement-breakpoint
|
||||
ALTER TABLE `tenant_instances` ADD `secret_bundle_ref` text;--> statement-breakpoint
|
||||
ALTER TABLE `tenant_instances` ADD `relay_ready` integer DEFAULT false NOT NULL;
|
||||
@@ -0,0 +1,8 @@
|
||||
ALTER TABLE `provisioning_operations` ADD `predecessor_id` text;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `credential_revision` integer DEFAULT 0 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `fence_epoch` integer DEFAULT 0 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `provisioning_operations` ADD `result_version` integer;--> statement-breakpoint
|
||||
ALTER TABLE `tenant_instances` ADD `desired_state` text DEFAULT 'requested' NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `tenant_instances` ADD `observed_state` text DEFAULT 'absent' NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `tenant_instances` ADD `credential_revision` integer DEFAULT 0 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `tenant_instances` ADD `tombstoned_at` text;
|
||||
@@ -0,0 +1,16 @@
|
||||
CREATE TABLE `beta_feedback` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`account_id` text NOT NULL,
|
||||
`category` text NOT NULL,
|
||||
`message` text NOT NULL,
|
||||
`status` text DEFAULT 'open' NOT NULL,
|
||||
`admin_response` text,
|
||||
`handled_by` text,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`resolved_at` text,
|
||||
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_beta_feedback_account_time` ON `beta_feedback` (`account_id`,`created_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_beta_feedback_status_time` ON `beta_feedback` (`status`,`created_at`);
|
||||
@@ -0,0 +1,16 @@
|
||||
CREATE TABLE `service_incidents` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`severity` text NOT NULL,
|
||||
`title` text NOT NULL,
|
||||
`message` text NOT NULL,
|
||||
`status` text DEFAULT 'active' NOT NULL,
|
||||
`created_by` text NOT NULL,
|
||||
`resolved_by` text,
|
||||
`resolution` text,
|
||||
`started_at` text NOT NULL,
|
||||
`resolved_at` text,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_service_incidents_status_started` ON `service_incidents` (`status`,`started_at`);
|
||||
@@ -0,0 +1,14 @@
|
||||
CREATE TABLE `account_deletion_requests` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`account_id` text NOT NULL,
|
||||
`status` text DEFAULT 'requested' NOT NULL,
|
||||
`reason` text,
|
||||
`requested_at` text NOT NULL,
|
||||
`cancelled_at` text,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_account_deletion_one_requested` ON `account_deletion_requests` (`account_id`) WHERE "account_deletion_requests"."status" = 'requested';--> statement-breakpoint
|
||||
CREATE INDEX `idx_account_deletion_status_time` ON `account_deletion_requests` (`status`,`requested_at`);
|
||||
@@ -0,0 +1,9 @@
|
||||
CREATE TABLE `provisioner_workers` (
|
||||
`tenant_id` text PRIMARY KEY NOT NULL,
|
||||
`worker_id` text NOT NULL,
|
||||
`poll_count` integer DEFAULT 1 NOT NULL,
|
||||
`last_seen_at` text NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
@@ -0,0 +1,16 @@
|
||||
CREATE TABLE `maintenance_jobs` (
|
||||
`key` text PRIMARY KEY NOT NULL,
|
||||
`state` text NOT NULL,
|
||||
`run_id` text,
|
||||
`trigger` text,
|
||||
`scheduled_at` text,
|
||||
`started_at` text,
|
||||
`completed_at` text,
|
||||
`last_success_at` text,
|
||||
`result_json` text,
|
||||
`error_code` text,
|
||||
`consecutive_failures` integer DEFAULT 0 NOT NULL,
|
||||
`run_count` integer DEFAULT 0 NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
@@ -0,0 +1,22 @@
|
||||
CREATE TABLE `beta_access_requests` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`account_id` text NOT NULL,
|
||||
`status` text DEFAULT 'requested' NOT NULL,
|
||||
`preferred_os` text NOT NULL,
|
||||
`requested_slots` integer DEFAULT 1 NOT NULL,
|
||||
`use_case` text NOT NULL,
|
||||
`admin_response` text,
|
||||
`resolved_by` text,
|
||||
`invitation_grant_id` text,
|
||||
`requested_at` text NOT NULL,
|
||||
`resolved_at` text,
|
||||
`cancelled_at` text,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`invitation_grant_id`) REFERENCES `entitlement_grants`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_beta_access_requests_one_pending` ON `beta_access_requests` (`account_id`) WHERE "beta_access_requests"."status" = 'requested';--> statement-breakpoint
|
||||
CREATE INDEX `idx_beta_access_requests_status_time` ON `beta_access_requests` (`status`,`requested_at`);--> statement-breakpoint
|
||||
CREATE INDEX `idx_beta_access_requests_account_time` ON `beta_access_requests` (`account_id`,`requested_at`);
|
||||
@@ -0,0 +1 @@
|
||||
CREATE INDEX `idx_beta_access_requests_requested_time` ON `beta_access_requests` (`requested_at`);
|
||||
@@ -0,0 +1,182 @@
|
||||
CREATE TABLE `relay_regions` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`code` text NOT NULL,
|
||||
`display_name` text NOT NULL,
|
||||
`status` text DEFAULT 'active' NOT NULL,
|
||||
`public_origin` text NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_relay_regions_code` ON `relay_regions` (`code`);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_relay_regions_public_origin` ON `relay_regions` (`public_origin`);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `relay_nodes` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`region_id` text NOT NULL,
|
||||
`status` text DEFAULT 'provisioning' NOT NULL,
|
||||
`internal_endpoint_ref` text NOT NULL,
|
||||
`capacity_tenants` integer DEFAULT 0 NOT NULL,
|
||||
`last_heartbeat_at` text,
|
||||
`heartbeat_generation` integer DEFAULT 0 NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (`region_id`) REFERENCES `relay_regions`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_relay_nodes_region_status` ON `relay_nodes` (`region_id`,`status`);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `tenant_placements` (
|
||||
`tenant_id` text PRIMARY KEY NOT NULL,
|
||||
`home_region_id` text NOT NULL,
|
||||
`relay_node_id` text,
|
||||
`generation` integer DEFAULT 1 NOT NULL,
|
||||
`state` text DEFAULT 'provisioning' NOT NULL,
|
||||
`last_error_code` text,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`home_region_id`) REFERENCES `relay_regions`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`relay_node_id`) REFERENCES `relay_nodes`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_tenant_placements_region_state` ON `tenant_placements` (`home_region_id`,`state`);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_tenant_placements_node_state` ON `tenant_placements` (`relay_node_id`,`state`);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `tenant_authorization_state` (
|
||||
`tenant_id` text PRIMARY KEY NOT NULL,
|
||||
`revision` integer DEFAULT 0 NOT NULL,
|
||||
`status` text DEFAULT 'active' NOT NULL,
|
||||
`updated_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_tenant_authorization_revision` ON `tenant_authorization_state` (`revision`);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `relay_signing_keys` (
|
||||
`kid` text PRIMARY KEY NOT NULL,
|
||||
`algorithm` text DEFAULT 'Ed25519' NOT NULL,
|
||||
`public_key_jwk` text NOT NULL,
|
||||
`private_key_ref` text NOT NULL,
|
||||
`status` text DEFAULT 'active' NOT NULL,
|
||||
`not_before` text NOT NULL,
|
||||
`not_after` text NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`retired_at` text
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `relay_node_credentials` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`node_id` text NOT NULL,
|
||||
`mtls_spiffe_id` text NOT NULL,
|
||||
`certificate_fingerprint_sha256` text NOT NULL,
|
||||
`status` text DEFAULT 'active' NOT NULL,
|
||||
`bootstrap_reason` text NOT NULL,
|
||||
`issued_by` text NOT NULL,
|
||||
`issued_at` text NOT NULL,
|
||||
`expires_at` text,
|
||||
`last_used_at` text,
|
||||
`revoked_at` text,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (`node_id`) REFERENCES `relay_nodes`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_relay_node_credentials_mtls` ON `relay_node_credentials` (`mtls_spiffe_id`,`certificate_fingerprint_sha256`);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_relay_node_credentials_node_status` ON `relay_node_credentials` (`node_id`,`status`);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `phone_handoff_tickets` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`ticket_hash` text NOT NULL,
|
||||
`account_id` text NOT NULL,
|
||||
`tenant_id` text NOT NULL,
|
||||
`expected_origin` text NOT NULL,
|
||||
`expires_at` text NOT NULL,
|
||||
`consumed_at` text,
|
||||
`consumed_by_node_id` text,
|
||||
`pending_phone_name` text,
|
||||
`pending_ed25519_public` text,
|
||||
`pending_x25519_public` text,
|
||||
`pending_identity_fingerprint` text,
|
||||
`completed_at` text,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`consumed_by_node_id`) REFERENCES `relay_nodes`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_phone_handoff_ticket_hash` ON `phone_handoff_tickets` (`ticket_hash`);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_phone_handoff_account_expiry` ON `phone_handoff_tickets` (`account_id`,`expires_at`);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `phone_route_handles` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`handle_hash` text NOT NULL,
|
||||
`tenant_id` text NOT NULL,
|
||||
`phone_id` text NOT NULL,
|
||||
`status` text DEFAULT 'active' NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`last_used_at` text,
|
||||
`revoked_at` text,
|
||||
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_phone_route_handle_hash` ON `phone_route_handles` (`handle_hash`);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_phone_route_tenant_status` ON `phone_route_handles` (`tenant_id`,`status`);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `relay_phone_principals` (
|
||||
`phone_id` text PRIMARY KEY NOT NULL,
|
||||
`tenant_id` text NOT NULL,
|
||||
`token_hash` text NOT NULL,
|
||||
`name` text NOT NULL,
|
||||
`ed25519_public` text NOT NULL,
|
||||
`x25519_public` text NOT NULL,
|
||||
`identity_fingerprint` text NOT NULL,
|
||||
`status` text DEFAULT 'active' NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
`last_used_at` text,
|
||||
`revoked_at` text,
|
||||
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_relay_phone_token_hash` ON `relay_phone_principals` (`token_hash`);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_relay_phone_tenant_identity` ON `relay_phone_principals` (`tenant_id`,`identity_fingerprint`);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_relay_phone_tenant_status` ON `relay_phone_principals` (`tenant_id`,`status`);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `device_registration_replays` (
|
||||
`pairing_id` text PRIMARY KEY NOT NULL,
|
||||
`request_hash` text NOT NULL,
|
||||
`response_ciphertext` text NOT NULL,
|
||||
`response_nonce` text NOT NULL,
|
||||
`expires_at` text NOT NULL,
|
||||
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY (`pairing_id`) REFERENCES `pairing_requests`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_device_registration_replay_expiry` ON `device_registration_replays` (`expires_at`);
|
||||
--> statement-breakpoint
|
||||
INSERT OR IGNORE INTO `relay_regions`
|
||||
(`id`, `code`, `display_name`, `status`, `public_origin`, `created_at`, `updated_at`)
|
||||
VALUES
|
||||
('region_default', 'default', 'Default region', 'active', 'https://connect.invalid', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
|
||||
--> statement-breakpoint
|
||||
INSERT OR IGNORE INTO `tenant_placements`
|
||||
(`tenant_id`, `home_region_id`, `generation`, `state`, `created_at`, `updated_at`)
|
||||
SELECT `id`, 'region_default', 1, 'provisioning', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
|
||||
FROM `tenant_instances`;
|
||||
--> statement-breakpoint
|
||||
DROP TABLE IF EXISTS `provisioner_workers`;
|
||||
--> statement-breakpoint
|
||||
DROP TABLE IF EXISTS `provisioning_operations`;
|
||||
--> statement-breakpoint
|
||||
INSERT OR IGNORE INTO `tenant_authorization_state`
|
||||
(`tenant_id`, `revision`, `status`, `updated_at`)
|
||||
SELECT `id`, `credential_revision`,
|
||||
CASE WHEN `tombstoned_at` IS NULL THEN 'active' ELSE 'suspended' END,
|
||||
CURRENT_TIMESTAMP
|
||||
FROM `tenant_instances`;
|
||||
@@ -0,0 +1,34 @@
|
||||
CREATE TABLE `relay_migrations` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`tenant_id` text NOT NULL,
|
||||
`source_node_id` text NOT NULL,
|
||||
`target_node_id` text NOT NULL,
|
||||
`source_generation` integer NOT NULL,
|
||||
`target_generation` integer NOT NULL,
|
||||
`state` text DEFAULT 'quiescing' NOT NULL,
|
||||
`backup_ref` text,
|
||||
`manifest_sha256` text,
|
||||
`requested_by` text NOT NULL,
|
||||
`reason` text NOT NULL,
|
||||
`started_at` text NOT NULL,
|
||||
`updated_at` text NOT NULL,
|
||||
`switched_at` text,
|
||||
`completed_at` text,
|
||||
`last_error_code` text,
|
||||
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`source_node_id`) REFERENCES `relay_nodes`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`target_node_id`) REFERENCES `relay_nodes`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
CHECK (`target_generation` = `source_generation` + 1),
|
||||
CHECK (`source_node_id` <> `target_node_id`),
|
||||
CHECK (`state` IN ('quiescing', 'copying', 'switching', 'draining', 'completed', 'failed'))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_relay_migrations_one_active`
|
||||
ON `relay_migrations` (`tenant_id`)
|
||||
WHERE `state` IN ('quiescing', 'copying', 'switching', 'draining');
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_relay_migrations_source_state`
|
||||
ON `relay_migrations` (`source_node_id`, `state`, `updated_at`);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_relay_migrations_target_state`
|
||||
ON `relay_migrations` (`target_node_id`, `state`, `updated_at`);
|
||||
@@ -0,0 +1,26 @@
|
||||
CREATE TABLE `relay_purge_jobs` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`deletion_request_id` text NOT NULL,
|
||||
`tenant_id` text NOT NULL,
|
||||
`relay_node_id` text NOT NULL,
|
||||
`placement_generation` integer NOT NULL,
|
||||
`state` text DEFAULT 'quiescing' NOT NULL,
|
||||
`requested_by` text NOT NULL,
|
||||
`reason` text NOT NULL,
|
||||
`started_at` text NOT NULL,
|
||||
`updated_at` text NOT NULL,
|
||||
`completed_at` text,
|
||||
`evidence_sha256` text,
|
||||
`last_error_code` text,
|
||||
FOREIGN KEY (`deletion_request_id`) REFERENCES `account_deletion_requests`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`tenant_id`) REFERENCES `tenant_instances`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`relay_node_id`) REFERENCES `relay_nodes`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
CONSTRAINT `relay_purge_generation_positive` CHECK (`placement_generation` > 0),
|
||||
CONSTRAINT `relay_purge_state_valid` CHECK (`state` IN ('quiescing', 'completed', 'failed'))
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_relay_purge_deletion_request` ON `relay_purge_jobs` (`deletion_request_id`);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_relay_purge_tenant` ON `relay_purge_jobs` (`tenant_id`);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `idx_relay_purge_node_state` ON `relay_purge_jobs` (`relay_node_id`,`state`,`updated_at`);
|
||||
@@ -0,0 +1,5 @@
|
||||
ALTER TABLE `phone_handoff_tickets` ADD `completed_phone_id` text;
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `phone_handoff_tickets` ADD `completed_phone_token_hash` text;
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `phone_handoff_tickets` ADD `completed_route_handle_hash` text;
|
||||
@@ -0,0 +1,6 @@
|
||||
ALTER TABLE `phone_handoff_tickets` ADD `activation_nonce` text;
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `phone_handoff_tickets` ADD `activated_at` text;
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `idx_phone_handoff_activation_nonce`
|
||||
ON `phone_handoff_tickets` (`activation_nonce`);
|
||||
@@ -0,0 +1,111 @@
|
||||
CREATE TRIGGER `provisioning_queue_guard`
|
||||
BEFORE INSERT ON `provisioning_operations`
|
||||
WHEN NEW.`status` = 'requested'
|
||||
BEGIN
|
||||
SELECT CASE WHEN NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM `tenant_instances`
|
||||
WHERE `id` = NEW.`tenant_id`
|
||||
AND `desired_generation` + 1 = NEW.`target_generation`
|
||||
AND `credential_revision` = NEW.`credential_revision`
|
||||
AND `tombstoned_at` IS NULL
|
||||
AND (
|
||||
(NEW.`operation` = 'ensure' AND `lifecycle` IN ('requested', 'failed', 'degraded'))
|
||||
OR (NEW.`operation` = 'suspend' AND `lifecycle` IN ('ready', 'degraded'))
|
||||
OR (NEW.`operation` = 'resume' AND `lifecycle` IN ('suspended', 'failed'))
|
||||
OR (NEW.`operation` = 'deprovision' AND `lifecycle` IN ('requested', 'ready', 'suspended', 'failed', 'degraded'))
|
||||
)
|
||||
) THEN RAISE(ABORT, 'invalid_provisioning_transition') END;
|
||||
END;--> statement-breakpoint
|
||||
|
||||
CREATE TRIGGER `provisioning_queue_tenant_update`
|
||||
AFTER INSERT ON `provisioning_operations`
|
||||
WHEN NEW.`status` = 'requested'
|
||||
BEGIN
|
||||
UPDATE `tenant_instances`
|
||||
SET `lifecycle` = CASE NEW.`operation`
|
||||
WHEN 'suspend' THEN 'suspending'
|
||||
WHEN 'deprovision' THEN 'deprovisioning'
|
||||
ELSE 'provisioning'
|
||||
END,
|
||||
`desired_state` = CASE NEW.`operation`
|
||||
WHEN 'suspend' THEN 'suspended'
|
||||
WHEN 'deprovision' THEN 'deleted'
|
||||
ELSE 'running'
|
||||
END,
|
||||
`desired_generation` = NEW.`target_generation`,
|
||||
`relay_ready` = 0,
|
||||
`updated_at` = NEW.`created_at`
|
||||
WHERE `id` = NEW.`tenant_id`;
|
||||
END;--> statement-breakpoint
|
||||
|
||||
CREATE TRIGGER `provisioning_completion_guard`
|
||||
BEFORE UPDATE OF `status` ON `provisioning_operations`
|
||||
WHEN OLD.`status` IN ('requested', 'leased') AND NEW.`status` IN ('succeeded', 'failed')
|
||||
BEGIN
|
||||
SELECT CASE WHEN NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM `tenant_instances`
|
||||
WHERE `id` = OLD.`tenant_id`
|
||||
AND `desired_generation` = OLD.`target_generation`
|
||||
AND (
|
||||
NEW.`status` = 'failed'
|
||||
OR `credential_revision` = OLD.`credential_revision`
|
||||
)
|
||||
) THEN RAISE(ABORT, 'stale_provisioning_generation') END;
|
||||
END;--> statement-breakpoint
|
||||
|
||||
CREATE TRIGGER `provisioning_completion_tenant_update`
|
||||
AFTER UPDATE OF `status` ON `provisioning_operations`
|
||||
WHEN OLD.`status` IN ('requested', 'leased') AND NEW.`status` IN ('succeeded', 'failed')
|
||||
BEGIN
|
||||
UPDATE `tenant_instances`
|
||||
SET `lifecycle` = CASE
|
||||
WHEN NEW.`status` = 'failed' AND NEW.`operation` IN ('ensure', 'resume') THEN 'failed'
|
||||
WHEN NEW.`status` = 'failed' THEN 'degraded'
|
||||
WHEN NEW.`operation` IN ('ensure', 'resume') THEN 'ready'
|
||||
WHEN NEW.`operation` = 'suspend' THEN 'suspended'
|
||||
ELSE 'deleted'
|
||||
END,
|
||||
`observed_state` = CASE
|
||||
WHEN NEW.`status` = 'failed' THEN `observed_state`
|
||||
WHEN NEW.`operation` IN ('ensure', 'resume') THEN 'running'
|
||||
WHEN NEW.`operation` = 'suspend' THEN 'suspended'
|
||||
ELSE 'absent'
|
||||
END,
|
||||
`active_generation` = CASE
|
||||
WHEN NEW.`status` = 'succeeded' THEN NEW.`target_generation`
|
||||
ELSE `active_generation`
|
||||
END,
|
||||
`runtime_version` = CASE
|
||||
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` IN ('ensure', 'resume') THEN NEW.`result_runtime_version`
|
||||
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` = 'deprovision' THEN NULL
|
||||
ELSE `runtime_version`
|
||||
END,
|
||||
`runtime_ref` = CASE
|
||||
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` IN ('ensure', 'resume') THEN NEW.`result_runtime_ref`
|
||||
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` = 'deprovision' THEN NULL
|
||||
ELSE `runtime_ref`
|
||||
END,
|
||||
`relay_origin` = CASE
|
||||
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` IN ('ensure', 'resume') THEN NEW.`result_relay_origin`
|
||||
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` = 'deprovision' THEN NULL
|
||||
ELSE `relay_origin`
|
||||
END,
|
||||
`secret_bundle_ref` = CASE
|
||||
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` IN ('ensure', 'resume') THEN NEW.`result_secret_bundle_ref`
|
||||
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` = 'deprovision' THEN NULL
|
||||
ELSE `secret_bundle_ref`
|
||||
END,
|
||||
`last_health_at` = CASE
|
||||
WHEN NEW.`status` = 'succeeded' THEN NEW.`health_checked_at`
|
||||
ELSE `last_health_at`
|
||||
END,
|
||||
`tombstoned_at` = CASE
|
||||
WHEN NEW.`status` = 'succeeded' AND NEW.`operation` = 'deprovision' THEN NEW.`completed_at`
|
||||
ELSE `tombstoned_at`
|
||||
END,
|
||||
`relay_ready` = 0,
|
||||
`updated_at` = NEW.`completed_at`
|
||||
WHERE `id` = NEW.`tenant_id`;
|
||||
END;
|
||||
@@ -0,0 +1,24 @@
|
||||
INSERT OR IGNORE INTO `audit_events`
|
||||
(`id`, `actor_id`, `action`, `target_type`, `target_id`, `reason`,
|
||||
`before_json`, `after_json`, `correlation_id`, `created_at`)
|
||||
SELECT 'audit_slug_backfill_' || `id`,
|
||||
'system:migration',
|
||||
'tenant.slug_backfilled',
|
||||
'tenant',
|
||||
`id`,
|
||||
'旧版短租户 slug 不满足隔离域名契约,按不可变 tenant ID 扩展',
|
||||
json_object('slug', `slug`),
|
||||
json_object('slug', 'n-' || substr(`id`, -32)),
|
||||
'corr_slug_backfill_' || `id`,
|
||||
CURRENT_TIMESTAMP
|
||||
FROM `tenant_instances`
|
||||
WHERE `id` LIKE 'tenant_%'
|
||||
AND length(`id`) = 39
|
||||
AND (`slug` NOT LIKE 'n-%' OR length(`slug`) <> 34);--> statement-breakpoint
|
||||
|
||||
UPDATE `tenant_instances`
|
||||
SET `slug` = 'n-' || substr(`id`, -32),
|
||||
`updated_at` = CURRENT_TIMESTAMP
|
||||
WHERE `id` LIKE 'tenant_%'
|
||||
AND length(`id`) = 39
|
||||
AND (`slug` NOT LIKE 'n-%' OR length(`slug`) <> 34);
|
||||
@@ -0,0 +1,21 @@
|
||||
DROP TRIGGER IF EXISTS `provisioning_queue_guard`;--> statement-breakpoint
|
||||
|
||||
CREATE TRIGGER `provisioning_queue_guard`
|
||||
BEFORE INSERT ON `provisioning_operations`
|
||||
WHEN NEW.`status` = 'requested'
|
||||
BEGIN
|
||||
SELECT CASE WHEN NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM `tenant_instances`
|
||||
WHERE `id` = NEW.`tenant_id`
|
||||
AND `desired_generation` + 1 = NEW.`target_generation`
|
||||
AND `credential_revision` = NEW.`credential_revision`
|
||||
AND `tombstoned_at` IS NULL
|
||||
AND (
|
||||
(NEW.`operation` = 'ensure' AND `lifecycle` IN ('requested', 'ready', 'failed', 'degraded'))
|
||||
OR (NEW.`operation` = 'suspend' AND `lifecycle` IN ('ready', 'degraded'))
|
||||
OR (NEW.`operation` = 'resume' AND `lifecycle` IN ('suspended', 'failed'))
|
||||
OR (NEW.`operation` = 'deprovision' AND `lifecycle` IN ('requested', 'ready', 'suspended', 'failed', 'degraded'))
|
||||
)
|
||||
) THEN RAISE(ABORT, 'invalid_provisioning_transition') END;
|
||||
END;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,97 @@
|
||||
{
|
||||
"version": "7",
|
||||
"dialect": "sqlite",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "6",
|
||||
"when": 1786458686828,
|
||||
"tag": "0000_condemned_legion",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "6",
|
||||
"when": 1786471272276,
|
||||
"tag": "0001_mushy_vance_astro",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 2,
|
||||
"version": "6",
|
||||
"when": 1786473834384,
|
||||
"tag": "0002_wild_ravenous",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 3,
|
||||
"version": "6",
|
||||
"when": 1786474656600,
|
||||
"tag": "0003_medical_rocket_racer",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 4,
|
||||
"version": "6",
|
||||
"when": 1786474813520,
|
||||
"tag": "0004_loud_prodigy",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 5,
|
||||
"version": "6",
|
||||
"when": 1786488227508,
|
||||
"tag": "0005_pale_corsair",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 6,
|
||||
"version": "6",
|
||||
"when": 1786490421386,
|
||||
"tag": "0006_clever_shocker",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 7,
|
||||
"version": "6",
|
||||
"when": 1786491408443,
|
||||
"tag": "0007_zippy_nomad",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 8,
|
||||
"version": "6",
|
||||
"when": 1786499791158,
|
||||
"tag": "0008_far_justice",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 9,
|
||||
"version": "6",
|
||||
"when": 1786500924681,
|
||||
"tag": "0009_flat_robbie_robertson",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 10,
|
||||
"version": "6",
|
||||
"when": 1786504111648,
|
||||
"tag": "0010_windy_toxin",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 11,
|
||||
"version": "6",
|
||||
"when": 1786506592910,
|
||||
"tag": "0011_next_thunderball",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 12,
|
||||
"version": "6",
|
||||
"when": 1786520000000,
|
||||
"tag": "0012_shared_relay_control_plane",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user