|
1
|
import { sql } from "drizzle-orm"; |
|
2
|
import { pgTable, text, varchar, integer, boolean, json, timestamp, jsonb, index } from "drizzle-orm/pg-core"; |
|
3
|
import { createInsertSchema } from "drizzle-zod"; |
|
4
|
import { z } from "zod"; |
|
5
|
|
|
6
|
export const repairGuides = pgTable("repair_guides", { |
|
7
|
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`), |
|
8
|
title: text("title").notNull(), |
|
9
|
description: text("description").notNull(), |
|
10
|
deviceType: text("device_type").notNull(), // "laptop" | "desktop" |
|
11
|
category: text("category").notNull(), // "hardware" | "software" | "cleaning" | "upgrades" |
|
12
|
difficulty: text("difficulty").notNull(), // "easy" | "medium" | "hard" |
|
13
|
estimatedTime: text("estimated_time").notNull(), // "30-45 min" |
|
14
|
toolsRequired: json("tools_required").$type<string[]>().notNull(), |
|
15
|
safetyWarnings: json("safety_warnings").$type<string[]>().notNull(), |
|
16
|
steps: json("steps").$type<RepairStep[]>().notNull(), |
|
17
|
alternativeSolutions: text("alternative_solutions"), |
|
18
|
imageUrl: text("image_url").notNull(), |
|
19
|
viewCount: integer("view_count").default(0), |
|
20
|
downloadCount: integer("download_count").default(0), |
|
21
|
isBookmarked: boolean("is_bookmarked").default(false), |
|
22
|
}); |
|
23
|
|
|
24
|
export const troubleshootingFlows = pgTable("troubleshooting_flows", { |
|
25
|
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`), |
|
26
|
type: text("type").notNull(), // "power" | "performance" | "display" |
|
27
|
title: text("title").notNull(), |
|
28
|
description: text("description").notNull(), |
|
29
|
steps: json("steps").$type<TroubleshootingStep[]>().notNull(), |
|
30
|
}); |
|
31
|
|
|
32
|
export const deviceComponents = pgTable("device_components", { |
|
33
|
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`), |
|
34
|
name: text("name").notNull(), |
|
35
|
description: text("description").notNull(), |
|
36
|
deviceType: text("device_type").notNull(), |
|
37
|
category: text("category").notNull(), |
|
38
|
safetyNotes: json("safety_notes").$type<string[]>().notNull(), |
|
39
|
}); |
|
40
|
|
|
41
|
// Type definitions for complex JSON fields |
|
42
|
export type RepairStep = { |
|
43
|
stepNumber: number; |
|
44
|
title: string; |
|
45
|
description: string; |
|
46
|
imageUrl?: string; |
|
47
|
notes?: string[]; |
|
48
|
warnings?: string[]; |
|
49
|
}; |
|
50
|
|
|
51
|
export type TroubleshootingStep = { |
|
52
|
id: string; |
|
53
|
question: string; |
|
54
|
answers: { |
|
55
|
text: string; |
|
56
|
nextStepId?: string; |
|
57
|
solutionId?: string; |
|
58
|
}[]; |
|
59
|
}; |
|
60
|
|
|
61
|
// Insert schemas |
|
62
|
export const insertRepairGuideSchema = createInsertSchema(repairGuides).omit({ |
|
63
|
id: true, |
|
64
|
viewCount: true, |
|
65
|
isBookmarked: true, |
|
66
|
}); |
|
67
|
|
|
68
|
export const insertTroubleshootingFlowSchema = createInsertSchema(troubleshootingFlows).omit({ |
|
69
|
id: true, |
|
70
|
}); |
|
71
|
|
|
72
|
export const insertDeviceComponentSchema = createInsertSchema(deviceComponents).omit({ |
|
73
|
id: true, |
|
74
|
}); |
|
75
|
|
|
76
|
// Types |
|
77
|
export type RepairGuide = typeof repairGuides.$inferSelect; |
|
78
|
export type InsertRepairGuide = z.infer<typeof insertRepairGuideSchema>; |
|
79
|
|
|
80
|
export type TroubleshootingFlow = typeof troubleshootingFlows.$inferSelect; |
|
81
|
export type InsertTroubleshootingFlow = z.infer<typeof insertTroubleshootingFlowSchema>; |
|
82
|
|
|
83
|
export type DeviceComponent = typeof deviceComponents.$inferSelect; |
|
84
|
export type InsertDeviceComponent = z.infer<typeof insertDeviceComponentSchema>; |
|
85
|
|
|
86
|
// Session storage table for Replit Auth |
|
87
|
export const sessions = pgTable( |
|
88
|
"sessions", |
|
89
|
{ |
|
90
|
sid: varchar("sid").primaryKey(), |
|
91
|
sess: jsonb("sess").notNull(), |
|
92
|
expire: timestamp("expire").notNull(), |
|
93
|
}, |
|
94
|
(table) => [index("IDX_session_expire").on(table.expire)], |
|
95
|
); |
|
96
|
|
|
97
|
// User storage table for Replit Auth |
|
98
|
export const users = pgTable("users", { |
|
99
|
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`), |
|
100
|
email: varchar("email").unique().notNull(), |
|
101
|
password: text("password").notNull(), |
|
102
|
firstName: varchar("first_name"), |
|
103
|
lastName: varchar("last_name"), |
|
104
|
profileImageUrl: varchar("profile_image_url"), |
|
105
|
role: varchar("role").default("user"), // "admin" gets extra powers |
|
106
|
createdAt: timestamp("created_at").defaultNow(), |
|
107
|
updatedAt: timestamp("updated_at").defaultNow(), |
|
108
|
}); |
|
109
|
|
|
110
|
// Favorites table to store user's favorite guides and videos |
|
111
|
export const favorites = pgTable("favorites", { |
|
112
|
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`), |
|
113
|
userId: varchar("user_id").notNull().references(() => users.id, { onDelete: "cascade" }), |
|
114
|
itemType: text("item_type").notNull(), // "guide" | "video" | "troubleshooting" |
|
115
|
itemId: varchar("item_id").notNull(), // ID of the favorited item |
|
116
|
itemTitle: text("item_title").notNull(), // Cache the title for quick display |
|
117
|
itemImageUrl: text("item_image_url"), // Cache image URL |
|
118
|
createdAt: timestamp("created_at").defaultNow(), |
|
119
|
}); |
|
120
|
|
|
121
|
// Device brands table |
|
122
|
export const deviceBrands = pgTable("device_brands", { |
|
123
|
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`), |
|
124
|
name: varchar("name").notNull(), |
|
125
|
deviceType: text("device_type").notNull(), // 'laptop' or 'desktop' |
|
126
|
logoUrl: varchar("logo_url"), |
|
127
|
supportLevel: varchar("support_level").notNull().default("community"), // 'official', 'community', 'basic' |
|
128
|
popularity: integer("popularity").default(0), // For sorting brands by popularity |
|
129
|
createdAt: timestamp("created_at").defaultNow(), |
|
130
|
}); |
|
131
|
|
|
132
|
// Device models table |
|
133
|
export const deviceModels = pgTable("device_models", { |
|
134
|
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`), |
|
135
|
brandId: varchar("brand_id").notNull().references(() => deviceBrands.id), |
|
136
|
name: varchar("name").notNull(), |
|
137
|
series: varchar("series"), // e.g., "ThinkPad", "Inspiron", "Pavilion" |
|
138
|
year: integer("year"), |
|
139
|
specifications: jsonb("specifications"), // CPU, RAM, storage, etc. |
|
140
|
commonIssues: jsonb("common_issues").default(sql`'[]'::jsonb`), // Array of common problems |
|
141
|
guideCount: integer("guide_count").default(0), // Number of compatible guides |
|
142
|
createdAt: timestamp("created_at").defaultNow(), |
|
143
|
}); |
|
144
|
|
|
145
|
// Guide compatibility table (many-to-many between guides and models) |
|
146
|
export const guideCompatibility = pgTable("guide_compatibility", { |
|
147
|
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`), |
|
148
|
guideId: varchar("guide_id").notNull().references(() => repairGuides.id), |
|
149
|
modelId: varchar("model_id").notNull().references(() => deviceModels.id), |
|
150
|
compatibility: varchar("compatibility").notNull().default("compatible"), // 'compatible', 'partial', 'not_compatible' |
|
151
|
notes: text("notes"), // Specific notes about compatibility |
|
152
|
createdAt: timestamp("created_at").defaultNow(), |
|
153
|
}); |
|
154
|
|
|
155
|
// Insert schemas for new tables |
|
156
|
export const insertUserSchema = createInsertSchema(users).omit({ |
|
157
|
id: true, |
|
158
|
createdAt: true, |
|
159
|
updatedAt: true, |
|
160
|
}); |
|
161
|
|
|
162
|
export const insertFavoriteSchema = createInsertSchema(favorites).omit({ |
|
163
|
id: true, |
|
164
|
createdAt: true, |
|
165
|
}); |
|
166
|
|
|
167
|
export const insertDeviceBrandSchema = createInsertSchema(deviceBrands).omit({ |
|
168
|
id: true, |
|
169
|
createdAt: true, |
|
170
|
}); |
|
171
|
|
|
172
|
export const insertDeviceModelSchema = createInsertSchema(deviceModels).omit({ |
|
173
|
id: true, |
|
174
|
createdAt: true, |
|
175
|
}); |
|
176
|
|
|
177
|
export const insertGuideCompatibilitySchema = createInsertSchema(guideCompatibility).omit({ |
|
178
|
id: true, |
|
179
|
createdAt: true, |
|
180
|
}); |
|
181
|
|
|
182
|
// Types for new tables |
|
183
|
export type User = typeof users.$inferSelect; |
|
184
|
export type UpsertUser = typeof users.$inferInsert; |
|
185
|
export type InsertUser = z.infer<typeof insertUserSchema>; |
|
186
|
|
|
187
|
export type Favorite = typeof favorites.$inferSelect; |
|
188
|
export type InsertFavorite = z.infer<typeof insertFavoriteSchema>; |
|
189
|
|
|
190
|
export type DeviceBrand = typeof deviceBrands.$inferSelect; |
|
191
|
export type InsertDeviceBrand = z.infer<typeof insertDeviceBrandSchema>; |
|
192
|
|
|
193
|
export type DeviceModel = typeof deviceModels.$inferSelect; |
|
194
|
export type InsertDeviceModel = z.infer<typeof insertDeviceModelSchema>; |
|
195
|
|
|
196
|
export type GuideCompatibility = typeof guideCompatibility.$inferSelect; |
|
197
|
export type InsertGuideCompatibility = z.infer<typeof insertGuideCompatibilitySchema>; |