119 lines
4.0 KiB
Plaintext
119 lines
4.0 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
model User {
|
|
id String @id @default(cuid())
|
|
did String @unique
|
|
username String?
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
eventSources EventSource[]
|
|
events Event[]
|
|
|
|
@@map("users")
|
|
}
|
|
|
|
// External event source (Luma, Meetup, iCal feed, manual, etc.)
|
|
model EventSource {
|
|
id String @id @default(cuid())
|
|
name String
|
|
sourceType String @map("source_type") // luma, meetup, ical, manual, rss
|
|
color String @default("#6b7280")
|
|
isActive Boolean @default(true) @map("is_active")
|
|
// Connection config (API key, feed URL, org slug, etc.)
|
|
config Json @default("{}")
|
|
lastSyncedAt DateTime? @map("last_synced_at")
|
|
lastSyncError String @default("") @map("last_sync_error")
|
|
eventCount Int @default(0) @map("event_count")
|
|
|
|
createdById String @map("created_by_id")
|
|
createdBy User @relation(fields: [createdById], references: [id])
|
|
|
|
// Space scoping
|
|
spaceSlug String? @map("space_slug")
|
|
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
events Event[]
|
|
|
|
@@index([createdById])
|
|
@@index([spaceSlug])
|
|
@@map("event_sources")
|
|
}
|
|
|
|
model Event {
|
|
id String @id @default(cuid())
|
|
sourceId String @map("source_id")
|
|
externalId String @default("") @map("external_id")
|
|
externalUrl String @default("") @map("external_url")
|
|
|
|
// Core
|
|
title String
|
|
description String @default("")
|
|
start DateTime
|
|
end DateTime
|
|
allDay Boolean @default(false) @map("all_day")
|
|
timezoneStr String @default("UTC") @map("timezone_str")
|
|
rrule String @default("")
|
|
isRecurring Boolean @default(false) @map("is_recurring")
|
|
|
|
// Location
|
|
locationName String @default("") @map("location_name")
|
|
locationAddress String @default("") @map("location_address")
|
|
latitude Float?
|
|
longitude Float?
|
|
isVirtual Boolean @default(false) @map("is_virtual")
|
|
virtualUrl String @default("") @map("virtual_url")
|
|
virtualPlatform String @default("") @map("virtual_platform")
|
|
|
|
// Organizer / participants
|
|
organizerName String @default("") @map("organizer_name")
|
|
organizerEmail String @default("") @map("organizer_email")
|
|
organizerUrl String @default("") @map("organizer_url")
|
|
attendeeCount Int @default(0) @map("attendee_count")
|
|
maxAttendees Int? @map("max_attendees")
|
|
rsvpUrl String @default("") @map("rsvp_url")
|
|
|
|
// Categorization
|
|
status String @default("confirmed") // confirmed, tentative, cancelled
|
|
visibility String @default("public")
|
|
category String @default("") // conference, meetup, workshop, social, etc.
|
|
tags String[] @default([])
|
|
imageUrl String @default("") @map("image_url")
|
|
cost String @default("") // free, $10, etc.
|
|
|
|
// rStack integration
|
|
rToolSource String? @map("r_tool_source") // e.g. "rcal", "rinbox"
|
|
rToolEntityId String? @map("r_tool_entity_id")
|
|
syncedToRcal Boolean @default(false) @map("synced_to_rcal")
|
|
metadata Json?
|
|
|
|
// Ownership
|
|
createdById String? @map("created_by_id")
|
|
createdBy User? @relation(fields: [createdById], references: [id])
|
|
spaceSlug String? @map("space_slug")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
// Relations
|
|
source EventSource @relation(fields: [sourceId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([sourceId, externalId])
|
|
@@index([sourceId])
|
|
@@index([start, end])
|
|
@@index([spaceSlug])
|
|
@@index([category])
|
|
@@index([rToolSource, rToolEntityId])
|
|
@@map("events")
|
|
}
|