diff --git a/CLAUDE.md b/CLAUDE.md index 880b7e62..c1b4946a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -52,27 +52,21 @@ npm run type-check # TypeScript type checking ### Database Operations -The project uses **two Prisma schemas**: - -- `prisma/schema.prisma` - MySQL schema (original) -- `prisma/schema.sqlite.prisma` - SQLite schema (current) - -**Always specify `--schema=./prisma/schema.sqlite.prisma`** for local -development. +The project uses SQLite with Prisma. The schema is at `prisma/schema.prisma`. ```bash # Development database (dev.db) -npm run dev # Auto-generates Prisma client for dev.db +npm run dev # Auto-generates Prisma client for dev.db # Production database (prod.db) - from MySQL dumps -npm run prod # Auto-generates Prisma client for prod.db +npm run prod # Auto-generates Prisma client for prod.db # Database management -npx prisma studio --schema=./prisma/schema.sqlite.prisma # Open Prisma Studio -npx prisma db push --schema=./prisma/schema.sqlite.prisma # Push schema changes -npx prisma migrate dev --name --schema=./prisma/schema.sqlite.prisma # Create migration -npx prisma migrate reset --force --schema=./prisma/schema.sqlite.prisma # Reset DB and run seed -npx prisma generate --schema=./prisma/schema.sqlite.prisma # Generate Prisma Client +npx prisma studio # Open Prisma Studio +npx prisma db push # Push schema changes +npx prisma migrate dev --name # Create migration +npx prisma migrate reset --force # Reset DB and run seed +npx prisma generate # Generate Prisma Client ``` **Three SQLite databases**: @@ -88,6 +82,23 @@ npm run setup # Install deps, reset DB, run E2E tests npm run presetup # Install Playwright browser dependencies ``` +### Database Inspection + +```bash +# Inspect dev.db with Prisma Studio +npx prisma studio + +# Inspect prod.db with Prisma Studio +DATABASE_URL="file:./prod.db" npx prisma studio + +# Direct SQLite queries +sqlite3 prisma/dev.db +sqlite3 prisma/prod.db + +# Browse prod data via UI (starts dev server with prod.db) +npm run prod +``` + ## Architecture ### Tech Stack @@ -147,8 +158,7 @@ app/ └── root.tsx # Root layout prisma/ -├── schema.prisma # MySQL schema (original) -├── schema.sqlite.prisma # SQLite schema (current) +├── schema.prisma # Prisma schema (SQLite) ├── migrations/ # Migration files ├── seed.ts # Seed data script ├── dumps/ # Database dumps (gitignored) @@ -268,8 +278,7 @@ Pre-commit hooks run: ## Important Notes -- **Database schema**: Always use `schema.sqlite.prisma` with `--schema` flag - for local work +- **Database schema**: Schema is at `prisma/schema.prisma` - **Environment**: Copy `.env.example` to `.env` before starting - **Node version**: Requires Node.js >= 14 - **Git hooks**: Husky manages pre-commit hooks for linting and testing diff --git a/Dockerfile b/Dockerfile index af4903db..636435b1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,8 +17,8 @@ COPY package.json package-lock.json ./ RUN npm ci # Copy Prisma schema and generate client -COPY prisma/schema.sqlite.prisma ./prisma/ -RUN npx prisma generate --schema=./prisma/schema.sqlite.prisma +COPY prisma/schema.prisma ./prisma/ +RUN npx prisma generate # Copy application source COPY . . @@ -51,8 +51,8 @@ COPY package.json ./ COPY --from=build /app/node_modules ./node_modules # Copy Prisma schema and regenerate client for Alpine's OpenSSL version -COPY --from=build /app/prisma/schema.sqlite.prisma ./prisma/ -RUN npx prisma generate --schema=./prisma/schema.sqlite.prisma +COPY --from=build /app/prisma/schema.prisma ./prisma/ +RUN npx prisma generate # Copy built application COPY --from=build /app/build ./build diff --git a/docs/database-migration.md b/docs/database-migration.md index 9b19074d..f7506f4f 100644 --- a/docs/database-migration.md +++ b/docs/database-migration.md @@ -41,8 +41,7 @@ prisma/ │ │ └── kelas.Transaction.00001.sql │ └── prod/ # Converted SQLite dumps (generated, not committed) │ └── [same files as main, converted to SQLite] -├── schema.prisma # Prisma schema for MySQL (original) -└── schema.sqlite.prisma # Prisma schema for SQLite +└── schema.prisma # Prisma schema for SQLite ``` ## Migration Process @@ -54,11 +53,10 @@ converted to SQLite-compatible format using the `convert-dumps.js` script. ### Step 2: Create Database Schema -The SQLite database is created using Prisma with the `schema.sqlite.prisma` -schema file: +The SQLite database is created using Prisma: ```bash -DATABASE_URL="file:./prod.db" npx prisma db push --schema=prisma/schema.sqlite.prisma --skip-generate +DATABASE_URL="file:./prod.db" npx prisma db push --skip-generate ``` ### Step 3: Import Data @@ -164,7 +162,7 @@ This script: ### 4. Create the database schema ```bash -DATABASE_URL="file:./prod.db" npx prisma db push --schema=prisma/schema.sqlite.prisma --skip-generate +DATABASE_URL="file:./prod.db" npx prisma db push --skip-generate ``` ### 5. Import the data @@ -265,8 +263,8 @@ If you encounter foreign key constraint errors during data import: ### Missing Tables -If tables are not created, verify the `schema.sqlite.prisma` file exists and the -Prisma command was executed correctly. +If tables are not created, verify `prisma/schema.prisma` exists and the Prisma +command was executed correctly. ## Environment Variables diff --git a/package.json b/package.json index 1fd436bc..850e9921 100644 --- a/package.json +++ b/package.json @@ -7,19 +7,19 @@ "seed": "node --require esbuild-register prisma/seed.ts" }, "scripts": { - "build": "prisma generate --schema=./prisma/schema.sqlite.prisma && cross-env NODE_ENV=production npm run build:css && remix build", + "build": "prisma generate && cross-env NODE_ENV=production npm run build:css && remix build", "build:css": "tailwindcss --minify -o ./app/tailwind.css", "build:remix": "cross-env NODE_ENV=production remix build --sourcemap", - "dev": "cross-env DATABASE_URL=file:./dev.db NODE_ENV=development prisma generate --schema=./prisma/schema.sqlite.prisma && concurrently -k \"npm run dev:css\" \"remix dev\"", + "dev": "cross-env DATABASE_URL=file:./dev.db NODE_ENV=development prisma generate && concurrently -k \"npm run dev:css\" \"remix dev\"", "dev:css": "tailwindcss -o ./app/tailwind.css --watch", - "prod": "cross-env DATABASE_URL=file:./prod.db NODE_ENV=development prisma generate --schema=./prisma/schema.sqlite.prisma && concurrently -k \"npm run prod:css\" \"remix dev\"", + "prod": "cross-env DATABASE_URL=file:./prod.db NODE_ENV=development prisma generate && concurrently -k \"npm run prod:css\" \"remix dev\"", "prod:css": "tailwindcss -o ./app/tailwind.css --watch", "format": "prettier --write \"./**/*.{ts,tsx,js,jsx,yml,yaml,md}\"", "lint": "eslint \"**/*.{js,jsx,ts,tsx,yml,yaml}\"", "lint:fix": "eslint --fix \"**/*.{js,jsx,ts,tsx,yml,yaml}\"", "prepare": "husky install", "start": "remix-serve build", - "prestart:e2e": "DATABASE_URL=file:./test.db prisma migrate reset --force --schema=./prisma/schema.sqlite.prisma && npm run build:css", + "prestart:e2e": "DATABASE_URL=file:./test.db prisma migrate reset --force && npm run build:css", "start:e2e": "cross-env RUNNING_E2E=true DATABASE_URL=file:./test.db remix dev", "test": "vitest run", "test:coverage": "vitest run --coverage", @@ -30,7 +30,7 @@ "test:e2e:docker": "playwright test --config=playwright.docker.config.ts", "test:e2e:production": "cross-env BASE_URL=https://kelas.rumahberbagi.com playwright test --config=playwright.docker.config.ts", "type-check": "tsc --noEmit", - "setup": "npm install && prisma migrate reset --force --schema=./prisma/schema.sqlite.prisma && npm run test:e2e:run", + "setup": "npm install && prisma migrate reset --force && npm run test:e2e:run", "presetup": "npx playwright install-deps" }, "dependencies": { diff --git a/prisma/schema.prisma b/prisma/schema.prisma index a5dd27d3..490118c1 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1,12 +1,10 @@ generator client { - provider = "prisma-client-js" - previewFeatures = ["referentialIntegrity"] + provider = "prisma-client-js" } datasource db { - provider = "mysql" - url = env("DATABASE_URL") - referentialIntegrity = "prisma" + provider = "sqlite" + url = env("DATABASE_URL") } model User { @@ -68,7 +66,7 @@ model Transaction { amount Int datetime DateTime? status String - notes String? @db.Text + notes String? user User @relation("UserTransactions", fields: [userId], references: [id], onDelete: Cascade) author User @relation("UserSales", fields: [authorId], references: [id], onDelete: Cascade) course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) @@ -91,7 +89,7 @@ model Lesson { updatedAt DateTime @updatedAt chapterId String name String - description String? @db.Text + description String? videoId String order Int chapter Chapter @relation(fields: [chapterId], references: [id], onDelete: Cascade) diff --git a/prisma/schema.sqlite.prisma b/prisma/schema.sqlite.prisma deleted file mode 100644 index 490118c1..00000000 --- a/prisma/schema.sqlite.prisma +++ /dev/null @@ -1,107 +0,0 @@ -generator client { - provider = "prisma-client-js" -} - -datasource db { - provider = "sqlite" - url = env("DATABASE_URL") -} - -model User { - id String @id @default(uuid()) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - email String @unique(map: "User.email_unique") - name String? - phoneNumber String? - telegram String? - instagram String? - role String - courses Course[] - subscriptions Subscription[] @relation("UserSubscriptions") - subscribers Subscription[] @relation("UserSubscribers") - transactions Transaction[] @relation("UserTransactions") - sales Transaction[] @relation("UserSales") -} - -model Subscription { - id String @id @default(uuid()) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - userId String - authorId String - courseId String - status String - course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) - user User @relation("UserSubscriptions", fields: [userId], references: [id], onDelete: Cascade) - author User @relation("UserSubscribers", fields: [authorId], references: [id], onDelete: Cascade) -} - -model Course { - id String @id @default(uuid()) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - authorId String - name String - description String - price Int - image String - category String - author User @relation(fields: [authorId], references: [id], onDelete: Cascade) - subscriptions Subscription[] - transactions Transaction[] - chapters Chapter[] -} - -model Transaction { - id String @id @default(uuid()) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - userId String - courseId String - authorId String - bankName String - bankAccountNumber String - bankAccountName String - amount Int - datetime DateTime? - status String - notes String? - user User @relation("UserTransactions", fields: [userId], references: [id], onDelete: Cascade) - author User @relation("UserSales", fields: [authorId], references: [id], onDelete: Cascade) - course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) -} - -model Chapter { - id String @id @default(uuid()) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - courseId String - name String - order Int - course Course @relation(fields: [courseId], references: [id], onDelete: Cascade) - lessons Lesson[] -} - -model Lesson { - id String @id @default(uuid()) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - chapterId String - name String - description String? - videoId String - order Int - chapter Chapter @relation(fields: [chapterId], references: [id], onDelete: Cascade) - attachments Attachment[] -} - -model Attachment { - id String @id @default(uuid()) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - name String - url String - lessonId String - lesson Lesson @relation(fields: [lessonId], references: [id], onDelete: Cascade) -}