feat: reconcile application vertical slices
Backfill the completed acquisitions, sales, dashboard, pricing, search, public detail, worker, migration, contracts, validation, tests, and implementation-status changes into one verified application slice.
This commit is contained in:
@@ -10,100 +10,100 @@ import {
|
||||
timestamp,
|
||||
uniqueIndex,
|
||||
uuid,
|
||||
} from 'drizzle-orm/pg-core';
|
||||
import { sql } from 'drizzle-orm';
|
||||
} from "drizzle-orm/pg-core";
|
||||
import { sql } from "drizzle-orm";
|
||||
|
||||
export const userRole = pgEnum('user_role', ['ADMIN']);
|
||||
export const inventoryStatus = pgEnum('inventory_status', [
|
||||
'ACTIVE',
|
||||
'SOLD',
|
||||
'ARCHIVED',
|
||||
export const userRole = pgEnum("user_role", ["ADMIN"]);
|
||||
export const inventoryStatus = pgEnum("inventory_status", [
|
||||
"ACTIVE",
|
||||
"SOLD",
|
||||
"ARCHIVED",
|
||||
]);
|
||||
export const listingStatus = pgEnum('listing_status', [
|
||||
'DRAFT',
|
||||
'AVAILABLE',
|
||||
'PENDING',
|
||||
'CLOSED',
|
||||
'ARCHIVED',
|
||||
export const listingStatus = pgEnum("listing_status", [
|
||||
"DRAFT",
|
||||
"AVAILABLE",
|
||||
"PENDING",
|
||||
"CLOSED",
|
||||
"ARCHIVED",
|
||||
]);
|
||||
|
||||
const timestamps = {
|
||||
createdAt: timestamp('created_at', { withTimezone: true })
|
||||
createdAt: timestamp("created_at", { withTimezone: true })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true })
|
||||
updatedAt: timestamp("updated_at", { withTimezone: true })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
};
|
||||
|
||||
export const users = pgTable(
|
||||
'users',
|
||||
"users",
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
email: text('email').notNull(),
|
||||
passwordHash: text('password_hash').notNull(),
|
||||
role: userRole('role').default('ADMIN').notNull(),
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
email: text("email").notNull(),
|
||||
passwordHash: text("password_hash").notNull(),
|
||||
role: userRole("role").default("ADMIN").notNull(),
|
||||
...timestamps,
|
||||
},
|
||||
(table) => [uniqueIndex('users_email_unique').on(table.email)],
|
||||
(table) => [uniqueIndex("users_email_unique").on(table.email)],
|
||||
);
|
||||
|
||||
export const sellers = pgTable(
|
||||
'sellers',
|
||||
"sellers",
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
userId: uuid('user_id')
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
userId: uuid("user_id")
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
displayName: text('display_name').notNull(),
|
||||
displayName: text("display_name").notNull(),
|
||||
...timestamps,
|
||||
},
|
||||
(table) => [uniqueIndex('sellers_user_id_unique').on(table.userId)],
|
||||
(table) => [uniqueIndex("sellers_user_id_unique").on(table.userId)],
|
||||
);
|
||||
|
||||
export const sessions = pgTable(
|
||||
'sessions',
|
||||
"sessions",
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
userId: uuid('user_id')
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
userId: uuid("user_id")
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
sessionTokenHash: text('session_token_hash').notNull(),
|
||||
csrfTokenHash: text('csrf_token_hash').notNull(),
|
||||
expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
|
||||
lastActivityAt: timestamp('last_activity_at', { withTimezone: true })
|
||||
sessionTokenHash: text("session_token_hash").notNull(),
|
||||
csrfTokenHash: text("csrf_token_hash").notNull(),
|
||||
expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
|
||||
lastActivityAt: timestamp("last_activity_at", { withTimezone: true })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
ipAddress: text('ip_address'),
|
||||
userAgent: text('user_agent'),
|
||||
revokedAt: timestamp('revoked_at', { withTimezone: true }),
|
||||
createdAt: timestamp('created_at', { withTimezone: true })
|
||||
ipAddress: text("ip_address"),
|
||||
userAgent: text("user_agent"),
|
||||
revokedAt: timestamp("revoked_at", { withTimezone: true }),
|
||||
createdAt: timestamp("created_at", { withTimezone: true })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
},
|
||||
(table) => [
|
||||
uniqueIndex('sessions_token_hash_unique').on(table.sessionTokenHash),
|
||||
index('sessions_user_id_index').on(table.userId),
|
||||
index('sessions_expires_at_index').on(table.expiresAt),
|
||||
uniqueIndex("sessions_token_hash_unique").on(table.sessionTokenHash),
|
||||
index("sessions_user_id_index").on(table.userId),
|
||||
index("sessions_expires_at_index").on(table.expiresAt),
|
||||
],
|
||||
);
|
||||
|
||||
export const securityAuditEvents = pgTable(
|
||||
'security_audit_events',
|
||||
"security_audit_events",
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
userId: uuid('user_id').references(() => users.id),
|
||||
event: text('event').notNull(),
|
||||
ipAddress: text('ip_address'),
|
||||
userAgent: text('user_agent'),
|
||||
metadata: jsonb('metadata').default({}).notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true })
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
userId: uuid("user_id").references(() => users.id),
|
||||
event: text("event").notNull(),
|
||||
ipAddress: text("ip_address"),
|
||||
userAgent: text("user_agent"),
|
||||
metadata: jsonb("metadata").default({}).notNull(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
},
|
||||
(table) => [
|
||||
index('security_audit_events_user_id_index').on(table.userId),
|
||||
index('security_audit_events_event_created_at_index').on(
|
||||
index("security_audit_events_user_id_index").on(table.userId),
|
||||
index("security_audit_events_event_created_at_index").on(
|
||||
table.event,
|
||||
table.createdAt,
|
||||
),
|
||||
@@ -111,89 +111,89 @@ export const securityAuditEvents = pgTable(
|
||||
);
|
||||
|
||||
export const passwordResetTokens = pgTable(
|
||||
'password_reset_tokens',
|
||||
"password_reset_tokens",
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
userId: uuid('user_id')
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
userId: uuid("user_id")
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
tokenHash: text('token_hash').notNull(),
|
||||
expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
|
||||
usedAt: timestamp('used_at', { withTimezone: true }),
|
||||
createdAt: timestamp('created_at', { withTimezone: true })
|
||||
tokenHash: text("token_hash").notNull(),
|
||||
expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
|
||||
usedAt: timestamp("used_at", { withTimezone: true }),
|
||||
createdAt: timestamp("created_at", { withTimezone: true })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
},
|
||||
(table) => [
|
||||
uniqueIndex('password_reset_tokens_token_hash_unique').on(table.tokenHash),
|
||||
index('password_reset_tokens_user_id_index').on(table.userId),
|
||||
uniqueIndex("password_reset_tokens_token_hash_unique").on(table.tokenHash),
|
||||
index("password_reset_tokens_user_id_index").on(table.userId),
|
||||
],
|
||||
);
|
||||
|
||||
export const mfaMethods = pgTable(
|
||||
'mfa_methods',
|
||||
"mfa_methods",
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
userId: uuid('user_id')
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
userId: uuid("user_id")
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
type: text('type').notNull(),
|
||||
secretCiphertext: text('secret_ciphertext').notNull(),
|
||||
name: text('name').notNull(),
|
||||
isEnabled: boolean('is_enabled').default(false).notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true })
|
||||
type: text("type").notNull(),
|
||||
secretCiphertext: text("secret_ciphertext").notNull(),
|
||||
name: text("name").notNull(),
|
||||
isEnabled: boolean("is_enabled").default(false).notNull(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
lastUsedAt: timestamp('last_used_at', { withTimezone: true }),
|
||||
disabledAt: timestamp('disabled_at', { withTimezone: true }),
|
||||
lastUsedAt: timestamp("last_used_at", { withTimezone: true }),
|
||||
disabledAt: timestamp("disabled_at", { withTimezone: true }),
|
||||
},
|
||||
(table) => [index('mfa_methods_user_id_index').on(table.userId)],
|
||||
(table) => [index("mfa_methods_user_id_index").on(table.userId)],
|
||||
);
|
||||
|
||||
export const categories = pgTable(
|
||||
'categories',
|
||||
"categories",
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
name: text('name').notNull(),
|
||||
slug: text('slug').notNull(),
|
||||
active: boolean('active').default(true).notNull(),
|
||||
sort: integer('sort').default(0).notNull(),
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
name: text("name").notNull(),
|
||||
slug: text("slug").notNull(),
|
||||
active: boolean("active").default(true).notNull(),
|
||||
sort: integer("sort").default(0).notNull(),
|
||||
...timestamps,
|
||||
},
|
||||
(table) => [
|
||||
uniqueIndex('categories_name_unique').on(table.name),
|
||||
uniqueIndex('categories_slug_unique').on(table.slug),
|
||||
uniqueIndex("categories_name_unique").on(table.name),
|
||||
uniqueIndex("categories_slug_unique").on(table.slug),
|
||||
],
|
||||
);
|
||||
|
||||
export const conditionProfiles = pgTable('condition_profiles', {
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
categoryId: uuid('category_id')
|
||||
export const conditionProfiles = pgTable("condition_profiles", {
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
categoryId: uuid("category_id")
|
||||
.notNull()
|
||||
.references(() => categories.id),
|
||||
name: text('name').notNull(),
|
||||
active: boolean('active').default(true).notNull(),
|
||||
sort: integer('sort').default(0).notNull(),
|
||||
name: text("name").notNull(),
|
||||
active: boolean("active").default(true).notNull(),
|
||||
sort: integer("sort").default(0).notNull(),
|
||||
...timestamps,
|
||||
});
|
||||
|
||||
export const conditions = pgTable(
|
||||
'conditions',
|
||||
"conditions",
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
conditionProfileId: uuid('condition_profile_id')
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
conditionProfileId: uuid("condition_profile_id")
|
||||
.notNull()
|
||||
.references(() => conditionProfiles.id),
|
||||
name: text('name').notNull(),
|
||||
code: text('code').notNull(),
|
||||
qualityRank: integer('quality_rank').notNull(),
|
||||
description: text('description'),
|
||||
active: boolean('active').default(true).notNull(),
|
||||
sort: integer('sort').default(0).notNull(),
|
||||
name: text("name").notNull(),
|
||||
code: text("code").notNull(),
|
||||
qualityRank: integer("quality_rank").notNull(),
|
||||
description: text("description"),
|
||||
active: boolean("active").default(true).notNull(),
|
||||
sort: integer("sort").default(0).notNull(),
|
||||
...timestamps,
|
||||
},
|
||||
(table) => [
|
||||
uniqueIndex('conditions_profile_code_unique').on(
|
||||
uniqueIndex("conditions_profile_code_unique").on(
|
||||
table.conditionProfileId,
|
||||
table.code,
|
||||
),
|
||||
@@ -201,229 +201,290 @@ export const conditions = pgTable(
|
||||
);
|
||||
|
||||
export const products = pgTable(
|
||||
'products',
|
||||
"products",
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
sellerId: uuid('seller_id')
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
sellerId: uuid("seller_id")
|
||||
.notNull()
|
||||
.references(() => sellers.id),
|
||||
categoryId: uuid('category_id')
|
||||
categoryId: uuid("category_id")
|
||||
.notNull()
|
||||
.references(() => categories.id),
|
||||
name: text('name').notNull(),
|
||||
slug: text('slug').notNull(),
|
||||
description: text('description'),
|
||||
brand: text('brand'),
|
||||
setName: text('set_name'),
|
||||
cardNumber: text('card_number'),
|
||||
eventName: text('event_name'),
|
||||
releaseYear: integer('release_year'),
|
||||
name: text("name").notNull(),
|
||||
slug: text("slug").notNull(),
|
||||
description: text("description"),
|
||||
brand: text("brand"),
|
||||
setName: text("set_name"),
|
||||
cardNumber: text("card_number"),
|
||||
eventName: text("event_name"),
|
||||
releaseYear: integer("release_year"),
|
||||
...timestamps,
|
||||
},
|
||||
(table) => [
|
||||
uniqueIndex('products_seller_slug_unique').on(table.sellerId, table.slug),
|
||||
uniqueIndex("products_seller_slug_unique").on(table.sellerId, table.slug),
|
||||
check(
|
||||
'products_release_year_valid',
|
||||
"products_release_year_valid",
|
||||
sql`${table.releaseYear} IS NULL OR ${table.releaseYear} BETWEEN 1996 AND 9999`,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
export const inventoryItems = pgTable('inventory_items', {
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
productId: uuid('product_id')
|
||||
export const inventoryItems = pgTable("inventory_items", {
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
productId: uuid("product_id")
|
||||
.notNull()
|
||||
.references(() => products.id),
|
||||
conditionId: uuid('condition_id')
|
||||
conditionId: uuid("condition_id")
|
||||
.notNull()
|
||||
.references(() => conditions.id),
|
||||
status: inventoryStatus('status').default('ACTIVE').notNull(),
|
||||
notes: text('notes'),
|
||||
status: inventoryStatus("status").default("ACTIVE").notNull(),
|
||||
notes: text("notes"),
|
||||
...timestamps,
|
||||
});
|
||||
|
||||
export const acquisitions = pgTable('acquisitions', {
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
inventoryItemId: uuid('inventory_item_id')
|
||||
export const acquisitions = pgTable("acquisitions", {
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
inventoryItemId: uuid("inventory_item_id")
|
||||
.notNull()
|
||||
.references(() => inventoryItems.id),
|
||||
method: text('method').notNull(),
|
||||
costMinor: integer('cost_minor').notNull(),
|
||||
currency: text('currency').notNull(),
|
||||
date: text('date'),
|
||||
source: text('source'),
|
||||
location: text('location'),
|
||||
shippingMinor: integer('shipping_minor').default(0).notNull(),
|
||||
taxMinor: integer('tax_minor').default(0).notNull(),
|
||||
otherFeesMinor: integer('other_fees_minor').default(0).notNull(),
|
||||
estimatedTradeValueMinor: integer('estimated_trade_value_minor').default(0).notNull(),
|
||||
notes: text('notes'),
|
||||
method: text("method").notNull(),
|
||||
costMinor: integer("cost_minor").notNull(),
|
||||
currency: text("currency").notNull(),
|
||||
date: text("date"),
|
||||
source: text("source"),
|
||||
location: text("location"),
|
||||
shippingMinor: integer("shipping_minor").default(0).notNull(),
|
||||
taxMinor: integer("tax_minor").default(0).notNull(),
|
||||
otherFeesMinor: integer("other_fees_minor").default(0).notNull(),
|
||||
estimatedTradeValueMinor: integer("estimated_trade_value_minor")
|
||||
.default(0)
|
||||
.notNull(),
|
||||
notes: text("notes"),
|
||||
...timestamps,
|
||||
});
|
||||
|
||||
export const pricingObservations = pgTable('pricing_observations', {
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
productId: uuid('product_id').notNull().references(() => products.id),
|
||||
inventoryItemId: uuid('inventory_item_id').notNull().references(() => inventoryItems.id),
|
||||
providerId: text('provider_id').notNull(),
|
||||
priceMinor: integer('price_minor').notNull(),
|
||||
currency: text('currency').notNull(),
|
||||
sourceIdentifier: text('source_identifier').notNull(),
|
||||
conditionId: uuid('condition_id').notNull().references(() => conditions.id),
|
||||
sourceUrl: text('source_url'),
|
||||
qualityScore: integer('quality_score'),
|
||||
isOutlier: boolean('is_outlier').default(false).notNull(),
|
||||
outlierReason: text('outlier_reason'),
|
||||
observedAt: timestamp('observed_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
...timestamps,
|
||||
}, (table) => [index('pricing_observations_inventory_item_id_index').on(table.inventoryItemId)]);
|
||||
|
||||
export const marketValuations = pgTable('market_valuations', {
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
inventoryItemId: uuid('inventory_item_id').notNull().references(() => inventoryItems.id),
|
||||
valueMinor: integer('value_minor').notNull(),
|
||||
currency: text('currency').notNull(),
|
||||
strategy: text('strategy').notNull(),
|
||||
confidence: text('confidence').notNull(),
|
||||
sourceCount: integer('source_count').notNull(),
|
||||
calculatedAt: timestamp('calculated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
});
|
||||
|
||||
export const marketValueOverrides = pgTable('market_value_overrides', {
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
inventoryItemId: uuid('inventory_item_id').notNull().references(() => inventoryItems.id),
|
||||
valueMinor: integer('value_minor').notNull(),
|
||||
currency: text('currency').notNull(),
|
||||
reason: text('reason').notNull(),
|
||||
createdBy: uuid('created_by').notNull().references(() => users.id),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
});
|
||||
|
||||
export const pricingProviderMappings = pgTable('pricing_provider_mappings', {
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
productId: uuid('product_id').notNull().references(() => products.id),
|
||||
providerId: text('provider_id').notNull(),
|
||||
mappingType: text('mapping_type').notNull(),
|
||||
externalIdentifier: text('external_identifier'),
|
||||
searchQuery: text('search_query'),
|
||||
sourceUrl: text('source_url'),
|
||||
status: text('status').default('ACTIVE').notNull(),
|
||||
metadata: jsonb('metadata').default({}).notNull(),
|
||||
disabledAt: timestamp('disabled_at', { withTimezone: true }),
|
||||
...timestamps,
|
||||
});
|
||||
|
||||
export const pricingRefreshJobs = pgTable('pricing_refresh_jobs', {
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
sellerId: uuid('seller_id').notNull().references(() => sellers.id),
|
||||
inventoryItemId: uuid('inventory_item_id').notNull().references(() => inventoryItems.id),
|
||||
productId: uuid('product_id').notNull().references(() => products.id),
|
||||
conditionId: uuid('condition_id').notNull().references(() => conditions.id),
|
||||
providerId: text('provider_id').notNull(),
|
||||
status: text('status').default('PENDING').notNull(),
|
||||
attemptCount: integer('attempt_count').default(0).notNull(),
|
||||
nextAttemptAt: timestamp('next_attempt_at', { withTimezone: true }),
|
||||
observations: jsonb('observations').default([]).notNull(),
|
||||
valuation: jsonb('valuation'),
|
||||
error: text('error'),
|
||||
...timestamps,
|
||||
}, (table) => [index('pricing_refresh_jobs_status_created_at_index').on(table.status, table.createdAt)]);
|
||||
|
||||
export const inventoryImages = pgTable(
|
||||
'inventory_images',
|
||||
export const pricingObservations = pgTable(
|
||||
"pricing_observations",
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
inventoryItemId: uuid('inventory_item_id')
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
productId: uuid("product_id")
|
||||
.notNull()
|
||||
.references(() => products.id),
|
||||
inventoryItemId: uuid("inventory_item_id")
|
||||
.notNull()
|
||||
.references(() => inventoryItems.id),
|
||||
storageKey: text('storage_key').notNull(),
|
||||
originalFilename: text('original_filename').notNull(),
|
||||
mimeType: text('mime_type').notNull(),
|
||||
fileSize: integer('file_size').notNull(),
|
||||
width: integer('width').notNull(),
|
||||
height: integer('height').notNull(),
|
||||
altText: text('alt_text'),
|
||||
sortOrder: integer('sort_order').default(0).notNull(),
|
||||
isPrimary: boolean('is_primary').default(false).notNull(),
|
||||
processingStatus: text('processing_status').default('PENDING').notNull(),
|
||||
providerId: text("provider_id").notNull(),
|
||||
externalIdentifier: text("external_identifier"),
|
||||
searchQuery: text("search_query"),
|
||||
priceMinor: integer("price_minor").notNull(),
|
||||
currency: text("currency").notNull(),
|
||||
sourceIdentifier: text("source_identifier").notNull(),
|
||||
conditionId: uuid("condition_id")
|
||||
.notNull()
|
||||
.references(() => conditions.id),
|
||||
sourceUrl: text("source_url"),
|
||||
qualityScore: integer("quality_score"),
|
||||
isOutlier: boolean("is_outlier").default(false).notNull(),
|
||||
outlierReason: text("outlier_reason"),
|
||||
observedAt: timestamp("observed_at", { withTimezone: true })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
...timestamps,
|
||||
},
|
||||
(table) => [index('inventory_images_inventory_item_id_index').on(table.inventoryItemId)],
|
||||
(table) => [
|
||||
index("pricing_observations_inventory_item_id_index").on(
|
||||
table.inventoryItemId,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
export const marketValuations = pgTable("market_valuations", {
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
inventoryItemId: uuid("inventory_item_id")
|
||||
.notNull()
|
||||
.references(() => inventoryItems.id),
|
||||
valueMinor: integer("value_minor").notNull(),
|
||||
currency: text("currency").notNull(),
|
||||
strategy: text("strategy").notNull(),
|
||||
confidence: text("confidence").notNull(),
|
||||
sourceCount: integer("source_count").notNull(),
|
||||
calculatedAt: timestamp("calculated_at", { withTimezone: true })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
});
|
||||
|
||||
export const marketValueOverrides = pgTable("market_value_overrides", {
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
inventoryItemId: uuid("inventory_item_id")
|
||||
.notNull()
|
||||
.references(() => inventoryItems.id),
|
||||
valueMinor: integer("value_minor").notNull(),
|
||||
currency: text("currency").notNull(),
|
||||
reason: text("reason").notNull(),
|
||||
createdBy: uuid("created_by")
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
createdAt: timestamp("created_at", { withTimezone: true })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
});
|
||||
|
||||
export const pricingProviderMappings = pgTable("pricing_provider_mappings", {
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
productId: uuid("product_id")
|
||||
.notNull()
|
||||
.references(() => products.id),
|
||||
providerId: text("provider_id").notNull(),
|
||||
mappingType: text("mapping_type").notNull(),
|
||||
externalIdentifier: text("external_identifier"),
|
||||
searchQuery: text("search_query"),
|
||||
sourceUrl: text("source_url"),
|
||||
status: text("status").default("ACTIVE").notNull(),
|
||||
metadata: jsonb("metadata").default({}).notNull(),
|
||||
disabledAt: timestamp("disabled_at", { withTimezone: true }),
|
||||
...timestamps,
|
||||
});
|
||||
|
||||
export const pricingRefreshJobs = pgTable(
|
||||
"pricing_refresh_jobs",
|
||||
{
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
sellerId: uuid("seller_id")
|
||||
.notNull()
|
||||
.references(() => sellers.id),
|
||||
inventoryItemId: uuid("inventory_item_id")
|
||||
.notNull()
|
||||
.references(() => inventoryItems.id),
|
||||
productId: uuid("product_id")
|
||||
.notNull()
|
||||
.references(() => products.id),
|
||||
conditionId: uuid("condition_id")
|
||||
.notNull()
|
||||
.references(() => conditions.id),
|
||||
providerId: text("provider_id").notNull(),
|
||||
status: text("status").default("PENDING").notNull(),
|
||||
attemptCount: integer("attempt_count").default(0).notNull(),
|
||||
nextAttemptAt: timestamp("next_attempt_at", { withTimezone: true }),
|
||||
observations: jsonb("observations").default([]).notNull(),
|
||||
valuation: jsonb("valuation"),
|
||||
error: text("error"),
|
||||
...timestamps,
|
||||
},
|
||||
(table) => [
|
||||
index("pricing_refresh_jobs_status_created_at_index").on(
|
||||
table.status,
|
||||
table.createdAt,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
export const inventoryImages = pgTable(
|
||||
"inventory_images",
|
||||
{
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
inventoryItemId: uuid("inventory_item_id")
|
||||
.notNull()
|
||||
.references(() => inventoryItems.id),
|
||||
storageKey: text("storage_key").notNull(),
|
||||
originalFilename: text("original_filename").notNull(),
|
||||
mimeType: text("mime_type").notNull(),
|
||||
fileSize: integer("file_size").notNull(),
|
||||
width: integer("width").notNull(),
|
||||
height: integer("height").notNull(),
|
||||
altText: text("alt_text"),
|
||||
sortOrder: integer("sort_order").default(0).notNull(),
|
||||
isPrimary: boolean("is_primary").default(false).notNull(),
|
||||
processingStatus: text("processing_status").default("PENDING").notNull(),
|
||||
...timestamps,
|
||||
},
|
||||
(table) => [
|
||||
index("inventory_images_inventory_item_id_index").on(table.inventoryItemId),
|
||||
],
|
||||
);
|
||||
|
||||
export const imageDerivativeJobs = pgTable(
|
||||
'image_derivative_jobs',
|
||||
"image_derivative_jobs",
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
inventoryImageId: uuid('inventory_image_id')
|
||||
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'),
|
||||
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)],
|
||||
(table) => [
|
||||
index("image_derivative_jobs_image_id_index").on(table.inventoryImageId),
|
||||
],
|
||||
);
|
||||
|
||||
export const listings = pgTable('listings', {
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
inventoryItemId: uuid('inventory_item_id')
|
||||
.notNull()
|
||||
.references(() => inventoryItems.id),
|
||||
productName: text('product_name').notNull(),
|
||||
categoryId: uuid('category_id').notNull(),
|
||||
conditionId: uuid('condition_id')
|
||||
.notNull()
|
||||
.references(() => conditions.id),
|
||||
askingPriceMinor: integer('asking_price_minor').notNull(),
|
||||
status: listingStatus('status').default('DRAFT').notNull(),
|
||||
notes: text('notes'),
|
||||
...timestamps,
|
||||
}, (table) => [
|
||||
index('listings_inventory_item_id_index').on(table.inventoryItemId),
|
||||
index('listings_status_index').on(table.status),
|
||||
]);
|
||||
export const listings = pgTable(
|
||||
"listings",
|
||||
{
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
inventoryItemId: uuid("inventory_item_id")
|
||||
.notNull()
|
||||
.references(() => inventoryItems.id),
|
||||
productName: text("product_name").notNull(),
|
||||
categoryId: uuid("category_id").notNull(),
|
||||
conditionId: uuid("condition_id")
|
||||
.notNull()
|
||||
.references(() => conditions.id),
|
||||
askingPriceMinor: integer("asking_price_minor").notNull(),
|
||||
status: listingStatus("status").default("DRAFT").notNull(),
|
||||
notes: text("notes"),
|
||||
...timestamps,
|
||||
},
|
||||
(table) => [
|
||||
index("listings_inventory_item_id_index").on(table.inventoryItemId),
|
||||
index("listings_status_index").on(table.status),
|
||||
],
|
||||
);
|
||||
|
||||
export const sales = pgTable('sales', {
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
sellerId: uuid('seller_id')
|
||||
export const sales = pgTable("sales", {
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
sellerId: uuid("seller_id")
|
||||
.notNull()
|
||||
.references(() => sellers.id),
|
||||
status: text('status').default('COMPLETED').notNull(),
|
||||
saleDate: text('sale_date').notNull(),
|
||||
saleLocation: text('sale_location'),
|
||||
soldPriceMinor: integer('sold_price_minor').notNull(),
|
||||
currency: text('currency').notNull(),
|
||||
platformFeesMinor: integer('platform_fees_minor').default(0).notNull(),
|
||||
paymentProcessingFeesMinor: integer('payment_processing_fees_minor').default(0).notNull(),
|
||||
shippingCostMinor: integer('shipping_cost_minor').default(0).notNull(),
|
||||
taxesMinor: integer('taxes_minor').default(0).notNull(),
|
||||
otherFeesMinor: integer('other_fees_minor').default(0).notNull(),
|
||||
buyerName: text('buyer_name'),
|
||||
buyerContact: text('buyer_contact'),
|
||||
notes: text('notes'),
|
||||
voidReason: text('void_reason'),
|
||||
voidedAt: timestamp('voided_at', { withTimezone: true }),
|
||||
status: text("status").default("COMPLETED").notNull(),
|
||||
saleDate: text("sale_date").notNull(),
|
||||
saleLocation: text("sale_location"),
|
||||
soldPriceMinor: integer("sold_price_minor").notNull(),
|
||||
currency: text("currency").notNull(),
|
||||
platformFeesMinor: integer("platform_fees_minor").default(0).notNull(),
|
||||
paymentProcessingFeesMinor: integer("payment_processing_fees_minor")
|
||||
.default(0)
|
||||
.notNull(),
|
||||
shippingCostMinor: integer("shipping_cost_minor").default(0).notNull(),
|
||||
taxesMinor: integer("taxes_minor").default(0).notNull(),
|
||||
otherFeesMinor: integer("other_fees_minor").default(0).notNull(),
|
||||
buyerName: text("buyer_name"),
|
||||
buyerContact: text("buyer_contact"),
|
||||
notes: text("notes"),
|
||||
voidReason: text("void_reason"),
|
||||
voidedAt: timestamp("voided_at", { withTimezone: true }),
|
||||
...timestamps,
|
||||
});
|
||||
|
||||
export const saleItems = pgTable(
|
||||
'sale_items',
|
||||
"sale_items",
|
||||
{
|
||||
id: uuid('id').defaultRandom().primaryKey(),
|
||||
saleId: uuid('sale_id')
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
saleId: uuid("sale_id")
|
||||
.notNull()
|
||||
.references(() => sales.id),
|
||||
inventoryItemId: uuid('inventory_item_id')
|
||||
inventoryItemId: uuid("inventory_item_id")
|
||||
.notNull()
|
||||
.references(() => inventoryItems.id),
|
||||
soldPriceMinor: integer('sold_price_minor').notNull(),
|
||||
costBasisMinor: integer('cost_basis_minor').notNull(),
|
||||
soldPriceMinor: integer("sold_price_minor").notNull(),
|
||||
costBasisMinor: integer("cost_basis_minor").notNull(),
|
||||
},
|
||||
(table) => [
|
||||
uniqueIndex('sale_items_inventory_item_id_unique').on(table.inventoryItemId),
|
||||
index('sale_items_sale_id_index').on(table.saleId),
|
||||
uniqueIndex("sale_items_inventory_item_id_unique").on(
|
||||
table.inventoryItemId,
|
||||
),
|
||||
index("sale_items_sale_id_index").on(table.saleId),
|
||||
],
|
||||
);
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user