This commit is contained in:
@@ -22,6 +22,7 @@ import { createInventoryItemService } from '../modules/inventory/services/invent
|
|||||||
import { createPublicInventoryService } from '../modules/inventory/services/public-inventory-service.js';
|
import { createPublicInventoryService } from '../modules/inventory/services/public-inventory-service.js';
|
||||||
import { createPublicImageService } from '../modules/inventory/services/public-image-service.js';
|
import { createPublicImageService } from '../modules/inventory/services/public-image-service.js';
|
||||||
import { createInventoryImageRepository } from '../modules/inventory/repositories/inventory-image-repository.js';
|
import { createInventoryImageRepository } from '../modules/inventory/repositories/inventory-image-repository.js';
|
||||||
|
import { createImageDerivativeJobRepository } from '../modules/inventory/repositories/image-derivative-job-repository.js';
|
||||||
import { createInventoryImageService } from '../modules/inventory/services/inventory-image-service.js';
|
import { createInventoryImageService } from '../modules/inventory/services/inventory-image-service.js';
|
||||||
import { createLocalImageStorage } from '../infrastructure/images/local-image-storage.js';
|
import { createLocalImageStorage } from '../infrastructure/images/local-image-storage.js';
|
||||||
import { createConditionRepository } from '../modules/inventory/repositories/condition-repository.js';
|
import { createConditionRepository } from '../modules/inventory/repositories/condition-repository.js';
|
||||||
@@ -51,6 +52,7 @@ async function startServer() {
|
|||||||
const productRepository = createProductRepository(database.db);
|
const productRepository = createProductRepository(database.db);
|
||||||
const inventoryItemRepository = createInventoryItemRepository(database.db);
|
const inventoryItemRepository = createInventoryItemRepository(database.db);
|
||||||
const inventoryImageRepository = createInventoryImageRepository(database.db);
|
const inventoryImageRepository = createInventoryImageRepository(database.db);
|
||||||
|
const imageDerivativeJobRepository = createImageDerivativeJobRepository(database.db);
|
||||||
const listingRepository = createListingRepository(database.db);
|
const listingRepository = createListingRepository(database.db);
|
||||||
const sellerRepository = createSellerRepository(database.db);
|
const sellerRepository = createSellerRepository(database.db);
|
||||||
const conditionRepository = createConditionRepository(database.db);
|
const conditionRepository = createConditionRepository(database.db);
|
||||||
@@ -104,6 +106,7 @@ async function startServer() {
|
|||||||
publicInventoryService: createPublicInventoryService({ inventoryItemRepository, publicImageService }),
|
publicInventoryService: createPublicInventoryService({ inventoryItemRepository, publicImageService }),
|
||||||
inventoryImageService: createInventoryImageService({
|
inventoryImageService: createInventoryImageService({
|
||||||
imageStorage: createLocalImageStorage(process.env.IMAGE_STORAGE_ROOT ?? '.local/image-storage'),
|
imageStorage: createLocalImageStorage(process.env.IMAGE_STORAGE_ROOT ?? '.local/image-storage'),
|
||||||
|
imageDerivativeJobRepository,
|
||||||
inventoryImageRepository,
|
inventoryImageRepository,
|
||||||
}),
|
}),
|
||||||
listingService: createListingService({ listingRepository, inventoryImageRepository }),
|
listingService: createListingService({ listingRepository, inventoryImageRepository }),
|
||||||
|
|||||||
@@ -264,6 +264,22 @@ export const inventoryImages = pgTable(
|
|||||||
(table) => [index('inventory_images_inventory_item_id_index').on(table.inventoryItemId)],
|
(table) => [index('inventory_images_inventory_item_id_index').on(table.inventoryItemId)],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const imageDerivativeJobs = pgTable(
|
||||||
|
'image_derivative_jobs',
|
||||||
|
{
|
||||||
|
id: uuid('id').defaultRandom().primaryKey(),
|
||||||
|
inventoryImageId: uuid('inventory_image_id')
|
||||||
|
.notNull()
|
||||||
|
.references(() => inventoryImages.id),
|
||||||
|
sourceKey: text('source_key').notNull(),
|
||||||
|
status: text('status').default('PENDING').notNull(),
|
||||||
|
derivatives: jsonb('derivatives').default([]).notNull(),
|
||||||
|
error: text('error'),
|
||||||
|
...timestamps,
|
||||||
|
},
|
||||||
|
(table) => [index('image_derivative_jobs_image_id_index').on(table.inventoryImageId)],
|
||||||
|
);
|
||||||
|
|
||||||
export const listings = pgTable('listings', {
|
export const listings = pgTable('listings', {
|
||||||
id: uuid('id').defaultRandom().primaryKey(),
|
id: uuid('id').defaultRandom().primaryKey(),
|
||||||
inventoryItemId: uuid('inventory_item_id')
|
inventoryItemId: uuid('inventory_item_id')
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { asc, eq } from 'drizzle-orm';
|
||||||
|
|
||||||
|
import { imageDerivativeJobs } from '../../../infrastructure/database/schema.js';
|
||||||
|
|
||||||
|
export function createImageDerivativeJobRepository(db) {
|
||||||
|
return {
|
||||||
|
async create(job) {
|
||||||
|
const [createdJob] = await db.insert(imageDerivativeJobs).values(job).returning();
|
||||||
|
return createdJob;
|
||||||
|
},
|
||||||
|
|
||||||
|
async listByImageId(inventoryImageId) {
|
||||||
|
return db
|
||||||
|
.select()
|
||||||
|
.from(imageDerivativeJobs)
|
||||||
|
.where(eq(imageDerivativeJobs.inventoryImageId, inventoryImageId))
|
||||||
|
.orderBy(asc(imageDerivativeJobs.createdAt));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createApplicationError } from '../../../shared/errors/application-error.js';
|
import { createApplicationError } from '../../../shared/errors/application-error.js';
|
||||||
import { validateImageSignature, validateInventoryImageMetadata } from '../domain/inventory-image.js';
|
import { validateImageSignature, validateInventoryImageMetadata } from '../domain/inventory-image.js';
|
||||||
|
|
||||||
export function createInventoryImageService({ inventoryImageRepository, imageStorage }) {
|
export function createInventoryImageService({ inventoryImageRepository, imageDerivativeJobRepository, imageStorage }) {
|
||||||
return {
|
return {
|
||||||
async create(input) {
|
async create(input) {
|
||||||
validateInventoryImageMetadata(input);
|
validateInventoryImageMetadata(input);
|
||||||
@@ -14,6 +14,12 @@ export function createInventoryImageService({ inventoryImageRepository, imageSto
|
|||||||
throw createApplicationError('INVENTORY_ITEM_NOT_FOUND', 'Inventory item was not found.', 404);
|
throw createApplicationError('INVENTORY_ITEM_NOT_FOUND', 'Inventory item was not found.', 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await imageDerivativeJobRepository?.create({
|
||||||
|
inventoryImageId: image.id,
|
||||||
|
sourceKey: image.storageKey,
|
||||||
|
status: 'PENDING',
|
||||||
|
});
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const input = {
|
|||||||
|
|
||||||
test('stores validated upload bytes before persisting image metadata', async () => {
|
test('stores validated upload bytes before persisting image metadata', async () => {
|
||||||
const stored = [];
|
const stored = [];
|
||||||
|
const jobs = [];
|
||||||
const service = createInventoryImageService({
|
const service = createInventoryImageService({
|
||||||
imageStorage: {
|
imageStorage: {
|
||||||
async put(value) { stored.push(value); },
|
async put(value) { stored.push(value); },
|
||||||
@@ -27,6 +28,9 @@ test('stores validated upload bytes before persisting image metadata', async ()
|
|||||||
return { id: 'image-1', ...image };
|
return { id: 'image-1', ...image };
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
imageDerivativeJobRepository: {
|
||||||
|
async create(job) { jobs.push(job); },
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const image = await service.upload(input);
|
const image = await service.upload(input);
|
||||||
@@ -36,6 +40,11 @@ test('stores validated upload bytes before persisting image metadata', async ()
|
|||||||
assert.equal(image.id, 'image-1');
|
assert.equal(image.id, 'image-1');
|
||||||
assert.equal(image.processingStatus, 'PENDING');
|
assert.equal(image.processingStatus, 'PENDING');
|
||||||
assert.equal('data' in image, false);
|
assert.equal('data' in image, false);
|
||||||
|
assert.deepEqual(jobs, [{
|
||||||
|
inventoryImageId: 'image-1',
|
||||||
|
sourceKey: input.storageKey,
|
||||||
|
status: 'PENDING',
|
||||||
|
}]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('removes stored bytes when metadata persistence fails', async () => {
|
test('removes stored bytes when metadata persistence fails', async () => {
|
||||||
|
|||||||
@@ -0,0 +1,198 @@
|
|||||||
|
CREATE TYPE "public"."inventory_status" AS ENUM('ACTIVE', 'SOLD', 'ARCHIVED');--> statement-breakpoint
|
||||||
|
CREATE TYPE "public"."listing_status" AS ENUM('DRAFT', 'AVAILABLE', 'PENDING', 'CLOSED', 'ARCHIVED');--> statement-breakpoint
|
||||||
|
CREATE TYPE "public"."user_role" AS ENUM('ADMIN');--> statement-breakpoint
|
||||||
|
CREATE TABLE "categories" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"slug" text NOT NULL,
|
||||||
|
"active" boolean DEFAULT true NOT NULL,
|
||||||
|
"sort" integer DEFAULT 0 NOT NULL,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "condition_profiles" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"category_id" uuid NOT NULL,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"active" boolean DEFAULT true NOT NULL,
|
||||||
|
"sort" integer DEFAULT 0 NOT NULL,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "conditions" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"condition_profile_id" uuid NOT NULL,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"code" text NOT NULL,
|
||||||
|
"quality_rank" integer NOT NULL,
|
||||||
|
"description" text,
|
||||||
|
"active" boolean DEFAULT true NOT NULL,
|
||||||
|
"sort" integer DEFAULT 0 NOT NULL,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "image_derivative_jobs" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"inventory_image_id" uuid NOT NULL,
|
||||||
|
"source_key" text NOT NULL,
|
||||||
|
"status" text DEFAULT 'PENDING' NOT NULL,
|
||||||
|
"derivatives" jsonb DEFAULT '[]'::jsonb NOT NULL,
|
||||||
|
"error" text,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "inventory_images" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"inventory_item_id" uuid NOT NULL,
|
||||||
|
"storage_key" text NOT NULL,
|
||||||
|
"original_filename" text NOT NULL,
|
||||||
|
"mime_type" text NOT NULL,
|
||||||
|
"file_size" integer NOT NULL,
|
||||||
|
"width" integer NOT NULL,
|
||||||
|
"height" integer NOT NULL,
|
||||||
|
"alt_text" text,
|
||||||
|
"sort_order" integer DEFAULT 0 NOT NULL,
|
||||||
|
"is_primary" boolean DEFAULT false NOT NULL,
|
||||||
|
"processing_status" text DEFAULT 'PENDING' NOT NULL,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "inventory_items" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"product_id" uuid NOT NULL,
|
||||||
|
"condition_id" uuid NOT NULL,
|
||||||
|
"status" "inventory_status" DEFAULT 'ACTIVE' NOT NULL,
|
||||||
|
"notes" text,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "listings" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"inventory_item_id" uuid NOT NULL,
|
||||||
|
"product_name" text NOT NULL,
|
||||||
|
"category_id" uuid NOT NULL,
|
||||||
|
"condition_id" uuid NOT NULL,
|
||||||
|
"asking_price_minor" integer NOT NULL,
|
||||||
|
"status" "listing_status" DEFAULT 'DRAFT' NOT NULL,
|
||||||
|
"notes" text,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "mfa_methods" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"user_id" uuid NOT NULL,
|
||||||
|
"type" text NOT NULL,
|
||||||
|
"secret_ciphertext" text NOT NULL,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"is_enabled" boolean DEFAULT false NOT NULL,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"last_used_at" timestamp with time zone,
|
||||||
|
"disabled_at" timestamp with time zone
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "password_reset_tokens" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"user_id" uuid NOT NULL,
|
||||||
|
"token_hash" text NOT NULL,
|
||||||
|
"expires_at" timestamp with time zone NOT NULL,
|
||||||
|
"used_at" timestamp with time zone,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "products" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"seller_id" uuid NOT NULL,
|
||||||
|
"category_id" uuid NOT NULL,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"slug" text NOT NULL,
|
||||||
|
"description" text,
|
||||||
|
"brand" text,
|
||||||
|
"set_name" text,
|
||||||
|
"card_number" text,
|
||||||
|
"event_name" text,
|
||||||
|
"release_year" integer,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
CONSTRAINT "products_release_year_valid" CHECK ("products"."release_year" IS NULL OR "products"."release_year" BETWEEN 1996 AND 9999)
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "security_audit_events" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"user_id" uuid,
|
||||||
|
"event" text NOT NULL,
|
||||||
|
"ip_address" text,
|
||||||
|
"user_agent" text,
|
||||||
|
"metadata" jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "sellers" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"user_id" uuid NOT NULL,
|
||||||
|
"display_name" text NOT NULL,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "sessions" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"user_id" uuid NOT NULL,
|
||||||
|
"session_token_hash" text NOT NULL,
|
||||||
|
"csrf_token_hash" text NOT NULL,
|
||||||
|
"expires_at" timestamp with time zone NOT NULL,
|
||||||
|
"last_activity_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"ip_address" text,
|
||||||
|
"user_agent" text,
|
||||||
|
"revoked_at" timestamp with time zone,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "users" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"email" text NOT NULL,
|
||||||
|
"password_hash" text NOT NULL,
|
||||||
|
"role" "user_role" DEFAULT 'ADMIN' NOT NULL,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "condition_profiles" ADD CONSTRAINT "condition_profiles_category_id_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "public"."categories"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "conditions" ADD CONSTRAINT "conditions_condition_profile_id_condition_profiles_id_fk" FOREIGN KEY ("condition_profile_id") REFERENCES "public"."condition_profiles"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "image_derivative_jobs" ADD CONSTRAINT "image_derivative_jobs_inventory_image_id_inventory_images_id_fk" FOREIGN KEY ("inventory_image_id") REFERENCES "public"."inventory_images"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "inventory_images" ADD CONSTRAINT "inventory_images_inventory_item_id_inventory_items_id_fk" FOREIGN KEY ("inventory_item_id") REFERENCES "public"."inventory_items"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "inventory_items" ADD CONSTRAINT "inventory_items_product_id_products_id_fk" FOREIGN KEY ("product_id") REFERENCES "public"."products"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "inventory_items" ADD CONSTRAINT "inventory_items_condition_id_conditions_id_fk" FOREIGN KEY ("condition_id") REFERENCES "public"."conditions"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "listings" ADD CONSTRAINT "listings_inventory_item_id_inventory_items_id_fk" FOREIGN KEY ("inventory_item_id") REFERENCES "public"."inventory_items"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "listings" ADD CONSTRAINT "listings_condition_id_conditions_id_fk" FOREIGN KEY ("condition_id") REFERENCES "public"."conditions"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "mfa_methods" ADD CONSTRAINT "mfa_methods_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "password_reset_tokens" ADD CONSTRAINT "password_reset_tokens_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "products" ADD CONSTRAINT "products_seller_id_sellers_id_fk" FOREIGN KEY ("seller_id") REFERENCES "public"."sellers"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "products" ADD CONSTRAINT "products_category_id_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "public"."categories"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "security_audit_events" ADD CONSTRAINT "security_audit_events_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "sellers" ADD CONSTRAINT "sellers_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "sessions" ADD CONSTRAINT "sessions_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "categories_name_unique" ON "categories" USING btree ("name");--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "categories_slug_unique" ON "categories" USING btree ("slug");--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "conditions_profile_code_unique" ON "conditions" USING btree ("condition_profile_id","code");--> statement-breakpoint
|
||||||
|
CREATE INDEX "image_derivative_jobs_image_id_index" ON "image_derivative_jobs" USING btree ("inventory_image_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "inventory_images_inventory_item_id_index" ON "inventory_images" USING btree ("inventory_item_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "listings_inventory_item_id_index" ON "listings" USING btree ("inventory_item_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "listings_status_index" ON "listings" USING btree ("status");--> statement-breakpoint
|
||||||
|
CREATE INDEX "mfa_methods_user_id_index" ON "mfa_methods" USING btree ("user_id");--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "password_reset_tokens_token_hash_unique" ON "password_reset_tokens" USING btree ("token_hash");--> statement-breakpoint
|
||||||
|
CREATE INDEX "password_reset_tokens_user_id_index" ON "password_reset_tokens" USING btree ("user_id");--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "products_seller_slug_unique" ON "products" USING btree ("seller_id","slug");--> statement-breakpoint
|
||||||
|
CREATE INDEX "security_audit_events_user_id_index" ON "security_audit_events" USING btree ("user_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "security_audit_events_event_created_at_index" ON "security_audit_events" USING btree ("event","created_at");--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "sellers_user_id_unique" ON "sellers" USING btree ("user_id");--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "sessions_token_hash_unique" ON "sessions" USING btree ("session_token_hash");--> statement-breakpoint
|
||||||
|
CREATE INDEX "sessions_user_id_index" ON "sessions" USING btree ("user_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "sessions_expires_at_index" ON "sessions" USING btree ("expires_at");--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "users_email_unique" ON "users" USING btree ("email");
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -71,6 +71,13 @@
|
|||||||
"when": 1789459200000,
|
"when": 1789459200000,
|
||||||
"tag": "0009_remove_listing_image_count",
|
"tag": "0009_remove_listing_image_count",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 10,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1788919152853,
|
||||||
|
"tag": "0010_plain_charles_xavier",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user