feat: add GIF Mood Board workshop
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 4m5s

- New workshop where each team member shares up to 5 GIFs with notes to express their weekly mood
- Per-user week rating (1-5 stars) visible next to each member's section
- Masonry-style grid with adjustable column count (3/4/5) toggle
- Handwriting font (Caveat) for GIF notes
- Full real-time collaboration via SSE
- Clean migration (add_gif_mood_workshop) safe for production deploy
- DB backup via cp before each migration in docker-entrypoint

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-03 10:04:56 +01:00
parent 7c68fb81e3
commit 766f3d5a59
21 changed files with 2032 additions and 15 deletions

View File

@@ -34,6 +34,12 @@ model User {
sharedWeatherSessions WeatherSessionShare[]
weatherSessionEvents WeatherSessionEvent[]
weatherEntries WeatherEntry[]
// GIF Mood Board relations
gifMoodSessions GifMoodSession[]
gifMoodItems GifMoodItem[]
sharedGifMoodSessions GMSessionShare[]
gifMoodSessionEvents GMSessionEvent[]
gifMoodRatings GifMoodUserRating[]
// Teams & OKRs relations
createdTeams Team[]
teamMembers TeamMember[]
@@ -525,3 +531,81 @@ model WeatherSessionEvent {
@@index([sessionId, createdAt])
}
// ============================================
// GIF Mood Board Workshop
// ============================================
model GifMoodSession {
id String @id @default(cuid())
title String
date DateTime @default(now())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
items GifMoodItem[]
shares GMSessionShare[]
events GMSessionEvent[]
ratings GifMoodUserRating[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([userId])
@@index([date])
}
model GifMoodUserRating {
id String @id @default(cuid())
sessionId String
session GifMoodSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
rating Int // 1-5
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([sessionId, userId])
@@index([sessionId])
}
model GifMoodItem {
id String @id @default(cuid())
sessionId String
session GifMoodSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
gifUrl String
note String?
order Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([sessionId, userId])
@@index([sessionId])
}
model GMSessionShare {
id String @id @default(cuid())
sessionId String
session GifMoodSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
role ShareRole @default(EDITOR)
createdAt DateTime @default(now())
@@unique([sessionId, userId])
@@index([sessionId])
@@index([userId])
}
model GMSessionEvent {
id String @id @default(cuid())
sessionId String
session GifMoodSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
type String // GIF_ADDED, GIF_UPDATED, GIF_DELETED, SESSION_UPDATED
payload String // JSON payload
createdAt DateTime @default(now())
@@index([sessionId, createdAt])
}