Files
zpan/migrations/0012_image-hosting.sql
T
Jasper Van 2dca9d9ffb feat(db): image hosting schema, apiKey plugin, migration 0011 (v2.4.0 T1) (#315)
* feat(db): image hosting schema, apiKey plugin, migration 0011

Adds the DB infrastructure for the v2.4 image hosting feature:

- server/db/schema.ts: new `image_hosting_configs` (per-org singleton,
  custom domain + referer allowlist) and `image_hostings` tables with
  all required indexes and cascade-delete FKs
- server/db/auth-schema.ts: `apikey` table for @better-auth/api-key
  plugin (referenceId-indexed, rate-limiting fields, permissions column)
- server/auth.ts: enable apiKey plugin (references='organization',
  image-hosting:upload permission declared)
- shared/types/index.ts: ImageHostingConfig, ImageHosting, ImageHostingStatus
- migrations/0011_image-hosting.sql: generated by drizzle-kit (NOT
  hand-authored); creates all three new tables + indexes
- migrations/meta/0011_snapshot.json: baseline snapshot for future
  migration generation (repo was missing snapshots 0002–0010)
- package.json: add @better-auth/api-key ^1.6.2 dep, bump
  better-auth to ^1.6.2

Note: migration is tagged 0011_image-hosting (idx=11 in journal) rather
than 0012 because the existing 0011_notifications was registered as idx=10
(pre-existing numbering offset from a skipped 0006_ slot).

Agent-Profile: https://agent-kanban.dev/agents/a6bb038c4226a87f

* fix: resolve coverage gap and migration filename collision

- Add getTableConfig FK reference tests to cover deferred .references()
  callbacks in schema.ts (fixes Codecov patch coverage < 94.98%)
- Rename 0011_image-hosting → 0012_image-hosting to avoid filename
  collision with pre-existing 0011_notifications migration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Bob <aibob@mails.agent-kanban.dev>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 03:18:52 -04:00

63 lines
2.4 KiB
SQL

CREATE TABLE `image_hosting_configs` (
`org_id` text PRIMARY KEY NOT NULL,
`custom_domain` text,
`cf_hostname_id` text,
`domain_verified_at` integer,
`referer_allowlist` text,
`created_at` integer NOT NULL,
`updated_at` integer NOT NULL,
FOREIGN KEY (`org_id`) REFERENCES `organization`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE UNIQUE INDEX `image_hosting_configs_custom_domain_unique` ON `image_hosting_configs` (`custom_domain`);--> statement-breakpoint
CREATE TABLE `image_hostings` (
`id` text PRIMARY KEY NOT NULL,
`org_id` text NOT NULL,
`token` text NOT NULL,
`path` text NOT NULL,
`storage_id` text NOT NULL,
`storage_key` text NOT NULL,
`size` integer NOT NULL,
`mime` text NOT NULL,
`width` integer,
`height` integer,
`status` text DEFAULT 'draft' NOT NULL,
`access_count` integer DEFAULT 0 NOT NULL,
`last_accessed_at` integer,
`created_at` integer NOT NULL,
FOREIGN KEY (`org_id`) REFERENCES `organization`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`storage_id`) REFERENCES `storages`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `image_hostings_token_unique` ON `image_hostings` (`token`);--> statement-breakpoint
CREATE UNIQUE INDEX `image_hostings_org_path_uniq` ON `image_hostings` (`org_id`,`path`);--> statement-breakpoint
CREATE INDEX `image_hostings_org_created_idx` ON `image_hostings` (`org_id`,`created_at`);--> statement-breakpoint
CREATE INDEX `image_hostings_token_idx` ON `image_hostings` (`token`);--> statement-breakpoint
CREATE TABLE `apikey` (
`id` text PRIMARY KEY NOT NULL,
`config_id` text DEFAULT 'default' NOT NULL,
`name` text,
`start` text,
`reference_id` text NOT NULL,
`prefix` text,
`key` text NOT NULL,
`refill_interval` integer,
`refill_amount` integer,
`last_refill_at` integer,
`enabled` integer DEFAULT true NOT NULL,
`rate_limit_enabled` integer DEFAULT true NOT NULL,
`rate_limit_time_window` integer,
`rate_limit_max` integer,
`request_count` integer DEFAULT 0 NOT NULL,
`remaining` integer,
`last_request` integer,
`expires_at` integer,
`created_at` integer NOT NULL,
`updated_at` integer NOT NULL,
`permissions` text,
`metadata` text
);
--> statement-breakpoint
CREATE INDEX `apikey_config_id_idx` ON `apikey` (`config_id`);--> statement-breakpoint
CREATE INDEX `apikey_reference_id_idx` ON `apikey` (`reference_id`);--> statement-breakpoint
CREATE INDEX `apikey_key_idx` ON `apikey` (`key`);