93 lines
4.1 KiB
TypeScript
93 lines
4.1 KiB
TypeScript
import { pgTable, text, serial, integer, timestamp, boolean, decimal, uuid } from 'drizzle-orm/pg-core'
|
|
import { createInsertSchema, createSelectSchema } from 'drizzle-zod'
|
|
import { z } from 'zod'
|
|
|
|
// Users table
|
|
export const users = pgTable('users', {
|
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
username: text('username').unique().notNull(),
|
|
email: text('email').unique().notNull(),
|
|
passwordHash: text('password_hash').notNull(),
|
|
avatar: text('avatar'),
|
|
bio: text('bio'),
|
|
createdAt: timestamp('created_at').defaultNow().notNull(),
|
|
updatedAt: timestamp('updated_at').defaultNow().notNull()
|
|
})
|
|
|
|
// Reading library - tracks novels added to user's library
|
|
export const library = pgTable('library', {
|
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
userId: uuid('user_id').notNull(),
|
|
novelSlug: text('novel_slug').notNull(),
|
|
addedAt: timestamp('added_at').defaultNow().notNull(),
|
|
notes: text('notes')
|
|
})
|
|
|
|
// Reading progress - tracks where user left off
|
|
export const readingProgress = pgTable('reading_progress', {
|
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
userId: uuid('user_id').notNull(),
|
|
novelSlug: text('novel_slug').notNull(),
|
|
chapterSlug: text('chapter_slug').notNull(),
|
|
chapterNumber: integer('chapter_number').notNull(),
|
|
scrollProgress: integer('scroll_progress').notNull().default(0), // 0-100
|
|
lastReadAt: timestamp('last_read_at').defaultNow().notNull(),
|
|
readTime: integer('read_time').default(0) // in seconds
|
|
})
|
|
|
|
// User preferences - stores reader customizations
|
|
export const userPreferences = pgTable('user_preferences', {
|
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
userId: uuid('user_id').unique().notNull(),
|
|
fontSize: integer('font_size').default(16),
|
|
fontFamily: text('font_family').default('serif'), // serif, sans-serif, monospace
|
|
lineHeight: decimal('line_height', { precision: 3, scale: 2 }).default('1.8'),
|
|
backgroundColor: text('background_color').default('white'), // white, cream, gray, black
|
|
textColor: text('text_color').default('black'), // black, white, gray
|
|
theme: text('theme').default('light'), // light, dark, sepia
|
|
createdAt: timestamp('created_at').defaultNow().notNull(),
|
|
updatedAt: timestamp('updated_at').defaultNow().notNull()
|
|
})
|
|
|
|
// Bookmarks - user can bookmark specific passages
|
|
export const bookmarks = pgTable('bookmarks', {
|
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
userId: uuid('user_id').notNull(),
|
|
novelSlug: text('novel_slug').notNull(),
|
|
chapterSlug: text('chapter_slug').notNull(),
|
|
paragraph: integer('paragraph').notNull(),
|
|
content: text('content').notNull(),
|
|
createdAt: timestamp('created_at').defaultNow().notNull()
|
|
})
|
|
|
|
// Ratings and reviews
|
|
export const reviews = pgTable('reviews', {
|
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
userId: uuid('user_id').notNull(),
|
|
novelSlug: text('novel_slug').notNull(),
|
|
rating: integer('rating').notNull(), // 1-5
|
|
reviewText: text('review_text'),
|
|
helpful: integer('helpful').default(0),
|
|
createdAt: timestamp('created_at').defaultNow().notNull(),
|
|
updatedAt: timestamp('updated_at').defaultNow().notNull()
|
|
})
|
|
|
|
// Zod schemas for validation
|
|
export const insertUserSchema = createInsertSchema(users).omit({ id: true, createdAt: true, updatedAt: true })
|
|
export const selectUserSchema = createSelectSchema(users)
|
|
|
|
export const insertLibrarySchema = createInsertSchema(library).omit({ id: true, addedAt: true })
|
|
export const selectLibrarySchema = createSelectSchema(library)
|
|
|
|
export const insertReadingProgressSchema = createInsertSchema(readingProgress).omit({ id: true })
|
|
export const selectReadingProgressSchema = createSelectSchema(readingProgress)
|
|
|
|
export const insertUserPreferencesSchema = createInsertSchema(userPreferences).omit({ id: true, createdAt: true, updatedAt: true })
|
|
export const selectUserPreferencesSchema = createSelectSchema(userPreferences)
|
|
|
|
export const insertBookmarkSchema = createInsertSchema(bookmarks).omit({ id: true, createdAt: true })
|
|
export const selectBookmarkSchema = createSelectSchema(bookmarks)
|
|
|
|
export const insertReviewSchema = createInsertSchema(reviews).omit({ id: true, createdAt: true, updatedAt: true })
|
|
export const selectReviewSchema = createSelectSchema(reviews)
|