- Initialize Git repository with main branch - Create comprehensive .gitignore for Node.js, React, and environment files - Set up directory structure (frontend/, backend/, docs/) - Create detailed README.md with project overview and setup instructions - Add .env.example with all required environment variables - Configure Prettier for consistent code formatting All acceptance criteria met: ✅ Git repository initialized with appropriate .gitignore ✅ Directory structure matches Technical Assumptions ✅ README.md created with project overview and setup docs ✅ .env.example file with all required environment variables ✅ Prettier config files added for code formatting consistency 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
98 lines
2.7 KiB
Markdown
98 lines
2.7 KiB
Markdown
# Database Schema
|
|
|
|
## Prisma Schema Definition
|
|
|
|
```prisma
|
|
// prisma/schema.prisma
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
model Book {
|
|
id Int @id @default(autoincrement())
|
|
title String @db.VarChar(500)
|
|
author String? @db.VarChar(500)
|
|
totalPages Int
|
|
coverUrl String? @db.VarChar(1000)
|
|
deadlineDate DateTime @db.Date
|
|
isPrimary Boolean @default(false)
|
|
status String @default("reading") @db.VarChar(50)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
readingLogs ReadingLog[]
|
|
|
|
@@index([deadlineDate])
|
|
@@index([status])
|
|
}
|
|
|
|
model ReadingLog {
|
|
id Int @id @default(autoincrement())
|
|
bookId Int
|
|
logDate DateTime @db.Date
|
|
currentPage Int
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
book Book @relation(fields: [bookId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([bookId, logDate])
|
|
@@index([bookId])
|
|
@@index([logDate])
|
|
}
|
|
```
|
|
|
|
## SQL Schema (Generated)
|
|
|
|
```sql
|
|
-- Books table
|
|
CREATE TABLE "Book" (
|
|
"id" SERIAL PRIMARY KEY,
|
|
"title" VARCHAR(500) NOT NULL,
|
|
"author" VARCHAR(500),
|
|
"totalPages" INTEGER NOT NULL,
|
|
"coverUrl" VARCHAR(1000),
|
|
"deadlineDate" DATE NOT NULL,
|
|
"isPrimary" BOOLEAN NOT NULL DEFAULT false,
|
|
"status" VARCHAR(50) NOT NULL DEFAULT 'reading',
|
|
"createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP NOT NULL
|
|
);
|
|
|
|
-- Indexes for Books
|
|
CREATE INDEX "Book_deadlineDate_idx" ON "Book"("deadlineDate");
|
|
CREATE INDEX "Book_status_idx" ON "Book"("status");
|
|
|
|
-- Reading Logs table
|
|
CREATE TABLE "ReadingLog" (
|
|
"id" SERIAL PRIMARY KEY,
|
|
"bookId" INTEGER NOT NULL,
|
|
"logDate" DATE NOT NULL,
|
|
"currentPage" INTEGER NOT NULL,
|
|
"createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" TIMESTAMP NOT NULL,
|
|
CONSTRAINT "ReadingLog_book_fkey" FOREIGN KEY ("bookId") REFERENCES "Book"("id") ON DELETE CASCADE
|
|
);
|
|
|
|
-- Unique constraint: one log per book per day
|
|
CREATE UNIQUE INDEX "ReadingLog_bookId_logDate_key" ON "ReadingLog"("bookId", "logDate");
|
|
|
|
-- Indexes for ReadingLog
|
|
CREATE INDEX "ReadingLog_bookId_idx" ON "ReadingLog"("bookId");
|
|
CREATE INDEX "ReadingLog_logDate_idx" ON "ReadingLog"("logDate");
|
|
```
|
|
|
|
**Performance Considerations:**
|
|
- Indexes on `deadlineDate` and `status` for filtering active books
|
|
- Composite unique index on `(bookId, logDate)` prevents duplicate logs and optimizes queries
|
|
- Index on `logDate` for date range queries (7-day rolling average)
|
|
- Cascade delete ensures orphaned logs don't persist when book is deleted
|
|
|
|
---
|