1 import { sql } from "drizzle-orm";
2 import { pgTable, text, varchar, integer, boolean, json, timestamp, jsonb, index } from "drizzle-orm/pg-core";
3 import { z } from "zod";
4
5 export const repairGuides = pgTable("repair_guides", {
6 id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
7 title: text("title").notNull(),
8 description: text("description").notNull(),
9 deviceType: text("device_type").notNull(), // "laptop" | "desktop"
10 category: text("category").notNull(), // "hardware" | "software" | "cleaning" | "upgrades"
11 difficulty: text("difficulty").notNull(), // "easy" | "medium" | "hard"
12 estimatedTime: text("estimated_time").notNull(), // "30-45 min"
13 toolsRequired: json("tools_required").$type<string[]>().notNull(),
14 safetyWarnings: json("safety_warnings").$type<string[]>().notNull(),
15 steps: json("steps").$type<RepairStep[]>().notNull(),
16 alternativeSolutions: text("alternative_solutions"),
17 imageUrl: text("image_url").notNull(),
18 viewCount: integer("view_count").default(0),
19 downloadCount: integer("download_count").default(0),
20 isBookmarked: boolean("is_bookmarked").default(false),
21 });
22
23 export const troubleshootingFlows = pgTable("troubleshooting_flows", {
24 id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
25 type: text("type").notNull(), // "power" | "performance" | "display"
26 title: text("title").notNull(),
27 description: text("description").notNull(),
28 steps: json("steps").$type<TroubleshootingStep[]>().notNull(),
29 });
30
31 export const deviceComponents = pgTable("device_components", {
32 id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
33 name: text("name").notNull(),
34 description: text("description").notNull(),
35 deviceType: text("device_type").notNull(),
36 category: text("category").notNull(),
37 safetyNotes: json("safety_notes").$type<string[]>().notNull(),
38 });
39
40 // Type definitions for complex JSON fields
41 export type RepairStep = {
42 stepNumber: number;
43 title: string;
44 description: string;
45 imageUrl?: string;
46 phase?: string;
47 subSteps?: string[];
48 torqueSpec?: string;
49 toolRequired?: string;
50 checkpoints?: string[];
51 notes?: string[];
52 warnings?: string[];
53 tips?: string[];
54 };
55
56 export type TroubleshootingStep = {
57 id: string;
58 question: string;
59 answers: {
60 text: string;
61 nextStepId?: string;
62 solutionId?: string;
63 }[];
64 };
65
66 // Insert schemas
67 export const insertRepairGuideSchema = z.object({
68 title: z.string(),
69 description: z.string(),
70 deviceType: z.string(),
71 category: z.string(),
72 difficulty: z.string(),
73 estimatedTime: z.string(),
74 toolsRequired: z.array(z.string()),
75 safetyWarnings: z.array(z.string()),
76 steps: z.array(z.object({
77 stepNumber: z.number(),
78 title: z.string(),
79 description: z.string(),
80 imageUrl: z.string().optional(),
81 phase: z.string().optional(),
82 subSteps: z.array(z.string()).optional(),
83 torqueSpec: z.string().optional(),
84 toolRequired: z.string().optional(),
85 checkpoints: z.array(z.string()).optional(),
86 notes: z.array(z.string()).optional(),
87 warnings: z.array(z.string()).optional(),
88 tips: z.array(z.string()).optional(),
89 })),
90 alternativeSolutions: z.string().optional().nullable(),
91 imageUrl: z.string(),
92 downloadCount: z.number().optional(),
93 });
94
95 export const insertTroubleshootingFlowSchema = z.object({
96 type: z.string(),
97 title: z.string(),
98 description: z.string(),
99 steps: z.array(z.object({
100 id: z.string(),
101 question: z.string(),
102 answers: z.array(z.object({
103 text: z.string(),
104 nextStepId: z.string().optional(),
105 solutionId: z.string().optional(),
106 })),
107 })),
108 });
109
110 export const insertDeviceComponentSchema = z.object({
111 name: z.string(),
112 description: z.string(),
113 deviceType: z.string(),
114 category: z.string(),
115 safetyNotes: z.array(z.string()),
116 });
117
118 // Types
119 export type RepairGuide = typeof repairGuides.$inferSelect;
120 export type InsertRepairGuide = z.infer<typeof insertRepairGuideSchema>;
121
122 export type TroubleshootingFlow = typeof troubleshootingFlows.$inferSelect;
123 export type InsertTroubleshootingFlow = z.infer<typeof insertTroubleshootingFlowSchema>;
124
125 export type DeviceComponent = typeof deviceComponents.$inferSelect;
126 export type InsertDeviceComponent = z.infer<typeof insertDeviceComponentSchema>;
127
128 // Session storage table
129 export const sessions = pgTable(
130 "sessions",
131 {
132 sid: varchar("sid").primaryKey(),
133 sess: jsonb("sess").notNull(),
134 expire: timestamp("expire").notNull(),
135 },
136 (table) => [index("IDX_session_expire").on(table.expire)],
137 );
138
139 // User storage table
140 export const users = pgTable("users", {
141 id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
142 email: varchar("email").unique().notNull(),
143 password: text("password").notNull(),
144 firstName: varchar("first_name"),
145 lastName: varchar("last_name"),
146 profileImageUrl: varchar("profile_image_url"),
147 role: varchar("role").default("user"),
148 createdAt: timestamp("created_at").defaultNow(),
149 updatedAt: timestamp("updated_at").defaultNow(),
150 });
151
152 // Favorites table
153 export const favorites = pgTable("favorites", {
154 id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
155 userId: varchar("user_id").notNull().references(() => users.id, { onDelete: "cascade" }),
156 itemType: text("item_type").notNull(),
157 itemId: varchar("item_id").notNull(),
158 itemTitle: text("item_title").notNull(),
159 itemImageUrl: text("item_image_url"),
160 createdAt: timestamp("created_at").defaultNow(),
161 });
162
163 // Device brands table
164 export const deviceBrands = pgTable("device_brands", {
165 id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
166 name: varchar("name").notNull(),
167 deviceType: text("device_type").notNull(),
168 logoUrl: varchar("logo_url"),
169 supportLevel: varchar("support_level").notNull().default("community"),
170 popularity: integer("popularity").default(0),
171 createdAt: timestamp("created_at").defaultNow(),
172 });
173
174 // Device models table
175 export const deviceModels = pgTable("device_models", {
176 id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
177 brandId: varchar("brand_id").notNull().references(() => deviceBrands.id),
178 name: varchar("name").notNull(),
179 series: varchar("series"),
180 year: integer("year"),
181 specifications: jsonb("specifications"),
182 commonIssues: jsonb("common_issues").default(sql`'[]'::jsonb`),
183 guideCount: integer("guide_count").default(0),
184 createdAt: timestamp("created_at").defaultNow(),
185 });
186
187 // Guide compatibility table
188 export const guideCompatibility = pgTable("guide_compatibility", {
189 id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
190 guideId: varchar("guide_id").notNull().references(() => repairGuides.id),
191 modelId: varchar("model_id").notNull().references(() => deviceModels.id),
192 compatibility: varchar("compatibility").notNull().default("compatible"),
193 notes: text("notes"),
194 createdAt: timestamp("created_at").defaultNow(),
195 });
196
197 // Insert schemas
198 export const insertUserSchema = z.object({
199 email: z.string().email(),
200 password: z.string(),
201 firstName: z.string().optional().nullable(),
202 lastName: z.string().optional().nullable(),
203 profileImageUrl: z.string().optional().nullable(),
204 role: z.string().optional().default("user"),
205 });
206
207 export const insertFavoriteSchema = z.object({
208 itemType: z.string(),
209 itemId: z.string(),
210 itemTitle: z.string(),
211 itemImageUrl: z.string().optional().nullable(),
212 });
213
214 export const insertDeviceBrandSchema = z.object({
215 name: z.string(),
216 deviceType: z.string(),
217 logoUrl: z.string().optional().nullable(),
218 supportLevel: z.string().default("community"),
219 popularity: z.number().optional().default(0),
220 });
221
222 export const insertDeviceModelSchema = z.object({
223 brandId: z.string(),
224 name: z.string(),
225 series: z.string().optional().nullable(),
226 year: z.number().optional().nullable(),
227 specifications: z.any().optional().nullable(),
228 commonIssues: z.any().optional().nullable(),
229 guideCount: z.number().optional().default(0),
230 });
231
232 export const insertGuideCompatibilitySchema = z.object({
233 guideId: z.string(),
234 modelId: z.string(),
235 compatibility: z.string().default("compatible"),
236 notes: z.string().optional().nullable(),
237 });
238
239 // Types for new tables
240 export type User = typeof users.$inferSelect;
241 export type UpsertUser = typeof users.$inferInsert;
242 export type InsertUser = z.infer<typeof insertUserSchema>;
243
244 export type Favorite = typeof favorites.$inferSelect;
245 export type InsertFavorite = z.infer<typeof insertFavoriteSchema>;
246
247 export type DeviceBrand = typeof deviceBrands.$inferSelect;
248 export type InsertDeviceBrand = z.infer<typeof insertDeviceBrandSchema>;
249
250 export type DeviceModel = typeof deviceModels.$inferSelect;
251 export type InsertDeviceModel = z.infer<typeof insertDeviceModelSchema>;
252
253 export type GuideCompatibility = typeof guideCompatibility.$inferSelect;
254 export type InsertGuideCompatibility = z.infer<typeof insertGuideCompatibilitySchema>;