airbnb-finder/prisma/schema.prisma

157 lines
4.9 KiB
Plaintext
Raw Normal View History

// This is your Prisma schema file
// Learn more: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
// ============================================
// MODELS
// ============================================
model Listing {
id String @id @default(cuid())
slug String @unique
airbnbUrl String @unique @map("airbnb_url")
normalizedUrl String @unique @map("normalized_url")
externalId String? @unique @map("external_id")
// Basic Info
title String
locationText String? @map("location_text")
latitude Float?
longitude Float?
// Pricing
nightlyPrice Float? @map("nightly_price")
totalPrice Float? @map("total_price")
currency String? @default("EUR")
priceStatus String? @map("price_status") // EXTRACTED, REQUIRES_TRIP_CONTEXT, UNKNOWN, PARTIAL
// Rating
rating Float?
reviewCount Int? @map("review_count")
// Capacity
guestCount Int? @map("guest_count")
officialGuestCount Int? @map("official_guest_count")
feat: massive Airbnb import pipeline overhaul + UI fixes 🔥 Scraper Improvements: - Add JSON-LD price extraction (regression fix) - Fix sleeping spotsPerUnit bug (was hardcoded to 2) - Remove stale CSS selectors, add robust fallbacks - Add JSON-LD price fallback in extraction pipeline - Improve sleeping parser regex (lastIndex bug fix) - Add 15+ new bed type patterns (murphy, day bed, hammock, plurals) - Smarter deriveSleepingFromBeds() with mixed bed logic 📅 Import Form UX: - Smart defaults (next weekend dates) - Auto-calculate nights display - URL param auto-detection (?check_in=&check_out=&adults=) - Better visual hierarchy with icons - Progress steps during import - Success redirect to listing detail page 🗑️ Delete Button Fix: - Add router.refresh() after successful delete - Inline error state instead of alert() - Admin delete button as proper client component ✏️ Edit/Admin Fixes: - Fix revalidatePath using slug instead of id - Fix redirect to detail page after edit - Add cascade delete logic to admin deleteListing - Extract delete to proper client component 🎨 UI States for Partial Data: - Price: 'Preis auf Anfrage' with context hint - Location: 'Ort nicht erkannt' instead of empty - Sleeping: placeholder when no data - Suitability: 3-state (yes/no/unknown) - Use formatPrice/formatRating utilities 🛏️ Sleeping Data Quality: - Add sleepingDataQuality to Prisma schema - Save quality (EXACT/DERIVED/UNKNOWN) to DB - Display '(geschätzt)' label for derived data 📊 Database: - Restore corrupted schema.prisma from git - Add sleepingDataQuality field - Push schema changes ✅ TypeScript: Zero errors ✅ Build: Successful
2026-03-12 08:07:52 +00:00
// Sleeping Analysis
maxSleepingPlaces Int? @map("max_sleeping_places")
suitableFor4 Boolean? @map("suitable_for_4")
extraMattressesNeededFor4 Int? @map("extra_mattresses_needed_for_4")
bedTypesSummary String? @map("bed_types_summary")
feat: massive Airbnb import pipeline overhaul + UI fixes 🔥 Scraper Improvements: - Add JSON-LD price extraction (regression fix) - Fix sleeping spotsPerUnit bug (was hardcoded to 2) - Remove stale CSS selectors, add robust fallbacks - Add JSON-LD price fallback in extraction pipeline - Improve sleeping parser regex (lastIndex bug fix) - Add 15+ new bed type patterns (murphy, day bed, hammock, plurals) - Smarter deriveSleepingFromBeds() with mixed bed logic 📅 Import Form UX: - Smart defaults (next weekend dates) - Auto-calculate nights display - URL param auto-detection (?check_in=&check_out=&adults=) - Better visual hierarchy with icons - Progress steps during import - Success redirect to listing detail page 🗑️ Delete Button Fix: - Add router.refresh() after successful delete - Inline error state instead of alert() - Admin delete button as proper client component ✏️ Edit/Admin Fixes: - Fix revalidatePath using slug instead of id - Fix redirect to detail page after edit - Add cascade delete logic to admin deleteListing - Extract delete to proper client component 🎨 UI States for Partial Data: - Price: 'Preis auf Anfrage' with context hint - Location: 'Ort nicht erkannt' instead of empty - Sleeping: placeholder when no data - Suitability: 3-state (yes/no/unknown) - Use formatPrice/formatRating utilities 🛏️ Sleeping Data Quality: - Add sleepingDataQuality to Prisma schema - Save quality (EXACT/DERIVED/UNKNOWN) to DB - Display '(geschätzt)' label for derived data 📊 Database: - Restore corrupted schema.prisma from git - Add sleepingDataQuality field - Push schema changes ✅ TypeScript: Zero errors ✅ Build: Successful
2026-03-12 08:07:52 +00:00
sleepingDataQuality String? @map("sleeping_data_quality") // EXACT, DERIVED, UNKNOWN
// Room Details
bedrooms Int?
beds Int?
bathrooms Float?
// Description
description String?
hostName String? @map("host_name")
cancellationPolicy String? @map("cancellation_policy")
// Amenities (stored as JSON string)
amenities String? @map("amenities")
// Status & Flags (using String instead of Enum for SQLite)
isFavorite Boolean @default(false) @map("is_favorite")
status String @default("NEW") // NEW, INTERESTING, SHORTLIST, BOOKED, REJECTED
// Images
coverImage String? @map("cover_image")
// Raw Data
rawSourceData String? @map("raw_source_data")
// Timestamps
importedAt DateTime @default(now()) @map("imported_at")
updatedAt DateTime @updatedAt @map("updated_at")
// Relations
images ListingImage[]
notes AdminNote[]
sleepingOptions ListingSleepingOption[]
tags ListingTag[]
// Indexes
@@index([status])
@@index([isFavorite])
@@index([locationText])
@@index([nightlyPrice])
@@index([rating])
@@map("listings")
}
model ListingImage {
id String @id @default(cuid())
listingId String @map("listing_id")
url String
alt String?
sortOrder Int @default(0) @map("sort_order")
isExternal Boolean @default(true) @map("is_external")
createdAt DateTime @default(now()) @map("created_at")
listing Listing @relation(fields: [listingId], references: [id], onDelete: Cascade)
@@index([listingId, sortOrder])
@@map("listing_images")
}
model AdminNote {
id String @id @default(cuid())
listingId String @map("listing_id")
body String
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
listing Listing @relation(fields: [listingId], references: [id], onDelete: Cascade)
@@index([listingId, createdAt])
@@map("admin_notes")
}
model Tag {
id String @id @default(cuid())
name String @unique
slug String @unique
color String? @default("#6366f1")
listings ListingTag[]
@@map("tags")
}
model ListingTag {
listingId String @map("listing_id")
tagId String @map("tag_id")
listing Listing @relation(fields: [listingId], references: [id], onDelete: Cascade)
tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
@@id([listingId, tagId])
@@map("listing_tags")
}
model ListingSleepingOption {
id String @id @default(cuid())
listingId String @map("listing_id")
bedType String @map("bed_type") // DOUBLE, SINGLE, SOFA_BED, etc.
quantity Int @default(1)
spotsPerUnit Int @default(1) @map("spots_per_unit")
quality String @default("FULL") // FULL, AUXILIARY
label String?
notes String?
listing Listing @relation(fields: [listingId], references: [id], onDelete: Cascade)
@@index([listingId])
@@map("listing_sleeping_options")
}