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