Merge branch 'worktree-agent-a64432fc' into Develop
# Conflicts: # .planning/STATE.md
This commit is contained in:
@@ -2,12 +2,12 @@
|
|||||||
gsd_state_version: 1.0
|
gsd_state_version: 1.0
|
||||||
milestone: v1.3
|
milestone: v1.3
|
||||||
milestone_name: Research & Decision Tools
|
milestone_name: Research & Decision Tools
|
||||||
status: Ready to discuss/plan
|
status: planning
|
||||||
stopped_at: Phase 19 context gathered
|
stopped_at: Completed 19-01-PLAN.md
|
||||||
last_updated: "2026-04-05T18:04:19.312Z"
|
last_updated: "2026-04-05T11:22:25.312Z"
|
||||||
last_activity: 2026-04-05
|
last_activity: 2026-04-05
|
||||||
progress:
|
progress:
|
||||||
total_phases: 13
|
total_phases: 12
|
||||||
completed_phases: 11
|
completed_phases: 11
|
||||||
total_plans: 33
|
total_plans: 33
|
||||||
completed_plans: 31
|
completed_plans: 31
|
||||||
@@ -21,16 +21,16 @@ progress:
|
|||||||
See: .planning/PROJECT.md (updated 2026-04-03)
|
See: .planning/PROJECT.md (updated 2026-04-03)
|
||||||
|
|
||||||
**Core value:** Help people make better gear decisions — discover what others use, compare real-world data, and see how a potential buy affects your setup before committing.
|
**Core value:** Help people make better gear decisions — discover what others use, compare real-world data, and see how a potential buy affects your setup before committing.
|
||||||
**Current focus:** v2.0 Platform Foundation — Phase 19 (Reference Item Model & Tags Schema)
|
**Current focus:** v2.0 Platform Foundation — Phase 14 (PostgreSQL Migration)
|
||||||
|
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 19 of 22 (Reference Item Model & Tags Schema)
|
Phase: 19 of 19 (Reference Item Model & Tags Schema)
|
||||||
Plan: Not started
|
Plan: 1 of 3
|
||||||
Status: Ready to discuss/plan
|
Status: Executing
|
||||||
Last activity: 2026-04-05
|
Last activity: 2026-04-05
|
||||||
|
|
||||||
Progress: [----------] 0% (v2.0 milestone)
|
Progress: [#---------] 3% (v2.0 milestone)
|
||||||
|
|
||||||
## Performance Metrics
|
## Performance Metrics
|
||||||
|
|
||||||
@@ -55,6 +55,9 @@ Key decisions made during v2.0 planning:
|
|||||||
- Separate globalItems table — not a flag on user items table
|
- Separate globalItems table — not a flag on user items table
|
||||||
- Single-user SQLite mode diverges at v2.0 boundary
|
- Single-user SQLite mode diverges at v2.0 boundary
|
||||||
- [Phase 18]: Profile data loaded via usePublicProfile(userId) not /auth/me extension
|
- [Phase 18]: Profile data loaded via usePublicProfile(userId) not /auth/me extension
|
||||||
|
- [Phase 19]: Direct globalItemId FK on items replaces itemGlobalLinks junction table
|
||||||
|
- [Phase 19]: Data migration SQL: UPDATE items before DROP TABLE item_global_links
|
||||||
|
- [Phase 19]: Flat tags system without type categorization per D-16
|
||||||
|
|
||||||
### Pending Todos
|
### Pending Todos
|
||||||
|
|
||||||
@@ -67,6 +70,6 @@ None active.
|
|||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-04-05T18:04:19.310Z
|
Last session: 2026-04-05T18:28:00Z
|
||||||
Stopped at: Phase 19 context gathered
|
Stopped at: Completed 19-01-PLAN.md
|
||||||
Resume file: .planning/phases/19-reference-item-model-tags-schema/19-CONTEXT.md
|
Resume file: None
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
---
|
||||||
|
phase: 19-reference-item-model-tags-schema
|
||||||
|
plan: 01
|
||||||
|
subsystem: database
|
||||||
|
tags: [drizzle, postgres, schema, migration, tags, reference-items]
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- phase: 18-global-items-public-profiles
|
||||||
|
provides: globalItems table and itemGlobalLinks junction table
|
||||||
|
provides:
|
||||||
|
- items.globalItemId direct FK replacing itemGlobalLinks junction table
|
||||||
|
- items.purchasePriceCents for user-specific purchase price tracking
|
||||||
|
- threadCandidates.globalItemId for catalog-linked candidates
|
||||||
|
- tags and globalItemTags tables for tag-based discovery
|
||||||
|
- Zod schemas with globalItemId and purchasePriceCents fields
|
||||||
|
- Tag and GlobalItemTag TypeScript types
|
||||||
|
- 30 curated seed tags for outdoor/adventure gear
|
||||||
|
affects: [19-02, 19-03, global-item-service, item-service, thread-service]
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "Reference item model: nullable globalItemId FK on items replaces junction table"
|
||||||
|
- "Tag system: flat tags table with many-to-many via globalItemTags"
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- drizzle-pg/0002_wakeful_vermin.sql
|
||||||
|
modified:
|
||||||
|
- src/db/schema.ts
|
||||||
|
- src/shared/schemas.ts
|
||||||
|
- src/shared/types.ts
|
||||||
|
- src/db/seed-global-items.ts
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "Data migration in SQL: UPDATE items SET global_item_id before DROP TABLE item_global_links"
|
||||||
|
- "Seed tags as flat list without type categorization per D-16"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "Reference items: globalItemId nullable FK on items table, when set base data comes from global item"
|
||||||
|
- "Tag seeding: idempotent async seedTags function alongside seedGlobalItems"
|
||||||
|
|
||||||
|
requirements-completed: [CATFLOW-03, TAG-01, TAG-02]
|
||||||
|
|
||||||
|
duration: 4min
|
||||||
|
completed: 2026-04-05
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 19 Plan 01: Reference Item Model & Tags Schema Summary
|
||||||
|
|
||||||
|
**Database schema updated with direct globalItemId FK on items/candidates, tags system tables, and data migration from itemGlobalLinks**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Duration:** 4 min
|
||||||
|
- **Started:** 2026-04-05T18:23:49Z
|
||||||
|
- **Completed:** 2026-04-05T18:28:00Z
|
||||||
|
- **Tasks:** 2
|
||||||
|
- **Files modified:** 5
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
- Added globalItemId and purchasePriceCents columns to items table, globalItemId to threadCandidates
|
||||||
|
- Created tags and globalItemTags tables for tag-based global item discovery
|
||||||
|
- Removed itemGlobalLinks junction table with safe data migration in SQL
|
||||||
|
- Updated Zod schemas with new fields, removed linkItemSchema
|
||||||
|
- Converted seed script to async with 30 curated outdoor/adventure tags
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
Each task was committed atomically:
|
||||||
|
|
||||||
|
1. **Task 1: Update schema.ts, generate migration with data migration step** - `5df513c` (feat)
|
||||||
|
2. **Task 2: Update Zod schemas, types, test helpers, and seed script** - `e9baa8d` (feat)
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
- `src/db/schema.ts` - Added globalItemId/purchasePriceCents to items, globalItemId to threadCandidates, tags + globalItemTags tables, removed itemGlobalLinks
|
||||||
|
- `src/shared/schemas.ts` - Added globalItemId/purchasePriceCents to createItemSchema, globalItemId to createCandidateSchema, tags to searchGlobalItemsSchema, removed linkItemSchema
|
||||||
|
- `src/shared/types.ts` - Added Tag and GlobalItemTag types, removed ItemGlobalLink and LinkItem
|
||||||
|
- `src/db/seed-global-items.ts` - Converted to async, added seedTags with 30 curated tags
|
||||||
|
- `drizzle-pg/0002_wakeful_vermin.sql` - Migration with ADD COLUMN, data migration UPDATE, DROP TABLE
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
- Reordered generated migration SQL to ensure data migration (UPDATE items SET global_item_id) runs before DROP TABLE item_global_links
|
||||||
|
- Kept seed tags as flat list per D-16 (no type categorization)
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
### Auto-fixed Issues
|
||||||
|
|
||||||
|
**1. [Rule 3 - Blocking] drizzle-kit generate interactive prompt**
|
||||||
|
- **Found during:** Task 1 (migration generation)
|
||||||
|
- **Issue:** drizzle-kit detected table rename ambiguity between itemGlobalLinks and globalItemTags, prompting interactively
|
||||||
|
- **Fix:** Used Bun.spawn with piped stdin to programmatically select "create table" option
|
||||||
|
- **Files modified:** None (tooling workaround)
|
||||||
|
- **Verification:** Migration file generated correctly
|
||||||
|
- **Committed in:** 5df513c (Task 1 commit)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Total deviations:** 1 auto-fixed (1 blocking)
|
||||||
|
**Impact on plan:** Tooling workaround only, no code impact.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
None beyond the drizzle-kit interactive prompt handled above.
|
||||||
|
|
||||||
|
## User Setup Required
|
||||||
|
None - no external service configuration required.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
- Schema foundation ready for service layer updates (plan 19-02)
|
||||||
|
- Services referencing itemGlobalLinks, linkItemToGlobal, unlinkItemFromGlobal need updating
|
||||||
|
- Test files referencing removed schema entities need updating
|
||||||
|
- Client code referencing LinkToGlobalItem component needs updating
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 19-reference-item-model-tags-schema*
|
||||||
|
*Completed: 2026-04-05*
|
||||||
27
drizzle-pg/0002_wakeful_vermin.sql
Normal file
27
drizzle-pg/0002_wakeful_vermin.sql
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
CREATE TABLE "tags" (
|
||||||
|
"id" serial PRIMARY KEY NOT NULL,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||||
|
CONSTRAINT "tags_name_unique" UNIQUE("name")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "global_item_tags" (
|
||||||
|
"global_item_id" integer NOT NULL,
|
||||||
|
"tag_id" integer NOT NULL,
|
||||||
|
CONSTRAINT "global_item_tags_global_item_id_tag_id_pk" PRIMARY KEY("global_item_id","tag_id")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "items" ADD COLUMN "global_item_id" integer;--> statement-breakpoint
|
||||||
|
ALTER TABLE "items" ADD COLUMN "purchase_price_cents" integer;--> statement-breakpoint
|
||||||
|
ALTER TABLE "thread_candidates" ADD COLUMN "global_item_id" integer;--> statement-breakpoint
|
||||||
|
UPDATE "items" SET "global_item_id" = (
|
||||||
|
SELECT "global_item_id" FROM "item_global_links"
|
||||||
|
WHERE "item_global_links"."item_id" = "items"."id"
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "item_global_links" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||||
|
DROP TABLE "item_global_links" CASCADE;--> statement-breakpoint
|
||||||
|
ALTER TABLE "global_item_tags" ADD CONSTRAINT "global_item_tags_global_item_id_global_items_id_fk" FOREIGN KEY ("global_item_id") REFERENCES "public"."global_items"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "global_item_tags" ADD CONSTRAINT "global_item_tags_tag_id_tags_id_fk" FOREIGN KEY ("tag_id") REFERENCES "public"."tags"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "items" ADD CONSTRAINT "items_global_item_id_global_items_id_fk" FOREIGN KEY ("global_item_id") REFERENCES "public"."global_items"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "thread_candidates" ADD CONSTRAINT "thread_candidates_global_item_id_global_items_id_fk" FOREIGN KEY ("global_item_id") REFERENCES "public"."global_items"("id") ON DELETE no action ON UPDATE no action;
|
||||||
1171
drizzle-pg/meta/0002_snapshot.json
Normal file
1171
drizzle-pg/meta/0002_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,13 @@
|
|||||||
"when": 1775386658636,
|
"when": 1775386658636,
|
||||||
"tag": "0001_tough_boomerang",
|
"tag": "0001_tough_boomerang",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 2,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1775413526643,
|
||||||
|
"tag": "0002_wakeful_vermin",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -55,6 +55,8 @@ export const items = pgTable("items", {
|
|||||||
imageFilename: text("image_filename"),
|
imageFilename: text("image_filename"),
|
||||||
imageSourceUrl: text("image_source_url"),
|
imageSourceUrl: text("image_source_url"),
|
||||||
quantity: integer("quantity").notNull().default(1),
|
quantity: integer("quantity").notNull().default(1),
|
||||||
|
globalItemId: integer("global_item_id").references(() => globalItems.id),
|
||||||
|
purchasePriceCents: integer("purchase_price_cents"),
|
||||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||||
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
||||||
});
|
});
|
||||||
@@ -97,6 +99,7 @@ export const threadCandidates = pgTable("thread_candidates", {
|
|||||||
pros: text("pros"),
|
pros: text("pros"),
|
||||||
cons: text("cons"),
|
cons: text("cons"),
|
||||||
sortOrder: doublePrecision("sort_order").notNull().default(0),
|
sortOrder: doublePrecision("sort_order").notNull().default(0),
|
||||||
|
globalItemId: integer("global_item_id").references(() => globalItems.id),
|
||||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||||
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
||||||
});
|
});
|
||||||
@@ -141,19 +144,29 @@ export const globalItems = pgTable("global_items", {
|
|||||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── Item Global Links ───────────────────────────────────────────────
|
// ── Tags ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
export const itemGlobalLinks = pgTable("item_global_links", {
|
export const tags = pgTable("tags", {
|
||||||
id: serial("id").primaryKey(),
|
id: serial("id").primaryKey(),
|
||||||
itemId: integer("item_id")
|
name: text("name").notNull().unique(),
|
||||||
.notNull()
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||||
.references(() => items.id, { onDelete: "cascade" })
|
|
||||||
.unique(),
|
|
||||||
globalItemId: integer("global_item_id")
|
|
||||||
.notNull()
|
|
||||||
.references(() => globalItems.id, { onDelete: "cascade" }),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ── Global Item Tags ───────────────────────────────────────────────
|
||||||
|
|
||||||
|
export const globalItemTags = pgTable(
|
||||||
|
"global_item_tags",
|
||||||
|
{
|
||||||
|
globalItemId: integer("global_item_id")
|
||||||
|
.notNull()
|
||||||
|
.references(() => globalItems.id, { onDelete: "cascade" }),
|
||||||
|
tagId: integer("tag_id")
|
||||||
|
.notNull()
|
||||||
|
.references(() => tags.id, { onDelete: "cascade" }),
|
||||||
|
},
|
||||||
|
(table) => [primaryKey({ columns: [table.globalItemId, table.tagId] })],
|
||||||
|
);
|
||||||
|
|
||||||
// ── Settings ────────────────────────────────────────────────────────
|
// ── Settings ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
export const settings = pgTable(
|
export const settings = pgTable(
|
||||||
|
|||||||
@@ -1,27 +1,73 @@
|
|||||||
import seedData from "./global-items-seed.json";
|
import seedData from "./global-items-seed.json";
|
||||||
import { db as prodDb } from "./index.ts";
|
import { db as prodDb } from "./index.ts";
|
||||||
import { globalItems } from "./schema.ts";
|
import { globalItems, tags } from "./schema.ts";
|
||||||
|
|
||||||
type Db = typeof prodDb;
|
type Db = typeof prodDb;
|
||||||
|
|
||||||
|
const SEED_TAGS = [
|
||||||
|
"handlebar-bag",
|
||||||
|
"framebag",
|
||||||
|
"saddlebag",
|
||||||
|
"top-tube-bag",
|
||||||
|
"stem-bag",
|
||||||
|
"fork-bag",
|
||||||
|
"hip-pack",
|
||||||
|
"backpack",
|
||||||
|
"tent",
|
||||||
|
"bivy",
|
||||||
|
"tarp",
|
||||||
|
"hammock",
|
||||||
|
"sleeping-bag",
|
||||||
|
"sleeping-pad",
|
||||||
|
"quilt",
|
||||||
|
"pillow",
|
||||||
|
"stove",
|
||||||
|
"cookware",
|
||||||
|
"water-filter",
|
||||||
|
"water-bottle",
|
||||||
|
"headlamp",
|
||||||
|
"bike-light",
|
||||||
|
"ultralight",
|
||||||
|
"waterproof",
|
||||||
|
"budget",
|
||||||
|
"premium",
|
||||||
|
"bikepacking",
|
||||||
|
"hiking",
|
||||||
|
"camping",
|
||||||
|
"touring",
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seed curated tags for outdoor/adventure gear.
|
||||||
|
* Idempotent: skips if any tags already exist.
|
||||||
|
*/
|
||||||
|
export async function seedTags(db: Db = prodDb) {
|
||||||
|
const existing = await db.select().from(tags).limit(1);
|
||||||
|
if (existing.length > 0) return;
|
||||||
|
|
||||||
|
for (const name of SEED_TAGS) {
|
||||||
|
await db.insert(tags).values({ name });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Seed the global items table with initial bikepacking gear data.
|
* Seed the global items table with initial bikepacking gear data.
|
||||||
* Idempotent: skips if any rows already exist.
|
* Idempotent: skips if any rows already exist.
|
||||||
*/
|
*/
|
||||||
export function seedGlobalItems(db: Db = prodDb) {
|
export async function seedGlobalItems(db: Db = prodDb) {
|
||||||
const existing = db.select().from(globalItems).limit(1).all();
|
const existing = await db.select().from(globalItems).limit(1);
|
||||||
if (existing.length > 0) return;
|
if (existing.length > 0) return;
|
||||||
|
|
||||||
for (const item of seedData) {
|
for (const item of seedData) {
|
||||||
db.insert(globalItems)
|
await db.insert(globalItems).values({
|
||||||
.values({
|
brand: item.brand,
|
||||||
brand: item.brand,
|
model: item.model,
|
||||||
model: item.model,
|
category: item.category ?? null,
|
||||||
category: item.category ?? null,
|
weightGrams: item.weightGrams ?? null,
|
||||||
weightGrams: item.weightGrams ?? null,
|
priceCents: item.priceCents ?? null,
|
||||||
priceCents: item.priceCents ?? null,
|
description: item.description ?? null,
|
||||||
description: item.description ?? null,
|
});
|
||||||
})
|
|
||||||
.run();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await seedTags(db);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ export const createItemSchema = z.object({
|
|||||||
imageFilename: z.string().optional(),
|
imageFilename: z.string().optional(),
|
||||||
imageSourceUrl: z.string().url().optional().or(z.literal("")),
|
imageSourceUrl: z.string().url().optional().or(z.literal("")),
|
||||||
quantity: z.number().int().positive().optional(),
|
quantity: z.number().int().positive().optional(),
|
||||||
|
globalItemId: z.number().int().positive().optional(),
|
||||||
|
purchasePriceCents: z.number().int().nonnegative().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const updateItemSchema = createItemSchema.partial().extend({
|
export const updateItemSchema = createItemSchema.partial().extend({
|
||||||
@@ -58,6 +60,7 @@ export const createCandidateSchema = z.object({
|
|||||||
status: candidateStatusSchema.optional(),
|
status: candidateStatusSchema.optional(),
|
||||||
pros: z.string().optional(),
|
pros: z.string().optional(),
|
||||||
cons: z.string().optional(),
|
cons: z.string().optional(),
|
||||||
|
globalItemId: z.number().int().positive().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const updateCandidateSchema = createCandidateSchema.partial();
|
export const updateCandidateSchema = createCandidateSchema.partial();
|
||||||
@@ -95,10 +98,7 @@ export const updateClassificationSchema = z.object({
|
|||||||
// Global item schemas
|
// Global item schemas
|
||||||
export const searchGlobalItemsSchema = z.object({
|
export const searchGlobalItemsSchema = z.object({
|
||||||
q: z.string().optional(),
|
q: z.string().optional(),
|
||||||
});
|
tags: z.string().optional(),
|
||||||
|
|
||||||
export const linkItemSchema = z.object({
|
|
||||||
globalItemId: z.number().int().positive(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Profile schemas
|
// Profile schemas
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ import type { z } from "zod";
|
|||||||
import type {
|
import type {
|
||||||
categories,
|
categories,
|
||||||
globalItems,
|
globalItems,
|
||||||
itemGlobalLinks,
|
globalItemTags,
|
||||||
items,
|
items,
|
||||||
setupItems,
|
setupItems,
|
||||||
setups,
|
setups,
|
||||||
|
tags,
|
||||||
threadCandidates,
|
threadCandidates,
|
||||||
threads,
|
threads,
|
||||||
} from "../db/schema.ts";
|
} from "../db/schema.ts";
|
||||||
@@ -15,7 +16,6 @@ import type {
|
|||||||
createItemSchema,
|
createItemSchema,
|
||||||
createSetupSchema,
|
createSetupSchema,
|
||||||
createThreadSchema,
|
createThreadSchema,
|
||||||
linkItemSchema,
|
|
||||||
reorderCandidatesSchema,
|
reorderCandidatesSchema,
|
||||||
resolveThreadSchema,
|
resolveThreadSchema,
|
||||||
searchGlobalItemsSchema,
|
searchGlobalItemsSchema,
|
||||||
@@ -49,7 +49,6 @@ export type UpdateClassification = z.infer<typeof updateClassificationSchema>;
|
|||||||
|
|
||||||
// Global item types
|
// Global item types
|
||||||
export type SearchGlobalItems = z.infer<typeof searchGlobalItemsSchema>;
|
export type SearchGlobalItems = z.infer<typeof searchGlobalItemsSchema>;
|
||||||
export type LinkItem = z.infer<typeof linkItemSchema>;
|
|
||||||
export type UpdateProfile = z.infer<typeof updateProfileSchema>;
|
export type UpdateProfile = z.infer<typeof updateProfileSchema>;
|
||||||
|
|
||||||
// Types inferred from Drizzle schema
|
// Types inferred from Drizzle schema
|
||||||
@@ -60,4 +59,5 @@ export type ThreadCandidate = typeof threadCandidates.$inferSelect;
|
|||||||
export type Setup = typeof setups.$inferSelect;
|
export type Setup = typeof setups.$inferSelect;
|
||||||
export type SetupItem = typeof setupItems.$inferSelect;
|
export type SetupItem = typeof setupItems.$inferSelect;
|
||||||
export type GlobalItem = typeof globalItems.$inferSelect;
|
export type GlobalItem = typeof globalItems.$inferSelect;
|
||||||
export type ItemGlobalLink = typeof itemGlobalLinks.$inferSelect;
|
export type Tag = typeof tags.$inferSelect;
|
||||||
|
export type GlobalItemTag = typeof globalItemTags.$inferSelect;
|
||||||
|
|||||||
Reference in New Issue
Block a user