Files
Todo/prisma/schema.prisma
Paul Bailey 7cda58440f feat: implement complete web push notification system
- Add self-hosted push notifications using VAPID (no external services)
- Create PushSubscription model in database
- Implement server-side push logic with web-push library
- Add notification helpers for list events (items, invitations, collaborators)
- Create NotificationSettings UI component for profile page
- Add usePushNotifications React hook for subscription management
- Create API routes for subscription management and VAPID key
- Update service worker with push event handlers
- Integrate notifications into item actions (add, remove, complete)
- Integrate notifications into sharing actions (invite, accept, remove)
- Add VAPID key generation script
- Add comprehensive documentation and setup guides

Notifications are sent when:
- Items are added/removed/completed in shared lists
- Users are invited to lists
- Invitations are accepted
- Collaborators are removed from lists

Works on iOS 16.4+ (when installed to home screen), Android, and desktop browsers.
2025-12-07 01:22:16 +00:00

114 lines
3.4 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
email String @unique
name String?
passwordHash String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
ownedLists List[] @relation("ListOwner")
collaborations Collaborator[]
sentInvitations Invitation[] @relation("InvitationInviter")
receivedInvitations Invitation[] @relation("InvitationReceiver")
pushSubscriptions PushSubscription[]
@@index([email])
}
model PushSubscription {
id String @id @default(cuid())
userId String
endpoint String @db.Text
p256dh String @db.Text
auth String @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([userId, endpoint(255)])
@@index([userId])
}
model List {
id String @id @default(cuid())
title String
color String @default("#3B82F6")
ownerId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
owner User @relation("ListOwner", fields: [ownerId], references: [id], onDelete: Cascade)
items Item[]
collaborators Collaborator[]
invitations Invitation[]
@@index([ownerId])
@@index([ownerId, createdAt])
}
model Collaborator {
id String @id @default(cuid())
userId String
listId String
permission String // 'editor' or 'viewer'
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
list List @relation(fields: [listId], references: [id], onDelete: Cascade)
@@unique([userId, listId])
@@index([userId])
@@index([listId])
@@index([listId, permission])
}
model Invitation {
id String @id @default(cuid())
email String
listId String
inviterId String
permission String // 'editor' or 'viewer'
status String @default("pending") // 'pending', 'accepted', 'declined'
createdAt DateTime @default(now())
expiresAt DateTime
list List @relation(fields: [listId], references: [id], onDelete: Cascade)
inviter User @relation("InvitationInviter", fields: [inviterId], references: [id], onDelete: Cascade)
receiver User? @relation("InvitationReceiver", fields: [email], references: [email], onDelete: Cascade)
@@index([email])
@@index([listId])
@@index([inviterId])
@@index([status])
@@index([email, status])
@@index([listId, status])
}
model Item {
id String @id @default(cuid())
title String
description String?
completed Boolean @default(false)
priority String @default("medium") // low, medium, high
dueDate DateTime?
tags Json @default("[]")
notes String? @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
listId String
list List @relation(fields: [listId], references: [id], onDelete: Cascade)
@@index([listId])
@@index([completed])
@@index([priority])
@@index([dueDate])
@@index([createdAt])
@@index([listId, completed])
@@index([listId, priority])
}