|
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>; |