From e32738ca5942a70f822c052aa959925d9fab334c Mon Sep 17 00:00:00 2001
From: Charvisree Koripella
Date: Thu, 16 Apr 2026 00:58:57 -0500
Subject: [PATCH 01/30] Deleted the old attendence toggles
---
app/components/Notes.vue | 26 ++++----------------------
1 file changed, 4 insertions(+), 22 deletions(-)
diff --git a/app/components/Notes.vue b/app/components/Notes.vue
index 692886c..13de5af 100644
--- a/app/components/Notes.vue
+++ b/app/components/Notes.vue
@@ -547,7 +547,6 @@
method: 'POST',
body: {
content: savedContent,
- attended: !isAbsent.value,
},
})) as { id: string; createdAt: string }
@@ -584,7 +583,6 @@
//Auto-save and status tracking
const saveStatus = ref<'idle' | 'saving' | 'saved' | 'error'>('idle')
- const isAbsent = ref(false)
const lastSaved = ref(null)
//Auto-save and status tracking for previous notes
@@ -992,28 +990,12 @@
-
-
-
-
-
+
@@ -1107,9 +1089,9 @@
@click.self="showSaveModal = false"
>
-
Save Note
+
Submit Note
- Are you sure you want to save this note?
+ Are you sure you want to submit this note?
Date: Thu, 16 Apr 2026 14:23:05 -0500
Subject: [PATCH 02/30] Added the attendance dropdown and edited the prisma
---
app/components/AttendenceDropdown.vue | 33 +++++++++++++++++++++++++++
prisma/schema/notes.prisma | 14 ++++++------
2 files changed, 40 insertions(+), 7 deletions(-)
create mode 100644 app/components/AttendenceDropdown.vue
diff --git a/app/components/AttendenceDropdown.vue b/app/components/AttendenceDropdown.vue
new file mode 100644
index 0000000..ecbf61a
--- /dev/null
+++ b/app/components/AttendenceDropdown.vue
@@ -0,0 +1,33 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/prisma/schema/notes.prisma b/prisma/schema/notes.prisma
index 286fd70..1f40b06 100644
--- a/prisma/schema/notes.prisma
+++ b/prisma/schema/notes.prisma
@@ -10,13 +10,13 @@ enum SessionNotesRequestStatus {
}
model SessionNote {
- id String @id @default(cuid())
- clientId String
- content String
- attended Boolean @default(true)
- createdAt DateTime @default(now())
- client Client @relation(fields: [clientId], references: [id], onDelete: Cascade)
- edits SessionNoteEdit[]
+ id String @id @default(cuid())
+ clientId String
+ content String
+ attendanceStatus String? @default("show")
+ createdAt DateTime @default(now())
+ client Client @relation(fields: [clientId], references: [id], onDelete: Cascade)
+ edits SessionNoteEdit[]
@@index([clientId])
@@map("session_note")
From c7be13c5da7c9f7f4bdfd4d6c095543ce0a6cbdf Mon Sep 17 00:00:00 2001
From: Charvisree Koripella
Date: Thu, 23 Apr 2026 02:36:46 -0500
Subject: [PATCH 03/30] Fixed the submit button and added attendance status to
notes
---
app/components/AttendanceDropdown.vue | 33 ++++++++++++++++++
app/components/AttendenceDropdown.vue | 33 ------------------
app/components/Notes.vue | 49 +++++++++++++++++++--------
app/pages/notes-test.vue | 2 +-
server/api/clients/[id]/notes.post.ts | 6 ++--
5 files changed, 71 insertions(+), 52 deletions(-)
create mode 100644 app/components/AttendanceDropdown.vue
delete mode 100644 app/components/AttendenceDropdown.vue
diff --git a/app/components/AttendanceDropdown.vue b/app/components/AttendanceDropdown.vue
new file mode 100644
index 0000000..3ea261c
--- /dev/null
+++ b/app/components/AttendanceDropdown.vue
@@ -0,0 +1,33 @@
+
+
+
+
+
diff --git a/app/components/AttendenceDropdown.vue b/app/components/AttendenceDropdown.vue
deleted file mode 100644
index ecbf61a..0000000
--- a/app/components/AttendenceDropdown.vue
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/components/Notes.vue b/app/components/Notes.vue
index 13de5af..fe4508d 100644
--- a/app/components/Notes.vue
+++ b/app/components/Notes.vue
@@ -1,5 +1,6 @@
-
+
+
+ Attendance Status
+
+ {{ opt.label }}
+
+
+
+
diff --git a/app/components/Notes.vue b/app/components/Notes.vue
index fcda0d6..e0fcaaf 100644
--- a/app/components/Notes.vue
+++ b/app/components/Notes.vue
@@ -6,7 +6,7 @@
import DOMPurify from 'dompurify'
import { useWindowSize } from '@vueuse/core'
- type SessionNoteRow = { id: string; content: string; createdAt: string }
+ type SessionNoteRow = { id: string; content: string; createdAt: string; attendanceStatus?: string }
type SelectedNote =
| { source: 'editor'; id: number; date: string; content: string; preview: string }
@@ -367,6 +367,10 @@
}
editingSessionNoteId.value = sd.id
editingNoteId.value = null
+
+ // Load current attendance status into the edit form
+ const sn = localSessionNotes.value.find(n => n.id === sd.id)
+ editingAttendanceStatus.value = sn?.attendanceStatus ?? 'show'
} else {
pendingMeta.value.set(sd.id, {
reason: editReason.value,
@@ -440,6 +444,7 @@
content: draft,
reason: meta.reason,
signature: meta.signature,
+ attendanceStatus: editingAttendanceStatus.value,
},
})
@@ -449,6 +454,7 @@
localSessionNotes.value[idx] = {
...row,
content: draft,
+ attendanceStatus: editingAttendanceStatus.value,
}
}
@@ -534,7 +540,15 @@
showSaveModal.value = true
}
- const attendanceStatus = ref('show')
+ const attendanceStatus = ref('')
+
+ const selectedNoteAttendance = computed(() => {
+ if (!selectedNoteData.value || selectedNoteData.value.source !== 'session') return null
+ const sn = localSessionNotes.value.find(n => n.id === selectedNoteData.value?.id)
+ return sn?.attendanceStatus ?? null
+ })
+
+ const editingAttendanceStatus = ref('show')
async function confirmSaveNote() {
console.log('confirmSaveNote called - Debug log added')
@@ -899,6 +913,16 @@
>
Session log note
+
+
+ {{ selectedNoteAttendance.replace(/-/g, ' ') }}
+
Editing previous note — save to confirm changes.
+
+
+
+
{{ currentNote.date }}
Current
-
-
-
+
+
+
{
content?: string
reason?: string
signature?: string
+ attendanceStatus?: string
}>(event)
if (!body?.content || typeof body.content !== 'string' || !body.content.trim()) {
@@ -41,13 +42,18 @@ export default defineEventHandler(async (event) => {
data: {
sessionNoteId: note.id,
originalContent: note.content,
+ editedContent: body.content.trim(),
+ oldAttendanceStatus: note.attendanceStatus,
+ newAttendanceStatus: body.attendanceStatus ?? note.attendanceStatus,
reason: body.reason.trim(),
signature: body.signature.trim(),
},
}),
prisma.sessionNote.update({
where: { id: note.id },
- data: { content: body.content.trim() },
+ data: { content: body.content.trim(),
+ ...(body.attendanceStatus && { attendanceStatus: body.attendanceStatus }),
+ },
}),
])
From 442345807efe09f1b5d28d4da1912c0fcb040ac4 Mon Sep 17 00:00:00 2001
From: Charvisree Koripella
Date: Thu, 23 Apr 2026 10:09:35 -0500
Subject: [PATCH 06/30] Fixed the attendance on notes edit and viewer
---
app/components/Notes.vue | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/app/components/Notes.vue b/app/components/Notes.vue
index e0fcaaf..dcdf7ad 100644
--- a/app/components/Notes.vue
+++ b/app/components/Notes.vue
@@ -370,7 +370,7 @@
// Load current attendance status into the edit form
const sn = localSessionNotes.value.find(n => n.id === sd.id)
- editingAttendanceStatus.value = sn?.attendanceStatus ?? 'show'
+ editingAttendanceStatus.value = sn?.attendanceStatus ?? ''
} else {
pendingMeta.value.set(sd.id, {
reason: editReason.value,
@@ -586,6 +586,7 @@
id: response.id,
createdAt: response.createdAt,
content: savedContent,
+ attendanceStatus: attendanceStatus.value,
})
// Clear editor → fresh current note
From 2e0867aae4be45e7c3168736ddb3964b35cca1bc Mon Sep 17 00:00:00 2001
From: Charvisree Koripella
Date: Sun, 26 Apr 2026 17:06:48 -0500
Subject: [PATCH 07/30] Changed to the justification modal and added a checkbox
list
---
app/components/Notes.vue | 98 +++++++++++----------------------
app/components/NotesToolbar.vue | 27 +--------
app/pages/notes-test.vue | 8 +++
nuxt.config.ts | 8 +++
4 files changed, 50 insertions(+), 91 deletions(-)
diff --git a/app/components/Notes.vue b/app/components/Notes.vue
index dcdf7ad..66cd36a 100644
--- a/app/components/Notes.vue
+++ b/app/components/Notes.vue
@@ -1,6 +1,8 @@
@@ -69,24 +58,14 @@ const items: EditorToolbarItem[][] = [
v-model="localContent"
:content-type="contentType || 'markdown'"
placeholder="Start typing your clinical notes here..."
- class="flex-1 prose prose-sm sm:prose text-left dark:prose-invert"
- :class="sizeClassMap[selectedSize]"
+ class="flex flex-col flex-1 min-h-0 prose prose-sm sm:prose text-left dark:prose-invert"
>
-
-
-
-
diff --git a/app/pages/notes-test.vue b/app/pages/notes-test.vue
index 98eade7..fc3bb7f 100644
--- a/app/pages/notes-test.vue
+++ b/app/pages/notes-test.vue
@@ -31,6 +31,14 @@
return clientPickerOptions.value[0]?.id ?? ''
})
+ type NotesEditorData = {
+ client: { id: string; name: string }
+ currentNote: { id: number; date: string; content: string }
+ previousNotes: { id: number; date: string; preview: string; content: string }[]
+ sessionNotes: { id: string; content: string; createdAt: string }[]
+ forms: { label?: string; status: 'complete' | 'pending' }[]
+ }
+
const { data, pending, error } = await useFetch(
() => `/api/clients/${clientId.value}/notes-editor-data`,
{
diff --git a/nuxt.config.ts b/nuxt.config.ts
index 8f578a6..051867c 100644
--- a/nuxt.config.ts
+++ b/nuxt.config.ts
@@ -41,5 +41,13 @@ export default defineNuxtConfig({
'prosemirror-transform',
],
},
+ optimizeDeps: {
+ include: [
+ '@vue/devtools-core',
+ '@vue/devtools-kit',
+ 'better-auth/vue',
+ 'better-auth/client/plugins',
+ ]
+ },
},
})
From 8f5e10f96c84469ed370fc715c4c101175b5aa5a Mon Sep 17 00:00:00 2001
From: Charvisree Koripella
Date: Sun, 26 Apr 2026 17:27:29 -0500
Subject: [PATCH 08/30] checkbox list on notes toolbar
---
app/assets/css/main.css | 35 +++++++++++++++++++++++++++++++++
app/components/NotesToolbar.vue | 14 ++++++++++++-
2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/app/assets/css/main.css b/app/assets/css/main.css
index 16bfeb1..ca8d126 100644
--- a/app/assets/css/main.css
+++ b/app/assets/css/main.css
@@ -222,4 +222,39 @@
.tiptap p.is-empty:not(:first-child)::before {
content: none;
+}
+
+/* Style tiptap task list checkboxes to match Nuxt UI */
+.tiptap ul[data-type="taskList"] {
+ list-style: none;
+ padding-left: 0;
+}
+
+.tiptap ul[data-type="taskList"] li {
+ display: flex;
+ align-items: flex-start;
+ gap: 0.5rem;
+}
+
+.tiptap ul[data-type="taskList"] li > label {
+ margin-top: 2px;
+ flex-shrink: 0;
+}
+
+.tiptap ul[data-type="taskList"] li > label input[type="checkbox"] {
+ width: 1rem;
+ height: 1rem;
+ border-radius: 4px;
+ border: 1.5px solid #d1d5db;
+ cursor: pointer;
+ accent-color: var(--color-primary-500);
+}
+
+.tiptap ul[data-type="taskList"] li > div {
+ flex: 1;
+}
+
+.tiptap ul[data-type="taskList"] li[data-checked="true"] > div {
+ text-decoration: line-through;
+ color: #9ca3af;
}
\ No newline at end of file
diff --git a/app/components/NotesToolbar.vue b/app/components/NotesToolbar.vue
index 0d6bb2a..9b7f03c 100644
--- a/app/components/NotesToolbar.vue
+++ b/app/components/NotesToolbar.vue
@@ -1,5 +1,6 @@
@@ -66,6 +67,17 @@ const items: EditorToolbarItem[][] = [
layout="fixed"
class="w-full border-b bg-gray-50 dark:bg-gray-800 flex-shrink-0 sticky top-0 z-10"
>
+
+
+
+
+
From 7b9b163a20eacfba458d573c3c65581aa56a2ccb Mon Sep 17 00:00:00 2001
From: Deethya Janjanam
Date: Sun, 26 Apr 2026 17:57:52 -0500
Subject: [PATCH 09/30] added the labels for event creation
---
app/pages/calendar.vue | 30 ++++++++++++++++++++++++++----
1 file changed, 26 insertions(+), 4 deletions(-)
diff --git a/app/pages/calendar.vue b/app/pages/calendar.vue
index 2752169..8ffa216 100644
--- a/app/pages/calendar.vue
+++ b/app/pages/calendar.vue
@@ -692,14 +692,36 @@
Session name will be auto-generated as Firstname_Lastname_## .
-
+
+
+ Description
+
+
+
-
+
+ Date
+
+
-
+
+
+ Start time
+
+
+
-
+
+
+ End time
+
+
+
{{ createTimeRangeError }}
From 842f095dc082dab1fe0c76dff178d2780560e99b Mon Sep 17 00:00:00 2001
From: Deethya Janjanam
Date: Sun, 26 Apr 2026 18:04:31 -0500
Subject: [PATCH 10/30] removed the meeting link things!
---
app/pages/calendar.vue | 108 ++++++++++++-----------------------------
1 file changed, 32 insertions(+), 76 deletions(-)
diff --git a/app/pages/calendar.vue b/app/pages/calendar.vue
index 8ffa216..a122925 100644
--- a/app/pages/calendar.vue
+++ b/app/pages/calendar.vue
@@ -7,12 +7,6 @@
import listPlugin from '@fullcalendar/list'
import { VIDEO_PROVIDER_LABEL } from '~/utils/video-conference'
- const videoMeetingTypeOptions = [
- { value: 'GOOGLE_MEET' as const, label: 'Google Meet' },
- { value: 'ZOOM' as const, label: 'Zoom' },
- { value: 'OTHER' as const, label: 'Other link' },
- ]
-
const isMobile = ref(process.client && window.innerWidth < 768)
const calendarRef = ref()
const session = authClient.useSession()
@@ -380,7 +374,7 @@
)
editForm.videoJoinUrl = selectedEvent.value.videoJoinUrl || ''
editForm.videoProvider = editForm.includeVideo
- ? (selectedEvent.value.videoProvider as typeof editForm.videoProvider) || 'GOOGLE_MEET'
+ ? (selectedEvent.value.videoProvider as typeof editForm.videoProvider) || 'OTHER'
: ''
editTimeRangeError.value = ''
}
@@ -418,7 +412,7 @@
date: editForm.date,
startTime: editForm.startTime,
endTime: editForm.endTime,
- videoProvider: editForm.includeVideo ? editForm.videoProvider || 'GOOGLE_MEET' : null,
+ videoProvider: editForm.includeVideo ? editForm.videoProvider || 'OTHER' : null,
videoJoinUrl: editForm.includeVideo ? editForm.videoJoinUrl.trim() || null : null,
},
})
@@ -493,7 +487,7 @@
form.videoProvider = ''
form.videoJoinUrl = ''
} else if (!form.videoProvider) {
- form.videoProvider = 'GOOGLE_MEET'
+ form.videoProvider = 'OTHER'
}
}
)
@@ -505,7 +499,7 @@
editForm.videoProvider = ''
editForm.videoJoinUrl = ''
} else if (!editForm.videoProvider) {
- editForm.videoProvider = 'GOOGLE_MEET'
+ editForm.videoProvider = 'OTHER'
}
}
)
@@ -570,7 +564,7 @@
date: form.date,
startTime: form.startTime,
endTime: form.endTime,
- videoProvider: form.includeVideo ? form.videoProvider || 'GOOGLE_MEET' : undefined,
+ videoProvider: form.includeVideo ? form.videoProvider || 'OTHER' : undefined,
videoJoinUrl: form.includeVideo ? form.videoJoinUrl.trim() : undefined,
},
})
@@ -735,41 +729,22 @@
-
Meeting type
-
-
-
- {{ opt.label }}
-
-
-
-
- Join link
-
-
-
- Paste a secure https link so clients can join from the dashboard and calendar.
-
-
+
+ Join link
+
+
+
+ Paste a secure https link so clients can join from the dashboard and calendar.
+
@@ -885,38 +860,19 @@
-
Meeting type
-
-
-
- {{ opt.label }}
-
-
-
-
- Join link
-
-
-
+
+ Join link
+
+
From d45eda8eb8ba0e4f71d9f52c8b44ec0c1a3262b2 Mon Sep 17 00:00:00 2001
From: Deethya Janjanam
Date: Sun, 26 Apr 2026 18:11:52 -0500
Subject: [PATCH 11/30] notes can scroll
---
app/components/Notes.vue | 78 ++++++++++++++++++++-------------
app/components/NotesToolbar.vue | 18 ++++++--
2 files changed, 62 insertions(+), 34 deletions(-)
diff --git a/app/components/Notes.vue b/app/components/Notes.vue
index c4e9916..a31fdf0 100644
--- a/app/components/Notes.vue
+++ b/app/components/Notes.vue
@@ -1024,9 +1024,9 @@
-
+
-
+
-
+
-
+
-
-
+
+
{{ selectedNoteData.date }}
-
+
Editing previous note — save to confirm changes.
-
+
-
+
-
+
Edit History
@@ -1468,8 +1477,10 @@
-
-
+
+
{{ currentNote.date }}
@@ -1554,20 +1565,22 @@
-
-
- {{ currentNoteLockMessage }}
+
+
+
+ {{ currentNoteLockMessage }}
+
-
+
● Saving...
@@ -1604,7 +1617,10 @@
class="w-auto"
/>
-
+
{{ attendanceLockMessage }}
@@ -1613,7 +1629,7 @@
diff --git a/app/components/NotesToolbar.vue b/app/components/NotesToolbar.vue
index 0fd770d..26a72d0 100644
--- a/app/components/NotesToolbar.vue
+++ b/app/components/NotesToolbar.vue
@@ -61,7 +61,9 @@ const items: EditorToolbarItem[][] = [
-
+
-
\ No newline at end of file
+
+
+
\ No newline at end of file
From 310d77fd2f1ea63ce6a70329a26120a8f234154b Mon Sep 17 00:00:00 2001
From: TusharW4ni
Date: Sun, 26 Apr 2026 18:21:48 -0500
Subject: [PATCH 12/30] added admin users
---
prisma/seed.ts | 425 ++++++++++++-------------------------------------
1 file changed, 99 insertions(+), 326 deletions(-)
diff --git a/prisma/seed.ts b/prisma/seed.ts
index 174a085..d97bf6d 100644
--- a/prisma/seed.ts
+++ b/prisma/seed.ts
@@ -10,122 +10,6 @@ const connectionString = process.env.DATABASE_URL ?? 'file:./dev.db'
const adapter = new PrismaBetterSqlite3({ url: connectionString })
const prisma = new PrismaClient({ adapter })
-async function ensureLatestGadForm(userId: string) {
- const existing = await prisma.gadForm.findFirst({
- where: { userId },
- orderBy: { id: 'desc' },
- })
-
- if (existing) {
- return prisma.gadForm.update({
- where: { id: existing.id },
- data: {
- status: 'COMPLETE',
- totalScore: 12,
- severity: 'Moderate',
- submittedAt: new Date(),
- },
- })
- }
-
- return prisma.gadForm.create({
- data: {
- userId,
- status: 'COMPLETE',
- totalScore: 12,
- severity: 'Moderate',
- submittedAt: new Date(),
- },
- })
-}
-
-async function ensureLatestPhqForm(userId: string) {
- const existing = await prisma.phqForm.findFirst({
- where: { userId },
- orderBy: { id: 'desc' },
- })
-
- if (existing) {
- return prisma.phqForm.update({
- where: { id: existing.id },
- data: {
- status: 'COMPLETE',
- totalScore: 14,
- severity: 'Moderate depression',
- submittedAt: new Date(),
- },
- })
- }
-
- return prisma.phqForm.create({
- data: {
- userId,
- status: 'COMPLETE',
- totalScore: 14,
- severity: 'Moderate depression',
- submittedAt: new Date(),
- },
- })
-}
-
-async function ensureLatestPclForm(userId: string) {
- const existing = await prisma.pclForm.findFirst({
- where: { userId },
- orderBy: { id: 'desc' },
- })
-
- if (existing) {
- return prisma.pclForm.update({
- where: { id: existing.id },
- data: {
- status: 'COMPLETE',
- totalScore: 45,
- severity: 'Moderate',
- submittedAt: new Date(),
- },
- })
- }
-
- return prisma.pclForm.create({
- data: {
- userId,
- status: 'COMPLETE',
- totalScore: 45,
- severity: 'Moderate',
- submittedAt: new Date(),
- },
- })
-}
-
-async function ensureLatestAceForm(userId: string) {
- const existing = await prisma.aceForm.findFirst({
- where: { userId },
- orderBy: { id: 'desc' },
- })
-
- if (existing) {
- return prisma.aceForm.update({
- where: { id: existing.id },
- data: {
- status: 'COMPLETE',
- totalScore: 2,
- severity: 'Low',
- submittedAt: new Date(),
- },
- })
- }
-
- return prisma.aceForm.create({
- data: {
- userId,
- status: 'COMPLETE',
- totalScore: 2,
- severity: 'Low',
- submittedAt: new Date(),
- },
- })
-}
-
async function seedForms(userId: string) {
// 1. AppForm (Application)
const appForm = await prisma.appForm.upsert({
@@ -151,22 +35,18 @@ async function seedForms(userId: string) {
})
// 2. GAD-7
- const gadForm = await ensureLatestGadForm(userId)
-
- await prisma.gadQuestion.upsert({
- where: { formId: gadForm.id },
- update: {
+ const gadForm = await prisma.gadForm.create({
+ data: {
userId,
- g01: 2,
- g02: 1,
- g03: 2,
- g04: 1,
- g05: 2,
- g06: 2,
- g07: 2,
- g08: 1,
+ status: 'COMPLETE',
+ totalScore: 12,
+ severity: 'Moderate',
+ submittedAt: new Date(),
},
- create: {
+ })
+
+ await prisma.gadQuestion.create({
+ data: {
formId: gadForm.id,
userId,
g01: 2,
@@ -181,23 +61,21 @@ async function seedForms(userId: string) {
})
// 3. PHQ-9
- const phqForm = await ensureLatestPhqForm(userId)
+ const phqForm = await prisma.phqForm.upsert({
+ where: { userId },
+ update: {},
+ create: {
+ userId,
+ status: 'COMPLETE',
+ totalScore: 14,
+ severity: 'Moderate depression',
+ submittedAt: new Date(),
+ },
+ })
await prisma.phqQuestion.upsert({
where: { formId: phqForm.id },
- update: {
- userId,
- q1: 2,
- q2: 1,
- q3: 2,
- q4: 1,
- q5: 2,
- q6: 2,
- q7: 2,
- q8: 1,
- q9: 1,
- q10: 1,
- },
+ update: {},
create: {
formId: phqForm.id,
userId,
@@ -215,34 +93,18 @@ async function seedForms(userId: string) {
})
// 4. PCL-5
- const pclForm = await ensureLatestPclForm(userId)
-
- await prisma.pclQuestion.upsert({
- where: { formId: pclForm.id },
- update: {
+ const pclForm = await prisma.pclForm.create({
+ data: {
userId,
- q01: 3,
- q02: 2,
- q03: 3,
- q04: 2,
- q05: 2,
- q06: 3,
- q07: 2,
- q08: 2,
- q09: 2,
- q10: 2,
- q11: 2,
- q12: 2,
- q13: 2,
- q14: 2,
- q15: 2,
- q16: 2,
- q17: 2,
- q18: 2,
- q19: 2,
- q20: 2,
+ status: 'COMPLETE',
+ totalScore: 45,
+ severity: 'Moderate',
+ submittedAt: new Date(),
},
- create: {
+ })
+
+ await prisma.pclQuestion.create({
+ data: {
formId: pclForm.id,
userId,
q01: 3,
@@ -269,23 +131,21 @@ async function seedForms(userId: string) {
})
// 5. ACE (Hardcoded Form)
- const aceForm = await ensureLatestAceForm(userId)
+ const aceForm = await prisma.aceForm.upsert({
+ where: { userId },
+ update: {},
+ create: {
+ userId,
+ status: 'COMPLETE',
+ totalScore: 2,
+ severity: 'Low',
+ submittedAt: new Date(),
+ },
+ })
await prisma.aceQuestion.upsert({
where: { formId: aceForm.id },
- update: {
- userId,
- a01: 'Yes',
- a02: 'Yes',
- a03: 'No',
- a04: 'No',
- a05: 'No',
- a06: 'No',
- a07: 'No',
- a08: 'No',
- a09: 'No',
- a10: 'No',
- },
+ update: {},
create: {
formId: aceForm.id,
userId,
@@ -303,139 +163,41 @@ async function seedForms(userId: string) {
})
}
-async function ensureBobBuilderSessionNotes(bobUserId: string, clinicianUserId: string) {
- const bobClient = await prisma.client.upsert({
+async function ensureBobBuilderSessionNotes(bobUserId: string) {
+ const client = await prisma.client.upsert({
where: { userId: bobUserId },
- update: { status: 'ACTIVE', clinicianUserId },
- create: { userId: bobUserId, status: 'ACTIVE', clinicianUserId },
+ update: { status: 'ACTIVE' },
+ create: { userId: bobUserId, status: 'ACTIVE' },
+ })
+
+ const existingSessionNotes = await prisma.sessionNote.count({
+ where: { clientId: client.id },
})
+
+ if (existingSessionNotes === 0) {
+ await prisma.sessionNote.createMany({
+ data: [
+ {
+ clientId: client.id,
+ content:
+ 'Intake / Week 1 — Rapport established. Bob reviewed clinic policies and confidentiality. Reported primary stressors related to work deadlines and sleep disruption. PHQ-9 and GAD-7 administered; safety screen negative. Plan: sleep hygiene handout, begin weekly CBT skills.',
+ },
+ {
+ clientId: client.id,
+ content:
+ 'Session 2 — Focus on thought challenging around catastrophic predictions at work. Homework: thought record for 3 situations. Bob engaged well; identified one automatic thought pattern to monitor between sessions.',
+ },
+ ],
+ })
+ console.log('Created sample SessionNote rows for Bob Builder.')
+ }
+
// Populate form dummy data if it doesn't exist
const existingApp = await prisma.appForm.count({ where: { userId: bobUserId } })
if (existingApp === 0) {
await seedForms(bobUserId)
console.log('Seeded clinical forms for Bob Builder.')
}
- return bobClient
-}
-
-/**
- * Seed a representative note in each workflow state so the multi-tier approval
- * UI (draft / clinician-signed / fully-approved) has real data to exercise,
- * and across both kinds (progress vs psychotherapy).
- */
-async function seedApprovalWorkflowNotes(
- clientId: string,
- clinicianUserId: string,
- adminUserId: string
-) {
- const existing = await prisma.sessionNote.count({ where: { clientId } })
- if (existing > 0) {
- console.log('Session notes already exist; skipping approval-workflow seed.')
- return
- }
-
- const PLACEHOLDER_SIG =
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='
-
- const now = new Date()
-
- // 1. DRAFT progress note – still being written.
- await prisma.sessionNote.create({
- data: {
- clientId,
- sessionName: 'Intake – initial session',
- sessionNumber: 1,
- kind: 'PROGRESS',
- status: 'DRAFT',
- content:
- 'Client arrived on time. Presenting concerns include sleep disruption and work stress. Draft — still gathering history.',
- attended: true,
- },
- })
-
- // 2. CLINICIAN_SIGNED progress note – waiting for admin sign-off.
- const pendingNote = await prisma.sessionNote.create({
- data: {
- clientId,
- sessionName: 'Session 2 – CBT intro',
- sessionNumber: 2,
- kind: 'PROGRESS',
- status: 'CLINICIAN_SIGNED',
- content:
- 'Reviewed sleep-hygiene worksheet. Client reports mild improvement. Introduced cognitive-restructuring framework.',
- attended: true,
- clinicianSignedAt: now,
- clinicianSignedById: clinicianUserId,
- clinicianSignatureData: PLACEHOLDER_SIG,
- },
- })
- await prisma.notification.create({
- data: {
- userId: adminUserId,
- type: 'NOTE_READY_FOR_APPROVAL',
- title: 'Note awaiting approval',
- message: 'Carl Karl signed a progress note for Bob Builder. Please review and countersign.',
- sessionNoteId: pendingNote.id,
- },
- })
-
- // 3. FULLY_APPROVED progress note.
- await prisma.sessionNote.create({
- data: {
- clientId,
- sessionName: 'Session 3 – thought records',
- sessionNumber: 3,
- kind: 'PROGRESS',
- status: 'FULLY_APPROVED',
- content:
- 'Completed two thought-record examples in session. Client identified core belief patterns and committed to daily practice.',
- attended: true,
- clinicianSignedAt: now,
- clinicianSignedById: clinicianUserId,
- clinicianSignatureData: PLACEHOLDER_SIG,
- adminSignedAt: now,
- adminSignedById: adminUserId,
- adminSignatureData: PLACEHOLDER_SIG,
- adminApprovalNote: 'Reviewed — documentation meets clinic standard.',
- },
- })
-
- // 4. PSYCHOTHERAPY draft – separately stored per HIPAA.
- await prisma.sessionNote.create({
- data: {
- clientId,
- sessionName: 'Session 3 – clinician process notes',
- sessionNumber: 3,
- kind: 'PSYCHOTHERAPY',
- status: 'DRAFT',
- content:
- 'Clinician-only process notes: countertransference observations, working hypotheses, and next-session targets.',
- attended: true,
- },
- })
-
- // 5. PSYCHOTHERAPY fully approved – demonstrates tier-2 sign-off on process notes.
- await prisma.sessionNote.create({
- data: {
- clientId,
- sessionName: 'Session 2 – clinician process notes',
- sessionNumber: 2,
- kind: 'PSYCHOTHERAPY',
- status: 'FULLY_APPROVED',
- content:
- 'Process notes: explored defense patterns around perfectionism. Plan to revisit in session 4.',
- attended: true,
- clinicianSignedAt: now,
- clinicianSignedById: clinicianUserId,
- clinicianSignatureData: PLACEHOLDER_SIG,
- adminSignedAt: now,
- adminSignedById: adminUserId,
- adminSignatureData: PLACEHOLDER_SIG,
- adminApprovalNote: 'Approved — psychotherapy note retained separately.',
- },
- })
-
- console.log('Seeded 5 session notes across DRAFT / CLINICIAN_SIGNED / FULLY_APPROVED.')
}
async function main() {
@@ -444,8 +206,8 @@ async function main() {
await ensureDefaultDeclarationTemplates(prisma)
await backfillSessionNotesRequestTemplates(prisma)
- // Create / Upsert Alice (Admin — default approver for the note workflow)
- const alice = await prisma.user.upsert({
+ // Create / Upsert Alice (Admin)
+ await prisma.user.upsert({
where: { email: 'alice@a.com' },
update: { role: 'ADMIN', name: 'Alice Wonderland' },
create: {
@@ -458,19 +220,30 @@ async function main() {
})
console.log('Seeded Admin: alice@a.com')
- // Create / Upsert Carl (Clinician)
- const carl = await prisma.user.upsert({
- where: { email: 'carl@c.com' },
- update: { role: 'CLINICIAN', name: 'Carl Karl' },
- create: {
- id: 'carl_id',
- email: 'carl@c.com',
- name: 'Carl Karl',
- emailVerified: true,
- role: 'CLINICIAN',
- },
- })
- console.log('Seeded Clinician: carl@c.com')
+ const newAdmins = [
+ { email: 'cxk230036@utdallas.edu', name: 'Charvisree Koripella ', id: 'charvisree_id' },
+ { email: 'dxj230013@utdallas.edu', name: 'Deethya Janjanam', id: 'deethya_id' },
+ { email: 'dxv230030@utdallas.edu', name: 'Devika Viju', id: 'devika_id' },
+ { email: 'rxa230079@utdallas.edu', name: 'Ritikha Ashok', id: 'ritikha_id' },
+ { email: 'sxr230101@utdallas.edu', name: 'Swaminathan Ramanathan', id: 'swaminathan_id' },
+ { email: 'tmw220003@utdallas.edu', name: 'Tushar Wani', id: 'tushar_id' },
+ { email: 'info@hopecopeheal.org', name: 'Adriana Lewin', id: 'adriana_id' },
+ ]
+
+ for (const admin of newAdmins) {
+ await prisma.user.upsert({
+ where: { email: admin.email },
+ update: { role: 'ADMIN', name: admin.name },
+ create: {
+ id: admin.id,
+ email: admin.email,
+ name: admin.name,
+ emailVerified: true,
+ role: 'ADMIN',
+ },
+ })
+ console.log(`Seeded Admin: ${admin.email}`)
+ }
// Create / Upsert Bob (Client)
const bob = await prisma.user.upsert({
@@ -486,8 +259,7 @@ async function main() {
})
console.log('Seeded Client: bob@b.com')
- const bobClient = await ensureBobBuilderSessionNotes(bob.id, carl.id)
- await seedApprovalWorkflowNotes(bobClient.id, carl.id, alice.id)
+ await ensureBobBuilderSessionNotes(bob.id)
console.log('Seeding finished.')
}
@@ -501,3 +273,4 @@ main()
await prisma.$disconnect()
process.exit(1)
})
+
From 1c5b6df330312cf91be1d5cad631e2ef9a77d497 Mon Sep 17 00:00:00 2001
From: Deethya Janjanam
Date: Sun, 26 Apr 2026 18:57:45 -0500
Subject: [PATCH 13/30] updated seed.ts file
---
prisma/seed.ts | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/prisma/seed.ts b/prisma/seed.ts
index d97bf6d..142f27f 100644
--- a/prisma/seed.ts
+++ b/prisma/seed.ts
@@ -61,10 +61,8 @@ async function seedForms(userId: string) {
})
// 3. PHQ-9
- const phqForm = await prisma.phqForm.upsert({
- where: { userId },
- update: {},
- create: {
+ const phqForm = await prisma.phqForm.create({
+ data: {
userId,
status: 'COMPLETE',
totalScore: 14,
@@ -131,10 +129,8 @@ async function seedForms(userId: string) {
})
// 5. ACE (Hardcoded Form)
- const aceForm = await prisma.aceForm.upsert({
- where: { userId },
- update: {},
- create: {
+ const aceForm = await prisma.aceForm.create({
+ data: {
userId,
status: 'COMPLETE',
totalScore: 2,
@@ -179,11 +175,15 @@ async function ensureBobBuilderSessionNotes(bobUserId: string) {
data: [
{
clientId: client.id,
+ sessionName: 'Intake / Week 1',
+ sessionNumber: 1,
content:
'Intake / Week 1 — Rapport established. Bob reviewed clinic policies and confidentiality. Reported primary stressors related to work deadlines and sleep disruption. PHQ-9 and GAD-7 administered; safety screen negative. Plan: sleep hygiene handout, begin weekly CBT skills.',
},
{
clientId: client.id,
+ sessionName: 'Session 2',
+ sessionNumber: 2,
content:
'Session 2 — Focus on thought challenging around catastrophic predictions at work. Homework: thought record for 3 situations. Bob engaged well; identified one automatic thought pattern to monitor between sessions.',
},
From e25376ab7c4604f61ff0c62ac6825e444794839c Mon Sep 17 00:00:00 2001
From: Deethya Janjanam
Date: Sun, 26 Apr 2026 19:08:50 -0500
Subject: [PATCH 14/30] error for video link is correctly showing up now!
---
app/pages/calendar.vue | 38 ++++++++++++++++++++++++++++++--------
1 file changed, 30 insertions(+), 8 deletions(-)
diff --git a/app/pages/calendar.vue b/app/pages/calendar.vue
index a122925..6040816 100644
--- a/app/pages/calendar.vue
+++ b/app/pages/calendar.vue
@@ -237,6 +237,16 @@
})
const createTimeRangeError = ref('')
const editTimeRangeError = ref('')
+ const createModalError = ref('')
+ const editModalError = ref('')
+
+ function setCreateModalError(message: string) {
+ createModalError.value = message
+ }
+
+ function setEditModalError(message: string) {
+ editModalError.value = message
+ }
function getTimeRangeError(
date: string,
@@ -377,19 +387,19 @@
? (selectedEvent.value.videoProvider as typeof editForm.videoProvider) || 'OTHER'
: ''
editTimeRangeError.value = ''
+ editModalError.value = ''
}
function cancelEdit() {
isEditMode.value = false
editTimeRangeError.value = ''
+ editModalError.value = ''
}
async function saveEdit() {
+ editModalError.value = ''
if (editForm.includeVideo && !editForm.videoJoinUrl?.trim()) {
- toast.add({
- title: 'Add a video link or uncheck Video',
- color: 'warning',
- })
+ setEditModalError('Add a video link or uncheck Video.')
return
}
editTimeRangeError.value = getTimeRangeError(editForm.date, editForm.startTime, editForm.endTime, {
@@ -529,20 +539,20 @@
form.videoProvider = ''
form.videoJoinUrl = ''
createTimeRangeError.value = ''
+ createModalError.value = ''
isCreateModalOpen.value = true
}
function closeCreateModal() {
isCreateModalOpen.value = false
createTimeRangeError.value = ''
+ createModalError.value = ''
}
async function createSession() {
+ createModalError.value = ''
if (form.includeVideo && !form.videoJoinUrl?.trim()) {
- toast.add({
- title: 'Add a video link or uncheck Video',
- color: 'warning',
- })
+ setCreateModalError('Add a video link or uncheck Video.')
return
}
createTimeRangeError.value = getTimeRangeError(form.date, form.startTime, form.endTime)
@@ -669,6 +679,12 @@
+
+ {{ createModalError }}
+
Client
@@ -823,6 +839,12 @@
+
+ {{ editModalError }}
+
Session name is auto-generated and cannot be edited.
From 7af7b2d1df974fc9b29ebd5d5e07f15afd6cef40 Mon Sep 17 00:00:00 2001
From: Deethya Janjanam
Date: Sun, 26 Apr 2026 19:13:57 -0500
Subject: [PATCH 15/30] the meeting link in the modal only works for real
links, there is a link in resources!
---
app/pages/calendar.vue | 41 ++++++++++++++-------------
server/api/appointments/[id].put.ts | 7 +++++
server/api/appointments/index.post.ts | 7 +++++
3 files changed, 36 insertions(+), 19 deletions(-)
diff --git a/app/pages/calendar.vue b/app/pages/calendar.vue
index 6040816..ca1f4b1 100644
--- a/app/pages/calendar.vue
+++ b/app/pages/calendar.vue
@@ -807,25 +807,24 @@
Status: {{ selectedEvent?.status }}
-
-
diff --git a/server/api/appointments/[id].put.ts b/server/api/appointments/[id].put.ts
index e599627..935e982 100644
--- a/server/api/appointments/[id].put.ts
+++ b/server/api/appointments/[id].put.ts
@@ -32,6 +32,13 @@ export default defineEventHandler(async (event) => {
: undefined
const parsedJoin =
videoJoinUrl !== undefined ? normalizeVideoJoinUrl(videoJoinUrl) : undefined
+ const rawJoinInput = typeof videoJoinUrl === 'string' ? videoJoinUrl.trim() : ''
+ if (videoJoinUrl !== undefined && rawJoinInput && !parsedJoin) {
+ throw createError({
+ statusCode: 400,
+ statusMessage: 'Enter a valid meeting link starting with http:// or https://',
+ })
+ }
const effectiveProvider =
parsedProvider !== undefined ? parsedProvider : existing.videoProvider
diff --git a/server/api/appointments/index.post.ts b/server/api/appointments/index.post.ts
index e5739c0..4a1b91d 100644
--- a/server/api/appointments/index.post.ts
+++ b/server/api/appointments/index.post.ts
@@ -61,6 +61,13 @@ export default defineEventHandler(async (event) => {
const parsedProvider = parseVideoProviderInput(videoProvider) as VideoConferenceProvider | null
const normalizedJoin = normalizeVideoJoinUrl(videoJoinUrl)
+ const rawJoinInput = typeof videoJoinUrl === 'string' ? videoJoinUrl.trim() : ''
+ if (rawJoinInput && !normalizedJoin) {
+ throw createError({
+ statusCode: 400,
+ statusMessage: 'Enter a valid meeting link starting with http:// or https://',
+ })
+ }
if (normalizedJoin && !parsedProvider) {
throw createError({
statusCode: 400,
From 20ae51818cb1b7592ab2a397730479ef637c4d8d Mon Sep 17 00:00:00 2001
From: Deethya Janjanam
Date: Sun, 26 Apr 2026 19:43:18 -0500
Subject: [PATCH 16/30] open notes button on calander modal
---
app/pages/calendar.vue | 12 ++++++++++++
server/api/appointments/index.get.ts | 1 +
2 files changed, 13 insertions(+)
diff --git a/app/pages/calendar.vue b/app/pages/calendar.vue
index ca1f4b1..a9d4cd3 100644
--- a/app/pages/calendar.vue
+++ b/app/pages/calendar.vue
@@ -52,6 +52,7 @@
const data = await $fetch<
{
id: string
+ clientId: string
title: string
sessionName: string
sessionNumber: number
@@ -73,6 +74,7 @@
start: e.start,
end: e.end,
extendedProps: {
+ clientId: e.clientId,
sessionName: e.sessionName,
sessionNumber: e.sessionNumber,
clientName: e.clientName,
@@ -354,6 +356,7 @@
const ext = info.event.extendedProps || info.event._def?.extendedProps || {}
selectedEvent.value = {
...ext,
+ clientId: ext.clientId ?? null,
clientName: clientName, // Make sure clientName is included
id: info.event.id,
title: info.event.title,
@@ -839,6 +842,15 @@
"
/>
+
diff --git a/server/api/appointments/index.get.ts b/server/api/appointments/index.get.ts
index d0627c0..868803a 100644
--- a/server/api/appointments/index.get.ts
+++ b/server/api/appointments/index.get.ts
@@ -73,6 +73,7 @@ export default defineEventHandler(async (event) => {
return appointments.map((a) => ({
id: a.id,
+ clientId: a.clientId,
title: a.title,
sessionName: a.sessionName,
sessionNumber: a.sessionNumber,
From 7fa0b936eee1f9029cabb6e836aae06b81558270 Mon Sep 17 00:00:00 2001
From: Deethya Janjanam
Date: Sun, 26 Apr 2026 19:58:38 -0500
Subject: [PATCH 17/30] cant open the same note twice
---
app/components/Notes.vue | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/app/components/Notes.vue b/app/components/Notes.vue
index a31fdf0..fab1766 100644
--- a/app/components/Notes.vue
+++ b/app/components/Notes.vue
@@ -247,6 +247,10 @@
}
async function selectSessionNote(sn: SessionNoteRow) {
+ if (sn.appointmentId && sn.appointmentId === selectedAppointmentId.value) {
+ alert('This session is already open in the current note editor.')
+ return
+ }
selectedPreviousNote.value = null
editingNoteId.value = null
selectedSessionNoteId.value = sn.id
From 929595894bfa5439e6a7011c65a0dcc1246f73ed Mon Sep 17 00:00:00 2001
From: Deethya Janjanam
Date: Sun, 26 Apr 2026 19:59:56 -0500
Subject: [PATCH 18/30] removed the extra session things on the notes page
---
app/components/Notes.vue | 17 -----------------
1 file changed, 17 deletions(-)
diff --git a/app/components/Notes.vue b/app/components/Notes.vue
index fab1766..61f9060 100644
--- a/app/components/Notes.vue
+++ b/app/components/Notes.vue
@@ -1487,23 +1487,6 @@
{{ currentNote.date }}
-
-
- Session
-
-
- Select a session
-
- {{ opt.label }}
-
-
-
- No sessions available yet for this client.
-
-
Note type
From 1072bb19c7b0481ee8980d0a0358d0504cca9226 Mon Sep 17 00:00:00 2001
From: Deethya Janjanam
Date: Sun, 26 Apr 2026 20:02:39 -0500
Subject: [PATCH 19/30] fixed the inital sign in thing
---
app/components/Notes.vue | 27 +++++++++++++++------------
1 file changed, 15 insertions(+), 12 deletions(-)
diff --git a/app/components/Notes.vue b/app/components/Notes.vue
index 61f9060..b0dc254 100644
--- a/app/components/Notes.vue
+++ b/app/components/Notes.vue
@@ -376,9 +376,13 @@
props.appointments.find((a) => a.id === selectedAppointmentId.value) ?? null
)
- /** True when saving would update an existing DB row for the selected session (not first save). */
- const isUpdatingSelectedSessionNote = computed(() =>
- localSessionNotes.value.some((n) => n.appointmentId === selectedAppointmentId.value)
+ /** Existing note row for the selected session (if one has already been created). */
+ const existingSelectedSessionNote = computed(() =>
+ localSessionNotes.value.find((n) => n.appointmentId === selectedAppointmentId.value) ?? null
+ )
+ /** Reason is only required when re-signing a clinician-signed note. */
+ const requiresEditReasonForSignSubmit = computed(
+ () => existingSelectedSessionNote.value?.status === 'CLINICIAN_SIGNED'
)
const canEditCurrentNote = computed(
@@ -842,10 +846,7 @@
return
}
- const updating = localSessionNotes.value.some(
- (n) => n.appointmentId === selectedAppointmentId.value
- )
- if (updating && !editReason?.trim()) {
+ if (requiresEditReasonForSignSubmit.value && !editReason?.trim()) {
alert('A reason is required to update an existing note for this session.')
saveStatus.value = 'idle'
return
@@ -870,7 +871,9 @@
kind: currentNoteKind.value,
action: 'clinician-sign',
clinicianSignatureData: signatureData,
- ...(updating && editReason?.trim() ? { reason: editReason.trim() } : {}),
+ ...(requiresEditReasonForSignSubmit.value && editReason?.trim()
+ ? { reason: editReason.trim() }
+ : {}),
},
})) as {
id: string
@@ -1769,14 +1772,14 @@
:open="showSaveModal"
title="Clinician sign & submit"
:description="
- isUpdatingSelectedSessionNote
+ requiresEditReasonForSignSubmit
? 'This session already has a note. Enter why you are changing it, then sign. The admin will be notified to counter-sign.'
: 'Your signature submits this note for admin approval. An administrator will be notified to counter-sign.'
"
- :submit-label="isUpdatingSelectedSessionNote ? 'Sign & resubmit for approval' : 'Sign & submit for approval'"
+ :submit-label="requiresEditReasonForSignSubmit ? 'Sign & resubmit for approval' : 'Sign & submit for approval'"
:loading="saveStatus === 'saving'"
- :signature-only="!isUpdatingSelectedSessionNote"
- :requires-edit-reason="isUpdatingSelectedSessionNote"
+ :signature-only="!requiresEditReasonForSignSubmit"
+ :requires-edit-reason="requiresEditReasonForSignSubmit"
@close="showSaveModal = false"
@submit="onSaveSessionNoteSigned"
/>
From 66a979329fdf3bb3776d93fe1dcab116c6ad9f4c Mon Sep 17 00:00:00 2001
From: TusharW4ni
Date: Sun, 26 Apr 2026 20:48:50 -0500
Subject: [PATCH 20/30] fix(stage): compile prisma seed to js to avoid tsx OOM
---
dockerfile | 1 +
entrypoint.sh | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/dockerfile b/dockerfile
index 05a5dc9..7609b4b 100644
--- a/dockerfile
+++ b/dockerfile
@@ -8,6 +8,7 @@ RUN corepack enable
RUN pnpm i --frozen-lockfile
RUN pnpm prisma generate
+RUN npx esbuild prisma/seed.ts --bundle --platform=node --format=esm --packages=external --outfile=prisma/seed.mjs
RUN pnpm run build
# Deployment container
diff --git a/entrypoint.sh b/entrypoint.sh
index e22eb69..e43cb42 100644
--- a/entrypoint.sh
+++ b/entrypoint.sh
@@ -3,7 +3,7 @@
# Apply migrations and initialize migrations if it does not exist
pnpm prisma generate
pnpm prisma migrate deploy
-pnpm prisma db seed
+node prisma/seed.mjs
# Run the CMD command from the dockerfile
exec "$@"
From def62f8545c0b569f7553da607789fe530e90790 Mon Sep 17 00:00:00 2001
From: Charvisree Koripella
Date: Sun, 26 Apr 2026 21:53:12 -0500
Subject: [PATCH 21/30] Fixed all the merge conflicts and errors that came
---
.../20260127013856_init/migration.sql | 66 ----
.../migrations/20260314154429/migration.sql | 374 ------------------
.../migration.sql | 147 -------
.../migration.sql | 28 --
.../migration.sql | 52 ---
.../migration.sql | 194 ---------
prisma/migrations/migration_lock.toml | 3 -
7 files changed, 864 deletions(-)
delete mode 100644 prisma/migrations/20260127013856_init/migration.sql
delete mode 100644 prisma/migrations/20260314154429/migration.sql
delete mode 100644 prisma/migrations/20260402034332_consolidate_notes_and_split_schemas/migration.sql
delete mode 100644 prisma/migrations/20260402035909_remove_dynamic_forms/migration.sql
delete mode 100644 prisma/migrations/20260402041509_hardcode_ace_form/migration.sql
delete mode 100644 prisma/migrations/20260426215909_add_client_clinician_user_id/migration.sql
delete mode 100644 prisma/migrations/migration_lock.toml
diff --git a/prisma/migrations/20260127013856_init/migration.sql b/prisma/migrations/20260127013856_init/migration.sql
deleted file mode 100644
index b547781..0000000
--- a/prisma/migrations/20260127013856_init/migration.sql
+++ /dev/null
@@ -1,66 +0,0 @@
--- CreateTable
-CREATE TABLE "user" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "name" TEXT NOT NULL,
- "email" TEXT NOT NULL,
- "emailVerified" BOOLEAN NOT NULL DEFAULT false,
- "image" TEXT,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "updatedAt" DATETIME NOT NULL
-);
-
--- CreateTable
-CREATE TABLE "session" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "expiresAt" DATETIME NOT NULL,
- "token" TEXT NOT NULL,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "updatedAt" DATETIME NOT NULL,
- "ipAddress" TEXT,
- "userAgent" TEXT,
- "userId" TEXT NOT NULL,
- CONSTRAINT "session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "account" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "accountId" TEXT NOT NULL,
- "providerId" TEXT NOT NULL,
- "userId" TEXT NOT NULL,
- "accessToken" TEXT,
- "refreshToken" TEXT,
- "idToken" TEXT,
- "accessTokenExpiresAt" DATETIME,
- "refreshTokenExpiresAt" DATETIME,
- "scope" TEXT,
- "password" TEXT,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "updatedAt" DATETIME NOT NULL,
- CONSTRAINT "account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "verification" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "identifier" TEXT NOT NULL,
- "value" TEXT NOT NULL,
- "expiresAt" DATETIME NOT NULL,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "updatedAt" DATETIME NOT NULL
-);
-
--- CreateIndex
-CREATE UNIQUE INDEX "user_email_key" ON "user"("email");
-
--- CreateIndex
-CREATE INDEX "session_userId_idx" ON "session"("userId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "session_token_key" ON "session"("token");
-
--- CreateIndex
-CREATE INDEX "account_userId_idx" ON "account"("userId");
-
--- CreateIndex
-CREATE INDEX "verification_identifier_idx" ON "verification"("identifier");
diff --git a/prisma/migrations/20260314154429/migration.sql b/prisma/migrations/20260314154429/migration.sql
deleted file mode 100644
index 57888dd..0000000
--- a/prisma/migrations/20260314154429/migration.sql
+++ /dev/null
@@ -1,374 +0,0 @@
--- CreateTable
-CREATE TABLE "client" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "userId" TEXT NOT NULL,
- "status" TEXT NOT NULL DEFAULT 'INCOMPLETE',
- "therapyWeek" INTEGER,
- "missedSessions" INTEGER NOT NULL DEFAULT 0,
- CONSTRAINT "client_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "client_permission" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "clientId" TEXT NOT NULL,
- "canViewScores" BOOLEAN NOT NULL DEFAULT false,
- "canViewNotes" BOOLEAN NOT NULL DEFAULT false,
- "canViewPlan" BOOLEAN NOT NULL DEFAULT false,
- CONSTRAINT "client_permission_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "client" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "session_note" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "clientId" TEXT NOT NULL,
- "content" TEXT NOT NULL,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT "session_note_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "client" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "client_plan" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "clientId" TEXT NOT NULL,
- "content" TEXT NOT NULL DEFAULT '',
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "updatedAt" DATETIME NOT NULL,
- CONSTRAINT "client_plan_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "client" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "form" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "title" TEXT NOT NULL,
- "description" TEXT,
- "slug" TEXT NOT NULL,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "updatedAt" DATETIME NOT NULL
-);
-
--- CreateTable
-CREATE TABLE "question" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "text" TEXT NOT NULL,
- "type" TEXT NOT NULL,
- "alias" TEXT NOT NULL,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "updatedAt" DATETIME NOT NULL
-);
-
--- CreateTable
-CREATE TABLE "form_question" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "formId" TEXT NOT NULL,
- "questionId" TEXT NOT NULL,
- "order" INTEGER NOT NULL,
- CONSTRAINT "form_question_questionId_fkey" FOREIGN KEY ("questionId") REFERENCES "question" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
- CONSTRAINT "form_question_formId_fkey" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "form_assignment" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "userId" TEXT NOT NULL,
- "formId" TEXT NOT NULL,
- "assignedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "completedAt" DATETIME,
- CONSTRAINT "form_assignment_formId_fkey" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
- CONSTRAINT "form_assignment_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "ace_response" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "userId" TEXT NOT NULL,
- "responses" TEXT NOT NULL,
- "completedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT "ace_response_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "AppForm" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "userId" TEXT NOT NULL,
- "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS',
- "submittedAt" DATETIME,
- CONSTRAINT "AppForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "AppQuestion" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "formId" INTEGER NOT NULL,
- "userId" TEXT NOT NULL,
- "q01" TEXT,
- "q02" TEXT,
- "q03" TEXT,
- "q04" TEXT,
- "q05" TEXT,
- "q06" TEXT,
- "q07" TEXT,
- "q08" TEXT,
- "q09" TEXT,
- "q10" TEXT,
- "q11" TEXT,
- "q12" TEXT,
- "q13" TEXT,
- "q14" TEXT,
- "q15" TEXT,
- "q16" TEXT,
- "q17" TEXT,
- "q18" TEXT,
- "q19" TEXT,
- "q20" TEXT,
- "q21" TEXT,
- "q22" TEXT,
- "q23" TEXT,
- "q24" TEXT,
- "q25" TEXT,
- "q26" TEXT,
- "q27" TEXT,
- "q28" TEXT,
- "q29" TEXT,
- "q30" TEXT,
- "q31" TEXT,
- "q32" TEXT,
- "q33" TEXT,
- "q34" TEXT,
- "q35" TEXT,
- "q36" TEXT,
- "q37" TEXT,
- "q38" TEXT,
- "q39" TEXT,
- "q40" TEXT,
- "q41" TEXT,
- "q42" TEXT,
- "q43" TEXT,
- "q44" TEXT,
- "q45" TEXT,
- "q46" TEXT,
- "q47" TEXT,
- "q48" TEXT,
- "q49" TEXT,
- "q50" TEXT,
- CONSTRAINT "AppQuestion_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
- CONSTRAINT "AppQuestion_formId_fkey" FOREIGN KEY ("formId") REFERENCES "AppForm" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "GadForm" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "userId" TEXT NOT NULL,
- "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS',
- "totalScore" INTEGER,
- "severity" TEXT,
- "submittedAt" DATETIME,
- CONSTRAINT "GadForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "GadQuestion" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "formId" INTEGER NOT NULL,
- "userId" TEXT NOT NULL,
- "g01" INTEGER,
- "g02" INTEGER,
- "g03" INTEGER,
- "g04" INTEGER,
- "g05" INTEGER,
- "g06" INTEGER,
- "g07" INTEGER,
- "g08" INTEGER,
- CONSTRAINT "GadQuestion_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
- CONSTRAINT "GadQuestion_formId_fkey" FOREIGN KEY ("formId") REFERENCES "GadForm" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "PhqForm" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "userId" TEXT NOT NULL,
- "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS',
- "totalScore" INTEGER,
- "submittedAt" DATETIME,
- "severity" TEXT,
- CONSTRAINT "PhqForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "PhqQuestion" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "formId" INTEGER NOT NULL,
- "userId" TEXT NOT NULL,
- "q1" INTEGER,
- "q2" INTEGER,
- "q3" INTEGER,
- "q4" INTEGER,
- "q5" INTEGER,
- "q6" INTEGER,
- "q7" INTEGER,
- "q8" INTEGER,
- "q9" INTEGER,
- "q10" INTEGER,
- CONSTRAINT "PhqQuestion_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
- CONSTRAINT "PhqQuestion_formId_fkey" FOREIGN KEY ("formId") REFERENCES "PhqForm" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "PclForm" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "userId" TEXT NOT NULL,
- "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS',
- "submittedAt" DATETIME,
- "severity" TEXT,
- "totalScore" INTEGER,
- CONSTRAINT "PclForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "PclQuestion" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "formId" INTEGER NOT NULL,
- "userId" TEXT NOT NULL,
- "q01" INTEGER,
- "q02" INTEGER,
- "q03" INTEGER,
- "q04" INTEGER,
- "q05" INTEGER,
- "q06" INTEGER,
- "q07" INTEGER,
- "q08" INTEGER,
- "q09" INTEGER,
- "q10" INTEGER,
- "q11" INTEGER,
- "q12" INTEGER,
- "q13" INTEGER,
- "q14" INTEGER,
- "q15" INTEGER,
- "q16" INTEGER,
- "q17" INTEGER,
- "q18" INTEGER,
- "q19" INTEGER,
- "q20" INTEGER,
- CONSTRAINT "PclQuestion_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
- CONSTRAINT "PclQuestion_formId_fkey" FOREIGN KEY ("formId") REFERENCES "PclForm" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "change_audit" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "entityType" TEXT NOT NULL,
- "entityId" TEXT NOT NULL,
- "oldValue" TEXT,
- "newValue" TEXT,
- "reasoning" TEXT,
- "documentationBase64" TEXT,
- "signatureData" TEXT NOT NULL,
- "signedById" TEXT NOT NULL,
- "signedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT "change_audit_signedById_fkey" FOREIGN KEY ("signedById") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- RedefineTables
-PRAGMA defer_foreign_keys=ON;
-PRAGMA foreign_keys=OFF;
-CREATE TABLE "new_user" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "name" TEXT NOT NULL,
- "email" TEXT NOT NULL,
- "emailVerified" BOOLEAN NOT NULL DEFAULT false,
- "image" TEXT,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "updatedAt" DATETIME NOT NULL,
- "role" TEXT NOT NULL DEFAULT 'CLIENT',
- "phoneNumber" INTEGER
-);
-INSERT INTO "new_user" ("createdAt", "email", "emailVerified", "id", "image", "name", "updatedAt") SELECT "createdAt", "email", "emailVerified", "id", "image", "name", "updatedAt" FROM "user";
-DROP TABLE "user";
-ALTER TABLE "new_user" RENAME TO "user";
-CREATE UNIQUE INDEX "user_email_key" ON "user"("email");
-PRAGMA foreign_keys=ON;
-PRAGMA defer_foreign_keys=OFF;
-
--- CreateIndex
-CREATE UNIQUE INDEX "client_userId_key" ON "client"("userId");
-
--- CreateIndex
-CREATE INDEX "client_status_idx" ON "client"("status");
-
--- CreateIndex
-CREATE UNIQUE INDEX "client_permission_clientId_key" ON "client_permission"("clientId");
-
--- CreateIndex
-CREATE INDEX "session_note_clientId_idx" ON "session_note"("clientId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "client_plan_clientId_key" ON "client_plan"("clientId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "form_slug_key" ON "form"("slug");
-
--- CreateIndex
-CREATE UNIQUE INDEX "question_alias_key" ON "question"("alias");
-
--- CreateIndex
-CREATE INDEX "form_question_formId_idx" ON "form_question"("formId");
-
--- CreateIndex
-CREATE INDEX "form_question_questionId_idx" ON "form_question"("questionId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "form_question_formId_questionId_key" ON "form_question"("formId", "questionId");
-
--- CreateIndex
-CREATE INDEX "form_assignment_userId_idx" ON "form_assignment"("userId");
-
--- CreateIndex
-CREATE INDEX "form_assignment_formId_idx" ON "form_assignment"("formId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "form_assignment_userId_formId_key" ON "form_assignment"("userId", "formId");
-
--- CreateIndex
-CREATE INDEX "ace_response_userId_idx" ON "ace_response"("userId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "AppForm_userId_key" ON "AppForm"("userId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "AppQuestion_formId_key" ON "AppQuestion"("formId");
-
--- CreateIndex
-CREATE INDEX "AppQuestion_userId_idx" ON "AppQuestion"("userId");
-
--- CreateIndex
-CREATE INDEX "GadForm_userId_idx" ON "GadForm"("userId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "GadQuestion_formId_key" ON "GadQuestion"("formId");
-
--- CreateIndex
-CREATE INDEX "GadQuestion_userId_idx" ON "GadQuestion"("userId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "PhqForm_userId_key" ON "PhqForm"("userId");
-
--- CreateIndex
-CREATE INDEX "PhqForm_userId_idx" ON "PhqForm"("userId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "PhqQuestion_formId_key" ON "PhqQuestion"("formId");
-
--- CreateIndex
-CREATE INDEX "PhqQuestion_userId_idx" ON "PhqQuestion"("userId");
-
--- CreateIndex
-CREATE INDEX "PclForm_userId_idx" ON "PclForm"("userId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "PclQuestion_formId_key" ON "PclQuestion"("formId");
-
--- CreateIndex
-CREATE INDEX "PclQuestion_userId_idx" ON "PclQuestion"("userId");
-
--- CreateIndex
-CREATE INDEX "change_audit_entityType_entityId_idx" ON "change_audit"("entityType", "entityId");
diff --git a/prisma/migrations/20260402034332_consolidate_notes_and_split_schemas/migration.sql b/prisma/migrations/20260402034332_consolidate_notes_and_split_schemas/migration.sql
deleted file mode 100644
index e59221e..0000000
--- a/prisma/migrations/20260402034332_consolidate_notes_and_split_schemas/migration.sql
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- Warnings:
-
- - You are about to drop the column `documentationBase64` on the `change_audit` table. All the data in the column will be lost.
-
-*/
--- AlterTable
-ALTER TABLE "PclQuestion" ADD COLUMN "worstEvent" TEXT;
-
--- CreateTable
-CREATE TABLE "Appointment" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "clientId" TEXT NOT NULL,
- "adminId" TEXT NOT NULL,
- "title" TEXT NOT NULL,
- "description" TEXT,
- "startTime" DATETIME NOT NULL,
- "endTime" DATETIME NOT NULL,
- "status" TEXT NOT NULL DEFAULT 'SCHEDULED',
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "updatedAt" DATETIME NOT NULL,
- CONSTRAINT "Appointment_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "user" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
- CONSTRAINT "Appointment_adminId_fkey" FOREIGN KEY ("adminId") REFERENCES "user" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "PhysicianStatementForm" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "userId" TEXT NOT NULL,
- "status" TEXT NOT NULL DEFAULT 'NOT_SUBMITTED',
- "originalFileName" TEXT,
- "storedFileName" TEXT,
- "mimeType" TEXT,
- "uploadedAt" DATETIME,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "updatedAt" DATETIME NOT NULL,
- CONSTRAINT "PhysicianStatementForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "ReleaseOfInformationAuthorizationForm" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "userId" TEXT NOT NULL,
- "status" TEXT NOT NULL DEFAULT 'NOT_SUBMITTED',
- "originalFileName" TEXT,
- "storedFileName" TEXT,
- "mimeType" TEXT,
- "uploadedAt" DATETIME,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "updatedAt" DATETIME NOT NULL,
- CONSTRAINT "ReleaseOfInformationAuthorizationForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "session_note_edit" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "sessionNoteId" TEXT NOT NULL,
- "originalContent" TEXT,
- "reason" TEXT,
- "signature" TEXT,
- "editedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT "session_note_edit_sessionNoteId_fkey" FOREIGN KEY ("sessionNoteId") REFERENCES "session_note" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "declaration_template" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "requestKind" TEXT NOT NULL,
- "version" INTEGER NOT NULL,
- "content" TEXT NOT NULL,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-
--- CreateTable
-CREATE TABLE "session_notes_request" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "clientId" TEXT NOT NULL,
- "requestKind" TEXT NOT NULL,
- "status" TEXT NOT NULL DEFAULT 'PENDING',
- "signatureData" TEXT NOT NULL,
- "declarationTemplateId" TEXT NOT NULL,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "decidedAt" DATETIME,
- "decidedByUserId" TEXT,
- "rejectionReason" TEXT,
- "approvedSummaryText" TEXT,
- CONSTRAINT "session_notes_request_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "client" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
- CONSTRAINT "session_notes_request_declarationTemplateId_fkey" FOREIGN KEY ("declarationTemplateId") REFERENCES "declaration_template" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
- CONSTRAINT "session_notes_request_decidedByUserId_fkey" FOREIGN KEY ("decidedByUserId") REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE CASCADE
-);
-
--- RedefineTables
-PRAGMA defer_foreign_keys=ON;
-PRAGMA foreign_keys=OFF;
-CREATE TABLE "new_change_audit" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "entityType" TEXT NOT NULL,
- "entityId" TEXT NOT NULL,
- "oldValue" TEXT,
- "newValue" TEXT,
- "reasoning" TEXT,
- "documentationPath" TEXT,
- "documentationName" TEXT,
- "signatureData" TEXT NOT NULL,
- "signedById" TEXT NOT NULL,
- "signedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT "change_audit_signedById_fkey" FOREIGN KEY ("signedById") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-INSERT INTO "new_change_audit" ("entityId", "entityType", "id", "newValue", "oldValue", "reasoning", "signatureData", "signedAt", "signedById") SELECT "entityId", "entityType", "id", "newValue", "oldValue", "reasoning", "signatureData", "signedAt", "signedById" FROM "change_audit";
-DROP TABLE "change_audit";
-ALTER TABLE "new_change_audit" RENAME TO "change_audit";
-CREATE INDEX "change_audit_entityType_entityId_idx" ON "change_audit"("entityType", "entityId");
-PRAGMA foreign_keys=ON;
-PRAGMA defer_foreign_keys=OFF;
-
--- CreateIndex
-CREATE INDEX "Appointment_clientId_idx" ON "Appointment"("clientId");
-
--- CreateIndex
-CREATE INDEX "Appointment_adminId_idx" ON "Appointment"("adminId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "PhysicianStatementForm_userId_key" ON "PhysicianStatementForm"("userId");
-
--- CreateIndex
-CREATE INDEX "PhysicianStatementForm_status_idx" ON "PhysicianStatementForm"("status");
-
--- CreateIndex
-CREATE UNIQUE INDEX "ReleaseOfInformationAuthorizationForm_userId_key" ON "ReleaseOfInformationAuthorizationForm"("userId");
-
--- CreateIndex
-CREATE INDEX "ReleaseOfInformationAuthorizationForm_status_idx" ON "ReleaseOfInformationAuthorizationForm"("status");
-
--- CreateIndex
-CREATE INDEX "session_note_edit_sessionNoteId_idx" ON "session_note_edit"("sessionNoteId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "declaration_template_requestKind_version_key" ON "declaration_template"("requestKind", "version");
-
--- CreateIndex
-CREATE INDEX "session_notes_request_clientId_idx" ON "session_notes_request"("clientId");
-
--- CreateIndex
-CREATE INDEX "session_notes_request_status_idx" ON "session_notes_request"("status");
-
--- CreateIndex
-CREATE INDEX "session_notes_request_declarationTemplateId_idx" ON "session_notes_request"("declarationTemplateId");
diff --git a/prisma/migrations/20260402035909_remove_dynamic_forms/migration.sql b/prisma/migrations/20260402035909_remove_dynamic_forms/migration.sql
deleted file mode 100644
index 21cc75c..0000000
--- a/prisma/migrations/20260402035909_remove_dynamic_forms/migration.sql
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- Warnings:
-
- - You are about to drop the `form` table. If the table is not empty, all the data it contains will be lost.
- - You are about to drop the `form_assignment` table. If the table is not empty, all the data it contains will be lost.
- - You are about to drop the `form_question` table. If the table is not empty, all the data it contains will be lost.
- - You are about to drop the `question` table. If the table is not empty, all the data it contains will be lost.
-
-*/
--- DropTable
-PRAGMA foreign_keys=off;
-DROP TABLE "form";
-PRAGMA foreign_keys=on;
-
--- DropTable
-PRAGMA foreign_keys=off;
-DROP TABLE "form_assignment";
-PRAGMA foreign_keys=on;
-
--- DropTable
-PRAGMA foreign_keys=off;
-DROP TABLE "form_question";
-PRAGMA foreign_keys=on;
-
--- DropTable
-PRAGMA foreign_keys=off;
-DROP TABLE "question";
-PRAGMA foreign_keys=on;
diff --git a/prisma/migrations/20260402041509_hardcode_ace_form/migration.sql b/prisma/migrations/20260402041509_hardcode_ace_form/migration.sql
deleted file mode 100644
index 575593d..0000000
--- a/prisma/migrations/20260402041509_hardcode_ace_form/migration.sql
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- Warnings:
-
- - You are about to drop the `ace_response` table. If the table is not empty, all the data it contains will be lost.
-
-*/
--- DropTable
-PRAGMA foreign_keys=off;
-DROP TABLE "ace_response";
-PRAGMA foreign_keys=on;
-
--- CreateTable
-CREATE TABLE "ace_form" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "userId" TEXT NOT NULL,
- "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS',
- "totalScore" INTEGER,
- "severity" TEXT,
- "submittedAt" DATETIME,
- CONSTRAINT "ace_form_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "ace_question" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "formId" INTEGER NOT NULL,
- "userId" TEXT NOT NULL,
- "a01" TEXT,
- "a02" TEXT,
- "a03" TEXT,
- "a04" TEXT,
- "a05" TEXT,
- "a06" TEXT,
- "a07" TEXT,
- "a08" TEXT,
- "a09" TEXT,
- "a10" TEXT,
- CONSTRAINT "ace_question_formId_fkey" FOREIGN KEY ("formId") REFERENCES "ace_form" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
- CONSTRAINT "ace_question_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateIndex
-CREATE UNIQUE INDEX "ace_form_userId_key" ON "ace_form"("userId");
-
--- CreateIndex
-CREATE INDEX "ace_form_userId_idx" ON "ace_form"("userId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "ace_question_formId_key" ON "ace_question"("formId");
-
--- CreateIndex
-CREATE INDEX "ace_question_userId_idx" ON "ace_question"("userId");
diff --git a/prisma/migrations/20260426215909_add_client_clinician_user_id/migration.sql b/prisma/migrations/20260426215909_add_client_clinician_user_id/migration.sql
deleted file mode 100644
index edb850a..0000000
--- a/prisma/migrations/20260426215909_add_client_clinician_user_id/migration.sql
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- Warnings:
-
- - You are about to drop the `ace_form` table. If the table is not empty, all the data it contains will be lost.
- - You are about to drop the `ace_question` table. If the table is not empty, all the data it contains will be lost.
- - Added the required column `sessionName` to the `Appointment` table without a default value. This is not possible if the table is not empty.
- - Added the required column `sessionNumber` to the `Appointment` table without a default value. This is not possible if the table is not empty.
- - Added the required column `sessionName` to the `session_note` table without a default value. This is not possible if the table is not empty.
- - Added the required column `sessionNumber` to the `session_note` table without a default value. This is not possible if the table is not empty.
-
-*/
--- DropIndex
-DROP INDEX "PhqForm_userId_key";
-
--- DropIndex
-DROP INDEX "ace_form_userId_idx";
-
--- DropIndex
-DROP INDEX "ace_form_userId_key";
-
--- DropIndex
-DROP INDEX "ace_question_userId_idx";
-
--- DropIndex
-DROP INDEX "ace_question_formId_key";
-
--- AlterTable
-ALTER TABLE "session_notes_request" ADD COLUMN "approvalReason" TEXT;
-ALTER TABLE "session_notes_request" ADD COLUMN "endDate" DATETIME;
-ALTER TABLE "session_notes_request" ADD COLUMN "startDate" DATETIME;
-
--- DropTable
-PRAGMA foreign_keys=off;
-DROP TABLE "ace_form";
-PRAGMA foreign_keys=on;
-
--- DropTable
-PRAGMA foreign_keys=off;
-DROP TABLE "ace_question";
-PRAGMA foreign_keys=on;
-
--- CreateTable
-CREATE TABLE "client_form_score_history" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "userId" TEXT NOT NULL,
- "formKey" TEXT NOT NULL,
- "score" INTEGER,
- "severity" TEXT,
- "recordedAt" DATETIME NOT NULL,
- "answersJson" TEXT,
- CONSTRAINT "client_form_score_history_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "AceForm" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "userId" TEXT NOT NULL,
- "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS',
- "totalScore" INTEGER,
- "severity" TEXT,
- "submittedAt" DATETIME,
- CONSTRAINT "AceForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "AceQuestion" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "formId" INTEGER NOT NULL,
- "userId" TEXT NOT NULL,
- "a01" TEXT,
- "a02" TEXT,
- "a03" TEXT,
- "a04" TEXT,
- "a05" TEXT,
- "a06" TEXT,
- "a07" TEXT,
- "a08" TEXT,
- "a09" TEXT,
- "a10" TEXT,
- CONSTRAINT "AceQuestion_formId_fkey" FOREIGN KEY ("formId") REFERENCES "AceForm" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
- CONSTRAINT "AceQuestion_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- CreateTable
-CREATE TABLE "notification" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "userId" TEXT NOT NULL,
- "type" TEXT NOT NULL,
- "title" TEXT NOT NULL,
- "message" TEXT NOT NULL,
- "sessionNoteId" TEXT,
- "readAt" DATETIME,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT "notification_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
- CONSTRAINT "notification_sessionNoteId_fkey" FOREIGN KEY ("sessionNoteId") REFERENCES "session_note" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);
-
--- RedefineTables
-PRAGMA defer_foreign_keys=ON;
-PRAGMA foreign_keys=OFF;
-CREATE TABLE "new_Appointment" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "clientId" TEXT NOT NULL,
- "adminId" TEXT NOT NULL,
- "title" TEXT NOT NULL,
- "sessionName" TEXT NOT NULL,
- "sessionNumber" INTEGER NOT NULL,
- "description" TEXT,
- "startTime" DATETIME NOT NULL,
- "endTime" DATETIME NOT NULL,
- "status" TEXT NOT NULL DEFAULT 'SCHEDULED',
- "videoProvider" TEXT,
- "videoJoinUrl" TEXT,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "updatedAt" DATETIME NOT NULL,
- CONSTRAINT "Appointment_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "user" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
- CONSTRAINT "Appointment_adminId_fkey" FOREIGN KEY ("adminId") REFERENCES "user" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
-);
-INSERT INTO "new_Appointment" ("adminId", "clientId", "createdAt", "description", "endTime", "id", "startTime", "status", "title", "updatedAt") SELECT "adminId", "clientId", "createdAt", "description", "endTime", "id", "startTime", "status", "title", "updatedAt" FROM "Appointment";
-DROP TABLE "Appointment";
-ALTER TABLE "new_Appointment" RENAME TO "Appointment";
-CREATE INDEX "Appointment_clientId_idx" ON "Appointment"("clientId");
-CREATE INDEX "Appointment_adminId_idx" ON "Appointment"("adminId");
-CREATE UNIQUE INDEX "Appointment_clientId_sessionNumber_key" ON "Appointment"("clientId", "sessionNumber");
-CREATE TABLE "new_client" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "userId" TEXT NOT NULL,
- "status" TEXT NOT NULL DEFAULT 'INCOMPLETE',
- "waitlistedAt" DATETIME,
- "archivedAt" DATETIME,
- "therapyWeek" INTEGER,
- "missedSessions" INTEGER NOT NULL DEFAULT 0,
- "clinicianUserId" TEXT,
- CONSTRAINT "client_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
- CONSTRAINT "client_clinicianUserId_fkey" FOREIGN KEY ("clinicianUserId") REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE CASCADE
-);
-INSERT INTO "new_client" ("id", "missedSessions", "status", "therapyWeek", "userId") SELECT "id", "missedSessions", "status", "therapyWeek", "userId" FROM "client";
-DROP TABLE "client";
-ALTER TABLE "new_client" RENAME TO "client";
-CREATE UNIQUE INDEX "client_userId_key" ON "client"("userId");
-CREATE INDEX "client_status_idx" ON "client"("status");
-CREATE INDEX "client_clinicianUserId_idx" ON "client"("clinicianUserId");
-CREATE TABLE "new_session_note" (
- "id" TEXT NOT NULL PRIMARY KEY,
- "clientId" TEXT NOT NULL,
- "sessionName" TEXT NOT NULL,
- "sessionNumber" INTEGER NOT NULL,
- "appointmentId" TEXT,
- "kind" TEXT NOT NULL DEFAULT 'PROGRESS',
- "status" TEXT NOT NULL DEFAULT 'DRAFT',
- "content" TEXT NOT NULL,
- "attended" BOOLEAN NOT NULL DEFAULT true,
- "signatureData" TEXT,
- "clinicianSignedAt" DATETIME,
- "clinicianSignedById" TEXT,
- "clinicianSignatureData" TEXT,
- "adminSignedAt" DATETIME,
- "adminSignedById" TEXT,
- "adminSignatureData" TEXT,
- "adminApprovalNote" TEXT,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "updatedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- CONSTRAINT "session_note_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "client" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
- CONSTRAINT "session_note_appointmentId_fkey" FOREIGN KEY ("appointmentId") REFERENCES "Appointment" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
- CONSTRAINT "session_note_clinicianSignedById_fkey" FOREIGN KEY ("clinicianSignedById") REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
- CONSTRAINT "session_note_adminSignedById_fkey" FOREIGN KEY ("adminSignedById") REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE CASCADE
-);
-INSERT INTO "new_session_note" ("clientId", "content", "createdAt", "id") SELECT "clientId", "content", "createdAt", "id" FROM "session_note";
-DROP TABLE "session_note";
-ALTER TABLE "new_session_note" RENAME TO "session_note";
-CREATE INDEX "session_note_clientId_idx" ON "session_note"("clientId");
-CREATE INDEX "session_note_appointmentId_idx" ON "session_note"("appointmentId");
-CREATE INDEX "session_note_status_idx" ON "session_note"("status");
-CREATE INDEX "session_note_kind_idx" ON "session_note"("kind");
-PRAGMA foreign_keys=ON;
-PRAGMA defer_foreign_keys=OFF;
-
--- CreateIndex
-CREATE INDEX "client_form_score_history_userId_recordedAt_idx" ON "client_form_score_history"("userId", "recordedAt");
-
--- CreateIndex
-CREATE INDEX "AceForm_userId_idx" ON "AceForm"("userId");
-
--- CreateIndex
-CREATE UNIQUE INDEX "AceQuestion_formId_key" ON "AceQuestion"("formId");
-
--- CreateIndex
-CREATE INDEX "AceQuestion_userId_idx" ON "AceQuestion"("userId");
-
--- CreateIndex
-CREATE INDEX "notification_userId_readAt_idx" ON "notification"("userId", "readAt");
-
--- CreateIndex
-CREATE INDEX "notification_userId_createdAt_idx" ON "notification"("userId", "createdAt");
diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml
deleted file mode 100644
index 2a5a444..0000000
--- a/prisma/migrations/migration_lock.toml
+++ /dev/null
@@ -1,3 +0,0 @@
-# Please do not edit this file manually
-# It should be added in your version-control system (e.g., Git)
-provider = "sqlite"
From 9a8c8ea6f0085f2a07dea810462c85a8cb68fd86 Mon Sep 17 00:00:00 2001
From: TusharW4ni
Date: Sun, 26 Apr 2026 22:19:40 -0500
Subject: [PATCH 22/30] fix(db): restore accidentally deleted migrations and
generate migration for attendanceStatus
---
.../20260127013856_init/migration.sql | 66 ++++
.../migrations/20260314154429/migration.sql | 374 ++++++++++++++++++
.../migration.sql | 147 +++++++
.../migration.sql | 28 ++
.../migration.sql | 52 +++
.../migration.sql | 194 +++++++++
.../migration.sql | 48 +++
prisma/migrations/migration_lock.toml | 3 +
8 files changed, 912 insertions(+)
create mode 100644 prisma/migrations/20260127013856_init/migration.sql
create mode 100644 prisma/migrations/20260314154429/migration.sql
create mode 100644 prisma/migrations/20260402034332_consolidate_notes_and_split_schemas/migration.sql
create mode 100644 prisma/migrations/20260402035909_remove_dynamic_forms/migration.sql
create mode 100644 prisma/migrations/20260402041509_hardcode_ace_form/migration.sql
create mode 100644 prisma/migrations/20260426215909_add_client_clinician_user_id/migration.sql
create mode 100644 prisma/migrations/20260427031935_add_attendance_status/migration.sql
create mode 100644 prisma/migrations/migration_lock.toml
diff --git a/prisma/migrations/20260127013856_init/migration.sql b/prisma/migrations/20260127013856_init/migration.sql
new file mode 100644
index 0000000..b547781
--- /dev/null
+++ b/prisma/migrations/20260127013856_init/migration.sql
@@ -0,0 +1,66 @@
+-- CreateTable
+CREATE TABLE "user" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "email" TEXT NOT NULL,
+ "emailVerified" BOOLEAN NOT NULL DEFAULT false,
+ "image" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+
+-- CreateTable
+CREATE TABLE "session" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "expiresAt" DATETIME NOT NULL,
+ "token" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "ipAddress" TEXT,
+ "userAgent" TEXT,
+ "userId" TEXT NOT NULL,
+ CONSTRAINT "session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "account" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "accountId" TEXT NOT NULL,
+ "providerId" TEXT NOT NULL,
+ "userId" TEXT NOT NULL,
+ "accessToken" TEXT,
+ "refreshToken" TEXT,
+ "idToken" TEXT,
+ "accessTokenExpiresAt" DATETIME,
+ "refreshTokenExpiresAt" DATETIME,
+ "scope" TEXT,
+ "password" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "verification" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "identifier" TEXT NOT NULL,
+ "value" TEXT NOT NULL,
+ "expiresAt" DATETIME NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "user_email_key" ON "user"("email");
+
+-- CreateIndex
+CREATE INDEX "session_userId_idx" ON "session"("userId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "session_token_key" ON "session"("token");
+
+-- CreateIndex
+CREATE INDEX "account_userId_idx" ON "account"("userId");
+
+-- CreateIndex
+CREATE INDEX "verification_identifier_idx" ON "verification"("identifier");
diff --git a/prisma/migrations/20260314154429/migration.sql b/prisma/migrations/20260314154429/migration.sql
new file mode 100644
index 0000000..57888dd
--- /dev/null
+++ b/prisma/migrations/20260314154429/migration.sql
@@ -0,0 +1,374 @@
+-- CreateTable
+CREATE TABLE "client" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "userId" TEXT NOT NULL,
+ "status" TEXT NOT NULL DEFAULT 'INCOMPLETE',
+ "therapyWeek" INTEGER,
+ "missedSessions" INTEGER NOT NULL DEFAULT 0,
+ CONSTRAINT "client_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "client_permission" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "clientId" TEXT NOT NULL,
+ "canViewScores" BOOLEAN NOT NULL DEFAULT false,
+ "canViewNotes" BOOLEAN NOT NULL DEFAULT false,
+ "canViewPlan" BOOLEAN NOT NULL DEFAULT false,
+ CONSTRAINT "client_permission_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "client" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "session_note" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "clientId" TEXT NOT NULL,
+ "content" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ CONSTRAINT "session_note_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "client" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "client_plan" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "clientId" TEXT NOT NULL,
+ "content" TEXT NOT NULL DEFAULT '',
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "client_plan_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "client" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "form" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "title" TEXT NOT NULL,
+ "description" TEXT,
+ "slug" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+
+-- CreateTable
+CREATE TABLE "question" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "text" TEXT NOT NULL,
+ "type" TEXT NOT NULL,
+ "alias" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL
+);
+
+-- CreateTable
+CREATE TABLE "form_question" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "formId" TEXT NOT NULL,
+ "questionId" TEXT NOT NULL,
+ "order" INTEGER NOT NULL,
+ CONSTRAINT "form_question_questionId_fkey" FOREIGN KEY ("questionId") REFERENCES "question" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT "form_question_formId_fkey" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "form_assignment" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "userId" TEXT NOT NULL,
+ "formId" TEXT NOT NULL,
+ "assignedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "completedAt" DATETIME,
+ CONSTRAINT "form_assignment_formId_fkey" FOREIGN KEY ("formId") REFERENCES "form" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT "form_assignment_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "ace_response" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "userId" TEXT NOT NULL,
+ "responses" TEXT NOT NULL,
+ "completedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ CONSTRAINT "ace_response_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "AppForm" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "userId" TEXT NOT NULL,
+ "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS',
+ "submittedAt" DATETIME,
+ CONSTRAINT "AppForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "AppQuestion" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "formId" INTEGER NOT NULL,
+ "userId" TEXT NOT NULL,
+ "q01" TEXT,
+ "q02" TEXT,
+ "q03" TEXT,
+ "q04" TEXT,
+ "q05" TEXT,
+ "q06" TEXT,
+ "q07" TEXT,
+ "q08" TEXT,
+ "q09" TEXT,
+ "q10" TEXT,
+ "q11" TEXT,
+ "q12" TEXT,
+ "q13" TEXT,
+ "q14" TEXT,
+ "q15" TEXT,
+ "q16" TEXT,
+ "q17" TEXT,
+ "q18" TEXT,
+ "q19" TEXT,
+ "q20" TEXT,
+ "q21" TEXT,
+ "q22" TEXT,
+ "q23" TEXT,
+ "q24" TEXT,
+ "q25" TEXT,
+ "q26" TEXT,
+ "q27" TEXT,
+ "q28" TEXT,
+ "q29" TEXT,
+ "q30" TEXT,
+ "q31" TEXT,
+ "q32" TEXT,
+ "q33" TEXT,
+ "q34" TEXT,
+ "q35" TEXT,
+ "q36" TEXT,
+ "q37" TEXT,
+ "q38" TEXT,
+ "q39" TEXT,
+ "q40" TEXT,
+ "q41" TEXT,
+ "q42" TEXT,
+ "q43" TEXT,
+ "q44" TEXT,
+ "q45" TEXT,
+ "q46" TEXT,
+ "q47" TEXT,
+ "q48" TEXT,
+ "q49" TEXT,
+ "q50" TEXT,
+ CONSTRAINT "AppQuestion_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT "AppQuestion_formId_fkey" FOREIGN KEY ("formId") REFERENCES "AppForm" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "GadForm" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "userId" TEXT NOT NULL,
+ "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS',
+ "totalScore" INTEGER,
+ "severity" TEXT,
+ "submittedAt" DATETIME,
+ CONSTRAINT "GadForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "GadQuestion" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "formId" INTEGER NOT NULL,
+ "userId" TEXT NOT NULL,
+ "g01" INTEGER,
+ "g02" INTEGER,
+ "g03" INTEGER,
+ "g04" INTEGER,
+ "g05" INTEGER,
+ "g06" INTEGER,
+ "g07" INTEGER,
+ "g08" INTEGER,
+ CONSTRAINT "GadQuestion_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT "GadQuestion_formId_fkey" FOREIGN KEY ("formId") REFERENCES "GadForm" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "PhqForm" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "userId" TEXT NOT NULL,
+ "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS',
+ "totalScore" INTEGER,
+ "submittedAt" DATETIME,
+ "severity" TEXT,
+ CONSTRAINT "PhqForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "PhqQuestion" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "formId" INTEGER NOT NULL,
+ "userId" TEXT NOT NULL,
+ "q1" INTEGER,
+ "q2" INTEGER,
+ "q3" INTEGER,
+ "q4" INTEGER,
+ "q5" INTEGER,
+ "q6" INTEGER,
+ "q7" INTEGER,
+ "q8" INTEGER,
+ "q9" INTEGER,
+ "q10" INTEGER,
+ CONSTRAINT "PhqQuestion_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT "PhqQuestion_formId_fkey" FOREIGN KEY ("formId") REFERENCES "PhqForm" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "PclForm" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "userId" TEXT NOT NULL,
+ "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS',
+ "submittedAt" DATETIME,
+ "severity" TEXT,
+ "totalScore" INTEGER,
+ CONSTRAINT "PclForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "PclQuestion" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "formId" INTEGER NOT NULL,
+ "userId" TEXT NOT NULL,
+ "q01" INTEGER,
+ "q02" INTEGER,
+ "q03" INTEGER,
+ "q04" INTEGER,
+ "q05" INTEGER,
+ "q06" INTEGER,
+ "q07" INTEGER,
+ "q08" INTEGER,
+ "q09" INTEGER,
+ "q10" INTEGER,
+ "q11" INTEGER,
+ "q12" INTEGER,
+ "q13" INTEGER,
+ "q14" INTEGER,
+ "q15" INTEGER,
+ "q16" INTEGER,
+ "q17" INTEGER,
+ "q18" INTEGER,
+ "q19" INTEGER,
+ "q20" INTEGER,
+ CONSTRAINT "PclQuestion_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT "PclQuestion_formId_fkey" FOREIGN KEY ("formId") REFERENCES "PclForm" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "change_audit" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "entityType" TEXT NOT NULL,
+ "entityId" TEXT NOT NULL,
+ "oldValue" TEXT,
+ "newValue" TEXT,
+ "reasoning" TEXT,
+ "documentationBase64" TEXT,
+ "signatureData" TEXT NOT NULL,
+ "signedById" TEXT NOT NULL,
+ "signedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ CONSTRAINT "change_audit_signedById_fkey" FOREIGN KEY ("signedById") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- RedefineTables
+PRAGMA defer_foreign_keys=ON;
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_user" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "name" TEXT NOT NULL,
+ "email" TEXT NOT NULL,
+ "emailVerified" BOOLEAN NOT NULL DEFAULT false,
+ "image" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "role" TEXT NOT NULL DEFAULT 'CLIENT',
+ "phoneNumber" INTEGER
+);
+INSERT INTO "new_user" ("createdAt", "email", "emailVerified", "id", "image", "name", "updatedAt") SELECT "createdAt", "email", "emailVerified", "id", "image", "name", "updatedAt" FROM "user";
+DROP TABLE "user";
+ALTER TABLE "new_user" RENAME TO "user";
+CREATE UNIQUE INDEX "user_email_key" ON "user"("email");
+PRAGMA foreign_keys=ON;
+PRAGMA defer_foreign_keys=OFF;
+
+-- CreateIndex
+CREATE UNIQUE INDEX "client_userId_key" ON "client"("userId");
+
+-- CreateIndex
+CREATE INDEX "client_status_idx" ON "client"("status");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "client_permission_clientId_key" ON "client_permission"("clientId");
+
+-- CreateIndex
+CREATE INDEX "session_note_clientId_idx" ON "session_note"("clientId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "client_plan_clientId_key" ON "client_plan"("clientId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "form_slug_key" ON "form"("slug");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "question_alias_key" ON "question"("alias");
+
+-- CreateIndex
+CREATE INDEX "form_question_formId_idx" ON "form_question"("formId");
+
+-- CreateIndex
+CREATE INDEX "form_question_questionId_idx" ON "form_question"("questionId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "form_question_formId_questionId_key" ON "form_question"("formId", "questionId");
+
+-- CreateIndex
+CREATE INDEX "form_assignment_userId_idx" ON "form_assignment"("userId");
+
+-- CreateIndex
+CREATE INDEX "form_assignment_formId_idx" ON "form_assignment"("formId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "form_assignment_userId_formId_key" ON "form_assignment"("userId", "formId");
+
+-- CreateIndex
+CREATE INDEX "ace_response_userId_idx" ON "ace_response"("userId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "AppForm_userId_key" ON "AppForm"("userId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "AppQuestion_formId_key" ON "AppQuestion"("formId");
+
+-- CreateIndex
+CREATE INDEX "AppQuestion_userId_idx" ON "AppQuestion"("userId");
+
+-- CreateIndex
+CREATE INDEX "GadForm_userId_idx" ON "GadForm"("userId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "GadQuestion_formId_key" ON "GadQuestion"("formId");
+
+-- CreateIndex
+CREATE INDEX "GadQuestion_userId_idx" ON "GadQuestion"("userId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "PhqForm_userId_key" ON "PhqForm"("userId");
+
+-- CreateIndex
+CREATE INDEX "PhqForm_userId_idx" ON "PhqForm"("userId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "PhqQuestion_formId_key" ON "PhqQuestion"("formId");
+
+-- CreateIndex
+CREATE INDEX "PhqQuestion_userId_idx" ON "PhqQuestion"("userId");
+
+-- CreateIndex
+CREATE INDEX "PclForm_userId_idx" ON "PclForm"("userId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "PclQuestion_formId_key" ON "PclQuestion"("formId");
+
+-- CreateIndex
+CREATE INDEX "PclQuestion_userId_idx" ON "PclQuestion"("userId");
+
+-- CreateIndex
+CREATE INDEX "change_audit_entityType_entityId_idx" ON "change_audit"("entityType", "entityId");
diff --git a/prisma/migrations/20260402034332_consolidate_notes_and_split_schemas/migration.sql b/prisma/migrations/20260402034332_consolidate_notes_and_split_schemas/migration.sql
new file mode 100644
index 0000000..e59221e
--- /dev/null
+++ b/prisma/migrations/20260402034332_consolidate_notes_and_split_schemas/migration.sql
@@ -0,0 +1,147 @@
+/*
+ Warnings:
+
+ - You are about to drop the column `documentationBase64` on the `change_audit` table. All the data in the column will be lost.
+
+*/
+-- AlterTable
+ALTER TABLE "PclQuestion" ADD COLUMN "worstEvent" TEXT;
+
+-- CreateTable
+CREATE TABLE "Appointment" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "clientId" TEXT NOT NULL,
+ "adminId" TEXT NOT NULL,
+ "title" TEXT NOT NULL,
+ "description" TEXT,
+ "startTime" DATETIME NOT NULL,
+ "endTime" DATETIME NOT NULL,
+ "status" TEXT NOT NULL DEFAULT 'SCHEDULED',
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Appointment_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "user" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
+ CONSTRAINT "Appointment_adminId_fkey" FOREIGN KEY ("adminId") REFERENCES "user" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "PhysicianStatementForm" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "userId" TEXT NOT NULL,
+ "status" TEXT NOT NULL DEFAULT 'NOT_SUBMITTED',
+ "originalFileName" TEXT,
+ "storedFileName" TEXT,
+ "mimeType" TEXT,
+ "uploadedAt" DATETIME,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "PhysicianStatementForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "ReleaseOfInformationAuthorizationForm" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "userId" TEXT NOT NULL,
+ "status" TEXT NOT NULL DEFAULT 'NOT_SUBMITTED',
+ "originalFileName" TEXT,
+ "storedFileName" TEXT,
+ "mimeType" TEXT,
+ "uploadedAt" DATETIME,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "ReleaseOfInformationAuthorizationForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "session_note_edit" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "sessionNoteId" TEXT NOT NULL,
+ "originalContent" TEXT,
+ "reason" TEXT,
+ "signature" TEXT,
+ "editedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ CONSTRAINT "session_note_edit_sessionNoteId_fkey" FOREIGN KEY ("sessionNoteId") REFERENCES "session_note" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "declaration_template" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "requestKind" TEXT NOT NULL,
+ "version" INTEGER NOT NULL,
+ "content" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+-- CreateTable
+CREATE TABLE "session_notes_request" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "clientId" TEXT NOT NULL,
+ "requestKind" TEXT NOT NULL,
+ "status" TEXT NOT NULL DEFAULT 'PENDING',
+ "signatureData" TEXT NOT NULL,
+ "declarationTemplateId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "decidedAt" DATETIME,
+ "decidedByUserId" TEXT,
+ "rejectionReason" TEXT,
+ "approvedSummaryText" TEXT,
+ CONSTRAINT "session_notes_request_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "client" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT "session_notes_request_declarationTemplateId_fkey" FOREIGN KEY ("declarationTemplateId") REFERENCES "declaration_template" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
+ CONSTRAINT "session_notes_request_decidedByUserId_fkey" FOREIGN KEY ("decidedByUserId") REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+
+-- RedefineTables
+PRAGMA defer_foreign_keys=ON;
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_change_audit" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "entityType" TEXT NOT NULL,
+ "entityId" TEXT NOT NULL,
+ "oldValue" TEXT,
+ "newValue" TEXT,
+ "reasoning" TEXT,
+ "documentationPath" TEXT,
+ "documentationName" TEXT,
+ "signatureData" TEXT NOT NULL,
+ "signedById" TEXT NOT NULL,
+ "signedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ CONSTRAINT "change_audit_signedById_fkey" FOREIGN KEY ("signedById") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+INSERT INTO "new_change_audit" ("entityId", "entityType", "id", "newValue", "oldValue", "reasoning", "signatureData", "signedAt", "signedById") SELECT "entityId", "entityType", "id", "newValue", "oldValue", "reasoning", "signatureData", "signedAt", "signedById" FROM "change_audit";
+DROP TABLE "change_audit";
+ALTER TABLE "new_change_audit" RENAME TO "change_audit";
+CREATE INDEX "change_audit_entityType_entityId_idx" ON "change_audit"("entityType", "entityId");
+PRAGMA foreign_keys=ON;
+PRAGMA defer_foreign_keys=OFF;
+
+-- CreateIndex
+CREATE INDEX "Appointment_clientId_idx" ON "Appointment"("clientId");
+
+-- CreateIndex
+CREATE INDEX "Appointment_adminId_idx" ON "Appointment"("adminId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "PhysicianStatementForm_userId_key" ON "PhysicianStatementForm"("userId");
+
+-- CreateIndex
+CREATE INDEX "PhysicianStatementForm_status_idx" ON "PhysicianStatementForm"("status");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "ReleaseOfInformationAuthorizationForm_userId_key" ON "ReleaseOfInformationAuthorizationForm"("userId");
+
+-- CreateIndex
+CREATE INDEX "ReleaseOfInformationAuthorizationForm_status_idx" ON "ReleaseOfInformationAuthorizationForm"("status");
+
+-- CreateIndex
+CREATE INDEX "session_note_edit_sessionNoteId_idx" ON "session_note_edit"("sessionNoteId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "declaration_template_requestKind_version_key" ON "declaration_template"("requestKind", "version");
+
+-- CreateIndex
+CREATE INDEX "session_notes_request_clientId_idx" ON "session_notes_request"("clientId");
+
+-- CreateIndex
+CREATE INDEX "session_notes_request_status_idx" ON "session_notes_request"("status");
+
+-- CreateIndex
+CREATE INDEX "session_notes_request_declarationTemplateId_idx" ON "session_notes_request"("declarationTemplateId");
diff --git a/prisma/migrations/20260402035909_remove_dynamic_forms/migration.sql b/prisma/migrations/20260402035909_remove_dynamic_forms/migration.sql
new file mode 100644
index 0000000..21cc75c
--- /dev/null
+++ b/prisma/migrations/20260402035909_remove_dynamic_forms/migration.sql
@@ -0,0 +1,28 @@
+/*
+ Warnings:
+
+ - You are about to drop the `form` table. If the table is not empty, all the data it contains will be lost.
+ - You are about to drop the `form_assignment` table. If the table is not empty, all the data it contains will be lost.
+ - You are about to drop the `form_question` table. If the table is not empty, all the data it contains will be lost.
+ - You are about to drop the `question` table. If the table is not empty, all the data it contains will be lost.
+
+*/
+-- DropTable
+PRAGMA foreign_keys=off;
+DROP TABLE "form";
+PRAGMA foreign_keys=on;
+
+-- DropTable
+PRAGMA foreign_keys=off;
+DROP TABLE "form_assignment";
+PRAGMA foreign_keys=on;
+
+-- DropTable
+PRAGMA foreign_keys=off;
+DROP TABLE "form_question";
+PRAGMA foreign_keys=on;
+
+-- DropTable
+PRAGMA foreign_keys=off;
+DROP TABLE "question";
+PRAGMA foreign_keys=on;
diff --git a/prisma/migrations/20260402041509_hardcode_ace_form/migration.sql b/prisma/migrations/20260402041509_hardcode_ace_form/migration.sql
new file mode 100644
index 0000000..575593d
--- /dev/null
+++ b/prisma/migrations/20260402041509_hardcode_ace_form/migration.sql
@@ -0,0 +1,52 @@
+/*
+ Warnings:
+
+ - You are about to drop the `ace_response` table. If the table is not empty, all the data it contains will be lost.
+
+*/
+-- DropTable
+PRAGMA foreign_keys=off;
+DROP TABLE "ace_response";
+PRAGMA foreign_keys=on;
+
+-- CreateTable
+CREATE TABLE "ace_form" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "userId" TEXT NOT NULL,
+ "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS',
+ "totalScore" INTEGER,
+ "severity" TEXT,
+ "submittedAt" DATETIME,
+ CONSTRAINT "ace_form_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "ace_question" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "formId" INTEGER NOT NULL,
+ "userId" TEXT NOT NULL,
+ "a01" TEXT,
+ "a02" TEXT,
+ "a03" TEXT,
+ "a04" TEXT,
+ "a05" TEXT,
+ "a06" TEXT,
+ "a07" TEXT,
+ "a08" TEXT,
+ "a09" TEXT,
+ "a10" TEXT,
+ CONSTRAINT "ace_question_formId_fkey" FOREIGN KEY ("formId") REFERENCES "ace_form" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT "ace_question_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "ace_form_userId_key" ON "ace_form"("userId");
+
+-- CreateIndex
+CREATE INDEX "ace_form_userId_idx" ON "ace_form"("userId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "ace_question_formId_key" ON "ace_question"("formId");
+
+-- CreateIndex
+CREATE INDEX "ace_question_userId_idx" ON "ace_question"("userId");
diff --git a/prisma/migrations/20260426215909_add_client_clinician_user_id/migration.sql b/prisma/migrations/20260426215909_add_client_clinician_user_id/migration.sql
new file mode 100644
index 0000000..edb850a
--- /dev/null
+++ b/prisma/migrations/20260426215909_add_client_clinician_user_id/migration.sql
@@ -0,0 +1,194 @@
+/*
+ Warnings:
+
+ - You are about to drop the `ace_form` table. If the table is not empty, all the data it contains will be lost.
+ - You are about to drop the `ace_question` table. If the table is not empty, all the data it contains will be lost.
+ - Added the required column `sessionName` to the `Appointment` table without a default value. This is not possible if the table is not empty.
+ - Added the required column `sessionNumber` to the `Appointment` table without a default value. This is not possible if the table is not empty.
+ - Added the required column `sessionName` to the `session_note` table without a default value. This is not possible if the table is not empty.
+ - Added the required column `sessionNumber` to the `session_note` table without a default value. This is not possible if the table is not empty.
+
+*/
+-- DropIndex
+DROP INDEX "PhqForm_userId_key";
+
+-- DropIndex
+DROP INDEX "ace_form_userId_idx";
+
+-- DropIndex
+DROP INDEX "ace_form_userId_key";
+
+-- DropIndex
+DROP INDEX "ace_question_userId_idx";
+
+-- DropIndex
+DROP INDEX "ace_question_formId_key";
+
+-- AlterTable
+ALTER TABLE "session_notes_request" ADD COLUMN "approvalReason" TEXT;
+ALTER TABLE "session_notes_request" ADD COLUMN "endDate" DATETIME;
+ALTER TABLE "session_notes_request" ADD COLUMN "startDate" DATETIME;
+
+-- DropTable
+PRAGMA foreign_keys=off;
+DROP TABLE "ace_form";
+PRAGMA foreign_keys=on;
+
+-- DropTable
+PRAGMA foreign_keys=off;
+DROP TABLE "ace_question";
+PRAGMA foreign_keys=on;
+
+-- CreateTable
+CREATE TABLE "client_form_score_history" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "userId" TEXT NOT NULL,
+ "formKey" TEXT NOT NULL,
+ "score" INTEGER,
+ "severity" TEXT,
+ "recordedAt" DATETIME NOT NULL,
+ "answersJson" TEXT,
+ CONSTRAINT "client_form_score_history_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "AceForm" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "userId" TEXT NOT NULL,
+ "status" TEXT NOT NULL DEFAULT 'IN_PROGRESS',
+ "totalScore" INTEGER,
+ "severity" TEXT,
+ "submittedAt" DATETIME,
+ CONSTRAINT "AceForm_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "AceQuestion" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "formId" INTEGER NOT NULL,
+ "userId" TEXT NOT NULL,
+ "a01" TEXT,
+ "a02" TEXT,
+ "a03" TEXT,
+ "a04" TEXT,
+ "a05" TEXT,
+ "a06" TEXT,
+ "a07" TEXT,
+ "a08" TEXT,
+ "a09" TEXT,
+ "a10" TEXT,
+ CONSTRAINT "AceQuestion_formId_fkey" FOREIGN KEY ("formId") REFERENCES "AceForm" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT "AceQuestion_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateTable
+CREATE TABLE "notification" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "userId" TEXT NOT NULL,
+ "type" TEXT NOT NULL,
+ "title" TEXT NOT NULL,
+ "message" TEXT NOT NULL,
+ "sessionNoteId" TEXT,
+ "readAt" DATETIME,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ CONSTRAINT "notification_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT "notification_sessionNoteId_fkey" FOREIGN KEY ("sessionNoteId") REFERENCES "session_note" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- RedefineTables
+PRAGMA defer_foreign_keys=ON;
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_Appointment" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "clientId" TEXT NOT NULL,
+ "adminId" TEXT NOT NULL,
+ "title" TEXT NOT NULL,
+ "sessionName" TEXT NOT NULL,
+ "sessionNumber" INTEGER NOT NULL,
+ "description" TEXT,
+ "startTime" DATETIME NOT NULL,
+ "endTime" DATETIME NOT NULL,
+ "status" TEXT NOT NULL DEFAULT 'SCHEDULED',
+ "videoProvider" TEXT,
+ "videoJoinUrl" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ CONSTRAINT "Appointment_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "user" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
+ CONSTRAINT "Appointment_adminId_fkey" FOREIGN KEY ("adminId") REFERENCES "user" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
+);
+INSERT INTO "new_Appointment" ("adminId", "clientId", "createdAt", "description", "endTime", "id", "startTime", "status", "title", "updatedAt") SELECT "adminId", "clientId", "createdAt", "description", "endTime", "id", "startTime", "status", "title", "updatedAt" FROM "Appointment";
+DROP TABLE "Appointment";
+ALTER TABLE "new_Appointment" RENAME TO "Appointment";
+CREATE INDEX "Appointment_clientId_idx" ON "Appointment"("clientId");
+CREATE INDEX "Appointment_adminId_idx" ON "Appointment"("adminId");
+CREATE UNIQUE INDEX "Appointment_clientId_sessionNumber_key" ON "Appointment"("clientId", "sessionNumber");
+CREATE TABLE "new_client" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "userId" TEXT NOT NULL,
+ "status" TEXT NOT NULL DEFAULT 'INCOMPLETE',
+ "waitlistedAt" DATETIME,
+ "archivedAt" DATETIME,
+ "therapyWeek" INTEGER,
+ "missedSessions" INTEGER NOT NULL DEFAULT 0,
+ "clinicianUserId" TEXT,
+ CONSTRAINT "client_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT "client_clinicianUserId_fkey" FOREIGN KEY ("clinicianUserId") REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+INSERT INTO "new_client" ("id", "missedSessions", "status", "therapyWeek", "userId") SELECT "id", "missedSessions", "status", "therapyWeek", "userId" FROM "client";
+DROP TABLE "client";
+ALTER TABLE "new_client" RENAME TO "client";
+CREATE UNIQUE INDEX "client_userId_key" ON "client"("userId");
+CREATE INDEX "client_status_idx" ON "client"("status");
+CREATE INDEX "client_clinicianUserId_idx" ON "client"("clinicianUserId");
+CREATE TABLE "new_session_note" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "clientId" TEXT NOT NULL,
+ "sessionName" TEXT NOT NULL,
+ "sessionNumber" INTEGER NOT NULL,
+ "appointmentId" TEXT,
+ "kind" TEXT NOT NULL DEFAULT 'PROGRESS',
+ "status" TEXT NOT NULL DEFAULT 'DRAFT',
+ "content" TEXT NOT NULL,
+ "attended" BOOLEAN NOT NULL DEFAULT true,
+ "signatureData" TEXT,
+ "clinicianSignedAt" DATETIME,
+ "clinicianSignedById" TEXT,
+ "clinicianSignatureData" TEXT,
+ "adminSignedAt" DATETIME,
+ "adminSignedById" TEXT,
+ "adminSignatureData" TEXT,
+ "adminApprovalNote" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ CONSTRAINT "session_note_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "client" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT "session_note_appointmentId_fkey" FOREIGN KEY ("appointmentId") REFERENCES "Appointment" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
+ CONSTRAINT "session_note_clinicianSignedById_fkey" FOREIGN KEY ("clinicianSignedById") REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
+ CONSTRAINT "session_note_adminSignedById_fkey" FOREIGN KEY ("adminSignedById") REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+INSERT INTO "new_session_note" ("clientId", "content", "createdAt", "id") SELECT "clientId", "content", "createdAt", "id" FROM "session_note";
+DROP TABLE "session_note";
+ALTER TABLE "new_session_note" RENAME TO "session_note";
+CREATE INDEX "session_note_clientId_idx" ON "session_note"("clientId");
+CREATE INDEX "session_note_appointmentId_idx" ON "session_note"("appointmentId");
+CREATE INDEX "session_note_status_idx" ON "session_note"("status");
+CREATE INDEX "session_note_kind_idx" ON "session_note"("kind");
+PRAGMA foreign_keys=ON;
+PRAGMA defer_foreign_keys=OFF;
+
+-- CreateIndex
+CREATE INDEX "client_form_score_history_userId_recordedAt_idx" ON "client_form_score_history"("userId", "recordedAt");
+
+-- CreateIndex
+CREATE INDEX "AceForm_userId_idx" ON "AceForm"("userId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "AceQuestion_formId_key" ON "AceQuestion"("formId");
+
+-- CreateIndex
+CREATE INDEX "AceQuestion_userId_idx" ON "AceQuestion"("userId");
+
+-- CreateIndex
+CREATE INDEX "notification_userId_readAt_idx" ON "notification"("userId", "readAt");
+
+-- CreateIndex
+CREATE INDEX "notification_userId_createdAt_idx" ON "notification"("userId", "createdAt");
diff --git a/prisma/migrations/20260427031935_add_attendance_status/migration.sql b/prisma/migrations/20260427031935_add_attendance_status/migration.sql
new file mode 100644
index 0000000..ad82aa1
--- /dev/null
+++ b/prisma/migrations/20260427031935_add_attendance_status/migration.sql
@@ -0,0 +1,48 @@
+/*
+ Warnings:
+
+ - You are about to drop the column `attended` on the `session_note` table. All the data in the column will be lost.
+
+*/
+-- AlterTable
+ALTER TABLE "session_note_edit" ADD COLUMN "editedContent" TEXT;
+ALTER TABLE "session_note_edit" ADD COLUMN "newAttendanceStatus" TEXT;
+ALTER TABLE "session_note_edit" ADD COLUMN "oldAttendanceStatus" TEXT;
+
+-- RedefineTables
+PRAGMA defer_foreign_keys=ON;
+PRAGMA foreign_keys=OFF;
+CREATE TABLE "new_session_note" (
+ "id" TEXT NOT NULL PRIMARY KEY,
+ "clientId" TEXT NOT NULL,
+ "content" TEXT NOT NULL,
+ "attendanceStatus" TEXT DEFAULT 'show',
+ "sessionName" TEXT NOT NULL,
+ "sessionNumber" INTEGER NOT NULL,
+ "appointmentId" TEXT,
+ "kind" TEXT NOT NULL DEFAULT 'PROGRESS',
+ "status" TEXT NOT NULL DEFAULT 'DRAFT',
+ "signatureData" TEXT,
+ "clinicianSignedAt" DATETIME,
+ "clinicianSignedById" TEXT,
+ "clinicianSignatureData" TEXT,
+ "adminSignedAt" DATETIME,
+ "adminSignedById" TEXT,
+ "adminSignatureData" TEXT,
+ "adminApprovalNote" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ CONSTRAINT "session_note_clientId_fkey" FOREIGN KEY ("clientId") REFERENCES "client" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT "session_note_appointmentId_fkey" FOREIGN KEY ("appointmentId") REFERENCES "Appointment" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
+ CONSTRAINT "session_note_clinicianSignedById_fkey" FOREIGN KEY ("clinicianSignedById") REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
+ CONSTRAINT "session_note_adminSignedById_fkey" FOREIGN KEY ("adminSignedById") REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+INSERT INTO "new_session_note" ("adminApprovalNote", "adminSignatureData", "adminSignedAt", "adminSignedById", "appointmentId", "clientId", "clinicianSignatureData", "clinicianSignedAt", "clinicianSignedById", "content", "createdAt", "id", "kind", "sessionName", "sessionNumber", "signatureData", "status", "updatedAt") SELECT "adminApprovalNote", "adminSignatureData", "adminSignedAt", "adminSignedById", "appointmentId", "clientId", "clinicianSignatureData", "clinicianSignedAt", "clinicianSignedById", "content", "createdAt", "id", "kind", "sessionName", "sessionNumber", "signatureData", "status", "updatedAt" FROM "session_note";
+DROP TABLE "session_note";
+ALTER TABLE "new_session_note" RENAME TO "session_note";
+CREATE INDEX "session_note_clientId_idx" ON "session_note"("clientId");
+CREATE INDEX "session_note_appointmentId_idx" ON "session_note"("appointmentId");
+CREATE INDEX "session_note_status_idx" ON "session_note"("status");
+CREATE INDEX "session_note_kind_idx" ON "session_note"("kind");
+PRAGMA foreign_keys=ON;
+PRAGMA defer_foreign_keys=OFF;
diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml
new file mode 100644
index 0000000..2a5a444
--- /dev/null
+++ b/prisma/migrations/migration_lock.toml
@@ -0,0 +1,3 @@
+# Please do not edit this file manually
+# It should be added in your version-control system (e.g., Git)
+provider = "sqlite"
From 72ee145c9378357e56be1fc110461133437300b9 Mon Sep 17 00:00:00 2001
From: Charvisree Koripella
Date: Tue, 28 Apr 2026 02:23:27 -0500
Subject: [PATCH 23/30] Fixed the toolbar and editor layout, checkbox, and
toolbar
---
app/components/Notes.vue | 83 ++++-----
app/components/NotesToolbar.vue | 100 +++++++----
package-lock.json | 300 ++++++++++----------------------
package.json | 2 +
4 files changed, 193 insertions(+), 292 deletions(-)
diff --git a/app/components/Notes.vue b/app/components/Notes.vue
index 98d0586..76e2f67 100644
--- a/app/components/Notes.vue
+++ b/app/components/Notes.vue
@@ -1037,7 +1037,7 @@
@@ -1094,7 +1094,7 @@
-
+
-
-
-
-
{{ currentNote.date }}
-
Current
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
{{ currentNote.date }}
@@ -1559,43 +1541,41 @@
- Psychotherapy (process) notes are stored separately and are not visible to
- the client.
+ Psychotherapy (process) notes are stored separately and are not visible to the client.
-
- Current
-
-
-
+
-
+
+
+
+
+
+
{{ currentNoteLockMessage }}
-
+
-
● Saving...
Saved {{ formatTime(lastSaved) }}
- Failed to save
+ Failed to save
-
-
+
+
{{ attendanceLockMessage }}
+
-
-//import type { EditorToolbarItem } from '@nuxt/ui'
-
-type EditorToolbarItem = any;
+import type { EditorToolbarItem } from '@nuxt/ui'
+import TaskList from '@tiptap/extension-task-list'
+import TaskItem from '@tiptap/extension-task-item'
const props = defineProps<{
modelValue: string
- contentType?: 'html' | 'markdown' | 'json'
+ contentType?: 'html' | 'markdown' | 'json'
}>()
const emit = defineEmits<{
@@ -13,22 +13,12 @@ const emit = defineEmits<{
}>()
const localContent = ref(props.modelValue)
-const editor = ref
(null)
-
-watch(() => props.modelValue, (newVal: string) => {
- localContent.value = newVal
-})
-
-watch(localContent, (newVal: string) => {
- emit('update:modelValue', newVal)
-}, { deep: true })
const items: EditorToolbarItem[][] = [
[
{
icon: 'i-lucide-heading',
tooltip: { text: 'Headings' },
- content: { align: 'start' },
items: [
{ kind: 'heading', level: 1, icon: 'i-lucide-heading-1', label: 'Heading 1' },
{ kind: 'heading', level: 2, icon: 'i-lucide-heading-2', label: 'Heading 2' },
@@ -45,41 +35,41 @@ const items: EditorToolbarItem[][] = [
[
{ kind: 'bulletList', icon: 'i-lucide-list', tooltip: { text: 'Bullet List' } },
{ kind: 'orderedList', icon: 'i-lucide-list-ordered', tooltip: { text: 'Ordered List' } },
- { slot: 'taskList' },
+ { slot: 'taskList' }
]
]
-
-
+
+
-
-
-
-
-
+
+
+
+
+
@@ -87,11 +77,49 @@ const items: EditorToolbarItem[][] = [
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 61f9bd2..44880bd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,6 +15,8 @@
"@nuxt/ui": "4.6.0",
"@prisma/adapter-better-sqlite3": "^7.2.0",
"@prisma/client": "^7.2.0",
+ "@tiptap/extension-task-item": "^3.22.4",
+ "@tiptap/extension-task-list": "^3.22.4",
"@tiptap/extension-text-align": "^3.20.1",
"@types/dompurify": "^3.2.0",
"@types/nodemailer": "^7.0.4",
@@ -92,6 +94,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
@@ -465,6 +468,7 @@
"version": "1.4.18",
"resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.4.18.tgz",
"integrity": "sha512-q+awYgC7nkLEBdx2sW0iJjkzgSHlIxGnOpsN1r/O1+a4m7osJNHtfK2mKJSL1I+GfNyIlxJF8WvD/NLuYMpmcg==",
+ "peer": true,
"dependencies": {
"@standard-schema/spec": "^1.0.0",
"zod": "^4.3.5"
@@ -494,12 +498,14 @@
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.3.0.tgz",
"integrity": "sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw==",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/@better-fetch/fetch": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.1.21.tgz",
- "integrity": "sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A=="
+ "integrity": "sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A==",
+ "peer": true
},
"node_modules/@bomb.sh/tab": {
"version": "0.0.14",
@@ -644,7 +650,8 @@
"resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.3.15.tgz",
"integrity": "sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ==",
"devOptional": true,
- "license": "Apache-2.0"
+ "license": "Apache-2.0",
+ "peer": true
},
"node_modules/@electric-sql/pglite-socket": {
"version": "0.0.20",
@@ -1130,6 +1137,7 @@
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz",
"integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@floating-ui/core": "^1.7.5",
"@floating-ui/utils": "^0.2.11"
@@ -1891,6 +1899,7 @@
"resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.4.2.tgz",
"integrity": "sha512-5+IPRNX2CjkBhuWUwz0hBuLqiaJPRoKzQ+SvcdrQDbAyE+VDeFt74VpSFr5/R0ujrK4b+XnSHUJWdS72w6hsog==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"c12": "^3.3.3",
"consola": "^3.4.2",
@@ -3705,6 +3714,7 @@
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-7.3.0.tgz",
"integrity": "sha512-FXBIxirqQfdC6b6HnNgxGmU7ydCPEPk7maHMOduJJfnTP+MuOGa15X4omjR/zpPUUpm8ef/mEFQjJudOGkXFcQ==",
"license": "Apache-2.0",
+ "peer": true,
"dependencies": {
"@prisma/client-runtime-utils": "7.3.0"
},
@@ -3952,12 +3962,6 @@
"react-dom": "^18.0.0 || ^19.0.0"
}
},
- "node_modules/@remirror/core-constants": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz",
- "integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==",
- "license": "MIT"
- },
"node_modules/@rolldown/pluginutils": {
"version": "1.0.0-rc.2",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz",
@@ -4855,16 +4859,17 @@
}
},
"node_modules/@tiptap/core": {
- "version": "3.20.5",
- "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.20.5.tgz",
- "integrity": "sha512-Pkjd41UJ4F6Z8cPV+gEvqnt1VhY2g66xMjbpxREs0ECA5jRezCNKSZcc2pueQRTMtmn1SaSzGM9U/ifhVlVYOA==",
+ "version": "3.22.4",
+ "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.22.4.tgz",
+ "integrity": "sha512-vGIGm/HpqLg8EAAQXQ+koV+/S828OEpzocfWcPOwo1u2QUVf9dQG47Yy6JJ8zFFaJwfv4dBcOXli+7BrJwsxDQ==",
"license": "MIT",
+ "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
},
"peerDependencies": {
- "@tiptap/pm": "^3.20.5"
+ "@tiptap/pm": "3.22.4"
}
},
"node_modules/@tiptap/extension-blockquote": {
@@ -4955,6 +4960,7 @@
"resolved": "https://registry.npmjs.org/@tiptap/extension-collaboration/-/extension-collaboration-3.20.5.tgz",
"integrity": "sha512-IalIm6BznHds2VzR4+6gMAgi4VXwZAXdYkl28EPZ8/xscBaUn1tCxcTBbCpmN3UhkABaCoJtmmER5TDy+x72Ag==",
"license": "MIT",
+ "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -4984,6 +4990,7 @@
"resolved": "https://registry.npmjs.org/@tiptap/extension-drag-handle/-/extension-drag-handle-3.20.5.tgz",
"integrity": "sha512-D2W2fkpmXKRG4i0K0XVfbsTRYQMU9RudQIXBB7HnYZFosyJs3dvsT1cFurDUANKLPCxbI24eiubAKs6b1vzGpA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@floating-ui/dom": "^1.6.13"
},
@@ -5140,17 +5147,18 @@
}
},
"node_modules/@tiptap/extension-list": {
- "version": "3.20.5",
- "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.20.5.tgz",
- "integrity": "sha512-s+Y8Q7Orq+WQiwgFB/VPMYZe+6EAR2F69xCpvOynlzTInLO4cF6QpXomuGEYAZxLHe8ZBmeIaR7y8MH/OgjrDw==",
+ "version": "3.22.4",
+ "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.22.4.tgz",
+ "integrity": "sha512-Xe8UFvvHmyp/c/TJsFwlwU9CWACYbBirNsluJ3U1+H8BTu1wqdrT/AXR5uIXeyCl5kiWKgX5q71eHWbYFOrqrg==",
"license": "MIT",
+ "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
},
"peerDependencies": {
- "@tiptap/core": "^3.20.5",
- "@tiptap/pm": "^3.20.5"
+ "@tiptap/core": "3.22.4",
+ "@tiptap/pm": "3.22.4"
}
},
"node_modules/@tiptap/extension-list-item": {
@@ -5199,6 +5207,7 @@
"resolved": "https://registry.npmjs.org/@tiptap/extension-node-range/-/extension-node-range-3.20.5.tgz",
"integrity": "sha512-6CbgZULF+dQ9KTothAORBZAXPdGneWicMWTV3Gyeh9gNySC18QsGQj3D2GxnllpMekmZXydtDbNFSoCiWjKFWQ==",
"license": "MIT",
+ "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -5260,6 +5269,32 @@
"@tiptap/core": "^3.20.5"
}
},
+ "node_modules/@tiptap/extension-task-item": {
+ "version": "3.22.4",
+ "resolved": "https://registry.npmjs.org/@tiptap/extension-task-item/-/extension-task-item-3.22.4.tgz",
+ "integrity": "sha512-PhoiOMatdRXJU1HJz0fMP5N7wv0eYAz/Id/gphby/gdxjYQaMhJ7vQiLTR28EkVBkdntTUb1bwZ4XQn9thFtpw==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/ueberdosis"
+ },
+ "peerDependencies": {
+ "@tiptap/extension-list": "3.22.4"
+ }
+ },
+ "node_modules/@tiptap/extension-task-list": {
+ "version": "3.22.4",
+ "resolved": "https://registry.npmjs.org/@tiptap/extension-task-list/-/extension-task-list-3.22.4.tgz",
+ "integrity": "sha512-5M3XiZMZJ2mwWSUKPG4mb90g86rpgYw7yf8lBEkaCgke9XxsLg8mXmYRpCc6n/v1TQXryB+WDKuenCzJTx/4/A==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/ueberdosis"
+ },
+ "peerDependencies": {
+ "@tiptap/extension-list": "3.22.4"
+ }
+ },
"node_modules/@tiptap/extension-text": {
"version": "3.20.5",
"resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.20.5.tgz",
@@ -5304,6 +5339,7 @@
"resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.20.5.tgz",
"integrity": "sha512-c4am6SznqfMnbUNSh4MvufiD7cMLdqL1BArok22uBgSWkS1sB9RVBYe8+x0jrOkk0UPEVlzDHbQ+nU+WmIyS2Q==",
"license": "MIT",
+ "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -5331,27 +5367,22 @@
}
},
"node_modules/@tiptap/pm": {
- "version": "3.20.5",
- "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.20.5.tgz",
- "integrity": "sha512-yJhDa7Chx2EqJMX/jlewBv0za7slf1dKHWYve1XaApuVHEkxl0Ul3EDbwnx316vIITkuFW/pWSwkSsAplyBeCw==",
+ "version": "3.22.4",
+ "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.22.4.tgz",
+ "integrity": "sha512-hj8Qka6WcHRllHUdeSjDnq2XaisUo4KsoGJc1WcFpoa1Yd+OeD861zUMnV7DFVGdZRy45Obht0CUYJpXQ4yA4w==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"prosemirror-changeset": "^2.3.0",
- "prosemirror-collab": "^1.3.1",
"prosemirror-commands": "^1.6.2",
"prosemirror-dropcursor": "^1.8.1",
"prosemirror-gapcursor": "^1.3.2",
"prosemirror-history": "^1.4.1",
- "prosemirror-inputrules": "^1.4.0",
"prosemirror-keymap": "^1.2.2",
- "prosemirror-markdown": "^1.13.1",
- "prosemirror-menu": "^1.2.4",
"prosemirror-model": "^1.24.1",
- "prosemirror-schema-basic": "^1.2.3",
"prosemirror-schema-list": "^1.5.0",
"prosemirror-state": "^1.4.3",
"prosemirror-tables": "^1.6.4",
- "prosemirror-trailing-node": "^3.0.0",
"prosemirror-transform": "^1.10.2",
"prosemirror-view": "^1.38.1"
},
@@ -5401,6 +5432,7 @@
"resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-3.20.5.tgz",
"integrity": "sha512-5fqRNgnzYdJ1oDpyLqwrbVsZwvI+5VW/U89LPMvBYM7sFS7Xd0xfyxyAOWcJN4V0zLeTcuElWN3R+IUTLKbU+Q==",
"license": "MIT",
+ "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -5415,6 +5447,7 @@
"resolved": "https://registry.npmjs.org/@tiptap/vue-3/-/vue-3-3.20.5.tgz",
"integrity": "sha512-5uUK3RAMNvUetZOv56Kz8nurhxHxMH60GgCCrVFgIBZoTc14u3d3v7EpcA6gNgzogutrR8GxvyFU3iIkj4kkHA==",
"license": "MIT",
+ "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -5487,28 +5520,6 @@
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
"license": "MIT"
},
- "node_modules/@types/linkify-it": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
- "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
- "license": "MIT"
- },
- "node_modules/@types/markdown-it": {
- "version": "14.1.2",
- "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
- "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
- "license": "MIT",
- "dependencies": {
- "@types/linkify-it": "^5",
- "@types/mdurl": "^2"
- }
- },
- "node_modules/@types/mdurl": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
- "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
- "license": "MIT"
- },
"node_modules/@types/node": {
"version": "25.1.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.1.0.tgz",
@@ -5887,6 +5898,7 @@
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.2.1.tgz",
"integrity": "sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/web-bluetooth": "^0.0.21",
"@vueuse/metadata": "14.2.1",
@@ -6012,6 +6024,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"license": "MIT",
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -6216,12 +6229,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "license": "Python-2.0"
- },
"node_modules/aria-hidden": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
@@ -6352,6 +6359,7 @@
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz",
"integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==",
"license": "Apache-2.0",
+ "peer": true,
"peerDependencies": {
"bare-abort-controller": "*"
},
@@ -6575,6 +6583,7 @@
"resolved": "https://registry.npmjs.org/better-call/-/better-call-1.1.8.tgz",
"integrity": "sha512-XMQ2rs6FNXasGNfMjzbyroSwKwYbZ/T3IxruSS6U2MJRsSYh3wYtG3o6H00ZlKZ/C/UPOAD97tqgQJNsxyeTXw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@better-auth/utils": "^0.3.0",
"@better-fetch/fetch": "^1.1.4",
@@ -6720,6 +6729,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -6821,6 +6831,7 @@
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=8"
}
@@ -6938,6 +6949,7 @@
"resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz",
"integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"consola": "^3.2.3"
}
@@ -7136,12 +7148,6 @@
"node": ">= 14"
}
},
- "node_modules/crelt": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
- "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
- "license": "MIT"
- },
"node_modules/croner": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/croner/-/croner-10.0.1.tgz",
@@ -7694,7 +7700,8 @@
"version": "8.6.0",
"resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz",
"integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/embla-carousel-auto-height": {
"version": "8.6.0",
@@ -8271,6 +8278,7 @@
"resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.1.0.tgz",
"integrity": "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==",
"license": "Apache-2.0",
+ "peer": true,
"engines": {
"node": ">=10"
}
@@ -8524,6 +8532,7 @@
"integrity": "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==",
"devOptional": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=16.9.0"
}
@@ -8917,7 +8926,6 @@
"resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz",
"integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==",
"license": "MIT",
- "peer": true,
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
@@ -8952,6 +8960,7 @@
"resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz",
"integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==",
"license": "MIT",
+ "peer": true,
"funding": {
"url": "https://github.com/sponsors/panva"
}
@@ -9015,6 +9024,7 @@
"resolved": "https://registry.npmjs.org/kysely/-/kysely-0.28.10.tgz",
"integrity": "sha512-ksNxfzIW77OcZ+QWSAPC7yDqUSaIVwkTWnTPNiIy//vifNbwsSgQ57OkkncHxxpcBHM3LRfLAZVEh7kjq5twVA==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=20.0.0"
}
@@ -9076,7 +9086,6 @@
"resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.117.tgz",
"integrity": "sha512-DeXj9X5xDCjgKLU/7RR+/HQEVzuuEUiwldwOGsHK/sfAfELGWEyTcf0x+uOvCvK3O2zPmZePXWL85vtia6GyZw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"isomorphic.js": "^0.2.4"
},
@@ -9354,15 +9363,6 @@
"url": "https://github.com/sponsors/antonk52"
}
},
- "node_modules/linkify-it": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
- "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
- "license": "MIT",
- "dependencies": {
- "uc.micro": "^2.0.0"
- }
- },
"node_modules/linkifyjs": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.2.tgz",
@@ -9523,35 +9523,6 @@
"url": "https://github.com/sponsors/sxzz"
}
},
- "node_modules/markdown-it": {
- "version": "14.1.1",
- "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz",
- "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==",
- "license": "MIT",
- "dependencies": {
- "argparse": "^2.0.1",
- "entities": "^4.4.0",
- "linkify-it": "^5.0.0",
- "mdurl": "^2.0.0",
- "punycode.js": "^2.3.1",
- "uc.micro": "^2.1.0"
- },
- "bin": {
- "markdown-it": "bin/markdown-it.mjs"
- }
- },
- "node_modules/markdown-it/node_modules/entities": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
- "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=0.12"
- },
- "funding": {
- "url": "https://github.com/fb55/entities?sponsor=1"
- }
- },
"node_modules/marked": {
"version": "17.0.4",
"resolved": "https://registry.npmjs.org/marked/-/marked-17.0.4.tgz",
@@ -9570,12 +9541,6 @@
"integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==",
"license": "CC0-1.0"
},
- "node_modules/mdurl": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
- "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
- "license": "MIT"
- },
"node_modules/merge-images": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/merge-images/-/merge-images-1.2.0.tgz",
@@ -9830,6 +9795,7 @@
"integrity": "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==",
"devOptional": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"aws-ssl-profiles": "^1.1.1",
"denque": "^2.1.0",
@@ -9886,6 +9852,7 @@
}
],
"license": "MIT",
+ "peer": true,
"engines": {
"node": "^20.0.0 || >=22.0.0"
}
@@ -10222,6 +10189,7 @@
"resolved": "https://registry.npmjs.org/nuxt/-/nuxt-4.4.2.tgz",
"integrity": "sha512-iWVFpr/YEqVU/CenqIHMnIkvb2HE/9f+q8oxZ+pj2et+60NljGRClCgnmbvGPdmNFE0F1bEhoBCYfqbDOCim3Q==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@dxup/nuxt": "^0.4.0",
"@nuxt/cli": "^3.34.0",
@@ -10574,6 +10542,7 @@
"resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.117.0.tgz",
"integrity": "sha512-l3cbgK5wUvWDVNWM/JFU77qDdGZK1wudnLsFcrRyNo/bL1CyU8pC25vDhMHikVY29lbK2InTWsX42RxVSutUdQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@oxc-project/types": "^0.117.0"
},
@@ -10773,6 +10742,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -11261,7 +11231,6 @@
"resolved": "https://registry.npmjs.org/preact/-/preact-10.12.1.tgz",
"integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==",
"license": "MIT",
- "peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
@@ -11299,6 +11268,7 @@
"integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -11407,6 +11377,7 @@
"devOptional": true,
"hasInstallScript": true,
"license": "Apache-2.0",
+ "peer": true,
"dependencies": {
"@prisma/config": "7.3.0",
"@prisma/dev": "0.20.0",
@@ -11477,15 +11448,6 @@
"prosemirror-transform": "^1.0.0"
}
},
- "node_modules/prosemirror-collab": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz",
- "integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==",
- "license": "MIT",
- "dependencies": {
- "prosemirror-state": "^1.0.0"
- }
- },
"node_modules/prosemirror-commands": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz",
@@ -11532,16 +11494,6 @@
"rope-sequence": "^1.3.0"
}
},
- "node_modules/prosemirror-inputrules": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.5.1.tgz",
- "integrity": "sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==",
- "license": "MIT",
- "dependencies": {
- "prosemirror-state": "^1.0.0",
- "prosemirror-transform": "^1.0.0"
- }
- },
"node_modules/prosemirror-keymap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz",
@@ -11552,47 +11504,16 @@
"w3c-keyname": "^2.2.0"
}
},
- "node_modules/prosemirror-markdown": {
- "version": "1.13.4",
- "resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.4.tgz",
- "integrity": "sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw==",
- "license": "MIT",
- "dependencies": {
- "@types/markdown-it": "^14.0.0",
- "markdown-it": "^14.0.0",
- "prosemirror-model": "^1.25.0"
- }
- },
- "node_modules/prosemirror-menu": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.3.0.tgz",
- "integrity": "sha512-TImyPXCHPcDsSka2/lwJ6WjTASr4re/qWq1yoTTuLOqfXucwF6VcRa2LWCkM/EyTD1UO3CUwiH8qURJoWJRxwg==",
- "license": "MIT",
- "dependencies": {
- "crelt": "^1.0.0",
- "prosemirror-commands": "^1.0.0",
- "prosemirror-history": "^1.0.0",
- "prosemirror-state": "^1.0.0"
- }
- },
"node_modules/prosemirror-model": {
"version": "1.25.4",
"resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.4.tgz",
"integrity": "sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"orderedmap": "^2.0.0"
}
},
- "node_modules/prosemirror-schema-basic": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.4.tgz",
- "integrity": "sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==",
- "license": "MIT",
- "dependencies": {
- "prosemirror-model": "^1.25.0"
- }
- },
"node_modules/prosemirror-schema-list": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz",
@@ -11609,6 +11530,7 @@
"resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz",
"integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"prosemirror-model": "^1.0.0",
"prosemirror-transform": "^1.0.0",
@@ -11628,33 +11550,6 @@
"prosemirror-view": "^1.41.4"
}
},
- "node_modules/prosemirror-trailing-node": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz",
- "integrity": "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==",
- "license": "MIT",
- "dependencies": {
- "@remirror/core-constants": "3.0.0",
- "escape-string-regexp": "^4.0.0"
- },
- "peerDependencies": {
- "prosemirror-model": "^1.22.1",
- "prosemirror-state": "^1.4.2",
- "prosemirror-view": "^1.33.8"
- }
- },
- "node_modules/prosemirror-trailing-node/node_modules/escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "license": "MIT",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/prosemirror-transform": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.11.0.tgz",
@@ -11669,6 +11564,7 @@
"resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.7.tgz",
"integrity": "sha512-jUwKNCEIGiqdvhlS91/2QAg21e4dfU5bH2iwmSDQeosXJgKF7smG0YSplOWK0cjSNgIqXe7VXqo7EIfUFJdt3w==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"prosemirror-model": "^1.20.0",
"prosemirror-state": "^1.0.0",
@@ -11685,15 +11581,6 @@
"once": "^1.3.1"
}
},
- "node_modules/punycode.js": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
- "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/pure-rand": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
@@ -12029,6 +11916,7 @@
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.0.tgz",
"integrity": "sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/estree": "1.0.8"
},
@@ -12315,8 +12203,7 @@
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
"devOptional": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/scule": {
"version": "1.3.0",
@@ -12884,6 +12771,7 @@
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.5.0.tgz",
"integrity": "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==",
"license": "MIT",
+ "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/dcastil"
@@ -12912,7 +12800,8 @@
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz",
"integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/tapable": {
"version": "2.3.2",
@@ -13158,6 +13047,7 @@
"integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
"devOptional": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"esbuild": "~0.27.0",
"get-tsconfig": "^4.7.5"
@@ -13219,12 +13109,6 @@
"node": ">=14.17"
}
},
- "node_modules/uc.micro": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
- "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
- "license": "MIT"
- },
"node_modules/ufo": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz",
@@ -13638,6 +13522,7 @@
"integrity": "sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==",
"devOptional": true,
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"typescript": ">=5"
},
@@ -13760,6 +13645,7 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"esbuild": "^0.27.0",
"fdir": "^6.5.0",
@@ -14115,6 +14001,7 @@
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.31.tgz",
"integrity": "sha512-iV/sU9SzOlmA/0tygSmjkEN6Jbs3nPoIPFhCMLD2STrjgOU8DX7ZtzMhg4ahVwf5Rp9KoFzcXeB1ZrVbLBp5/Q==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@vue/compiler-dom": "3.5.31",
"@vue/compiler-sfc": "3.5.31",
@@ -14157,6 +14044,7 @@
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz",
"integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@vue/devtools-api": "^6.6.4"
},
@@ -14355,6 +14243,7 @@
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
"license": "ISC",
+ "peer": true,
"bin": {
"yaml": "bin.mjs"
},
@@ -14471,6 +14360,7 @@
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
"license": "MIT",
+ "peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
diff --git a/package.json b/package.json
index 03f9c58..2fb442e 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,8 @@
"@nuxt/ui": "4.6.0",
"@prisma/adapter-better-sqlite3": "^7.2.0",
"@prisma/client": "^7.2.0",
+ "@tiptap/extension-task-item": "^3.22.4",
+ "@tiptap/extension-task-list": "^3.22.4",
"@tiptap/extension-text-align": "^3.20.1",
"@types/dompurify": "^3.2.0",
"@types/nodemailer": "^7.0.4",
From 2a590176524389ed16484bd7866b3fa952dbb165 Mon Sep 17 00:00:00 2001
From: Charvisree Koripella
Date: Tue, 28 Apr 2026 02:25:42 -0500
Subject: [PATCH 24/30] Fixed the toolbar and text overlap issue and checkboxes
---
app/components/NotesToolbar.vue | 28 ----------------------------
1 file changed, 28 deletions(-)
diff --git a/app/components/NotesToolbar.vue b/app/components/NotesToolbar.vue
index 1d1c16b..8b1d77a 100644
--- a/app/components/NotesToolbar.vue
+++ b/app/components/NotesToolbar.vue
@@ -78,15 +78,6 @@ const items: EditorToolbarItem[][] = [
\ No newline at end of file
From 8f6eb7e7341dfda98317b81742cbaf7dd43b58bc Mon Sep 17 00:00:00 2001
From: Charvisree Koripella
Date: Tue, 28 Apr 2026 10:51:14 -0500
Subject: [PATCH 25/30] Updated the lockfile for tiptap extensions
---
app/components/Notes.vue | 2 +-
pnpm-lock.yaml | 75 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 76 insertions(+), 1 deletion(-)
diff --git a/app/components/Notes.vue b/app/components/Notes.vue
index 76e2f67..011427e 100644
--- a/app/components/Notes.vue
+++ b/app/components/Notes.vue
@@ -1037,7 +1037,7 @@
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f567a60..d8cbda5 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -38,6 +38,12 @@ importers:
'@prisma/client':
specifier: ^7.2.0
version: 7.5.0(prisma@7.5.0(@types/react@19.2.14)(better-sqlite3@12.8.0)(magicast@0.5.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3)
+ '@tiptap/extension-task-item':
+ specifier: ^3.22.4
+ version: 3.22.5(@tiptap/extension-list@3.20.4(@tiptap/core@3.20.4(@tiptap/pm@3.20.4))(@tiptap/pm@3.20.4))
+ '@tiptap/extension-task-list':
+ specifier: ^3.22.4
+ version: 3.22.5(@tiptap/extension-list@3.20.4(@tiptap/core@3.20.4(@tiptap/pm@3.20.4))(@tiptap/pm@3.20.4))
'@tiptap/extension-text-align':
specifier: ^3.20.1
version: 3.22.2(@tiptap/core@3.20.4(@tiptap/pm@3.20.4))
@@ -848,48 +854,56 @@ packages:
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@oxc-minify/binding-linux-arm64-musl@0.117.0':
resolution: {integrity: sha512-C3zapJconWpl2Y7LR3GkRkH6jxpuV2iVUfkFcHT5Ffn4Zu7l88mZa2dhcfdULZDybN1Phka/P34YUzuskUUrXw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@oxc-minify/binding-linux-ppc64-gnu@0.117.0':
resolution: {integrity: sha512-2T/Bm+3/qTfuNS4gKSzL8qbiYk+ErHW2122CtDx+ilZAzvWcJ8IbqdZIbEWOlwwe03lESTxPwTBLFqVgQU2OeQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@oxc-minify/binding-linux-riscv64-gnu@0.117.0':
resolution: {integrity: sha512-MKLjpldYkeoB4T+yAi4aIAb0waifxUjLcKkCUDmYAY3RqBJTvWK34KtfaKZL0IBMIXfD92CbKkcxQirDUS9Xcg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@oxc-minify/binding-linux-riscv64-musl@0.117.0':
resolution: {integrity: sha512-UFVcbPvKUStry6JffriobBp8BHtjmLLPl4bCY+JMxIn/Q3pykCpZzRwFTcDurG/kY8tm+uSNfKKdRNa5Nh9A7g==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
+ libc: [musl]
'@oxc-minify/binding-linux-s390x-gnu@0.117.0':
resolution: {integrity: sha512-B9GyPQ1NKbvpETVAMyJMfRlD3c6UJ7kiuFUAlx9LTYiQL+YIyT6vpuRlq1zgsXxavZluVrfeJv6x0owV4KDx4Q==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@oxc-minify/binding-linux-x64-gnu@0.117.0':
resolution: {integrity: sha512-fXfhtr+WWBGNy4M5GjAF5vu/lpulR4Me34FjTyaK9nDrTZs7LM595UDsP1wliksqp4hD/KdoqHGmbCrC+6d4vA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@oxc-minify/binding-linux-x64-musl@0.117.0':
resolution: {integrity: sha512-jFBgGbx1oLadb83ntJmy1dWlAHSQanXTS21G4PgkxyONmxZdZ/UMKr7KsADzMuoPsd2YhJHxzRpwJd9U+4BFBw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@oxc-minify/binding-openharmony-arm64@0.117.0':
resolution: {integrity: sha512-nxPd9vx1vYz8IlIMdl9HFdOK/ood1H5hzbSFsyO8JU55tkcJoBL8TLCbuFf9pHpOy27l2gcPyV6z3p4eAcTH5Q==}
@@ -967,48 +981,56 @@ packages:
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@oxc-parser/binding-linux-arm64-musl@0.117.0':
resolution: {integrity: sha512-QagKTDF4lrz8bCXbUi39Uq5xs7C7itAseKm51f33U+Dyar9eJY/zGKqfME9mKLOiahX7Fc1J3xMWVS0AdDXLPg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@oxc-parser/binding-linux-ppc64-gnu@0.117.0':
resolution: {integrity: sha512-RPddpcE/0xxWaommWy0c5i/JdrXcXAkxBS2GOrAUh5LKmyCh03hpJedOAWszG4ADsKQwoUQQ1/tZVGRhZIWtKA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@oxc-parser/binding-linux-riscv64-gnu@0.117.0':
resolution: {integrity: sha512-ur/WVZF9FSOiZGxyP+nfxZzuv6r5OJDYoVxJnUR7fM/hhXLh4V/be6rjbzm9KLCDBRwYCEKJtt+XXNccwd06IA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@oxc-parser/binding-linux-riscv64-musl@0.117.0':
resolution: {integrity: sha512-ujGcAx8xAMvhy7X5sBFi3GXML1EtyORuJZ5z2T6UV3U416WgDX/4OCi3GnoteeenvxIf6JgP45B+YTHpt71vpA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
+ libc: [musl]
'@oxc-parser/binding-linux-s390x-gnu@0.117.0':
resolution: {integrity: sha512-hbsfKjUwRjcMZZvvmpZSc+qS0bHcHRu8aV/I3Ikn9BzOA0ZAgUE7ctPtce5zCU7bM8dnTLi4sJ1Pi9YHdx6Urw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@oxc-parser/binding-linux-x64-gnu@0.117.0':
resolution: {integrity: sha512-1QrTrf8rige7UPJrYuDKJLQOuJlgkt+nRSJLBMHWNm9TdivzP48HaK3f4q18EjNlglKtn03lgjMu4fryDm8X4A==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@oxc-parser/binding-linux-x64-musl@0.117.0':
resolution: {integrity: sha512-gRvK6HPzF5ITRL68fqb2WYYs/hGviPIbkV84HWCgiJX+LkaOpp+HIHQl3zVZdyKHwopXToTbXbtx/oFjDjl8pg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@oxc-parser/binding-openharmony-arm64@0.117.0':
resolution: {integrity: sha512-QPJvFbnnDZZY7xc+xpbIBWLThcGBakwaYA9vKV8b3+oS5MGfAZUoTFJcix5+Zg2Ri46sOfrUim6Y6jsKNcssAQ==}
@@ -1089,48 +1111,56 @@ packages:
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@oxc-transform/binding-linux-arm64-musl@0.117.0':
resolution: {integrity: sha512-ykxpPQp0eAcSmhy0Y3qKvdanHY4d8THPonDfmCoktUXb6r0X6qnjpJB3V+taN1wevW55bOEZd97kxtjTKjqhmg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@oxc-transform/binding-linux-ppc64-gnu@0.117.0':
resolution: {integrity: sha512-Rvspti4Kr7eq6zSrURK5WjscfWQPvmy/KjJZV45neRKW8RLonE3r9+NgrwSLGoHvQ3F24fbqlkplox1RtlhH5A==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@oxc-transform/binding-linux-riscv64-gnu@0.117.0':
resolution: {integrity: sha512-Dr2ZW9ZZ4l1eQ5JUEUY3smBh4JFPCPuybWaDZTLn3ADZjyd8ZtNXEjeMT8rQbbhbgSL9hEgbwaqraole3FNThQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@oxc-transform/binding-linux-riscv64-musl@0.117.0':
resolution: {integrity: sha512-oD1Bnes1bIC3LVBSrWEoSUBj6fvatESPwAVWfJVGVQlqWuOs/ZBn1e4Nmbipo3KGPHK7DJY75r/j7CQCxhrOFQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
+ libc: [musl]
'@oxc-transform/binding-linux-s390x-gnu@0.117.0':
resolution: {integrity: sha512-qT//IAPLvse844t99Kff5j055qEbXfwzWgvCMb0FyjisnB8foy25iHZxZIocNBe6qwrCYWUP1M8rNrB/WyfS1Q==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@oxc-transform/binding-linux-x64-gnu@0.117.0':
resolution: {integrity: sha512-2YEO5X+KgNzFqRVO5dAkhjcI5gwxus4NSWVl/+cs2sI6P0MNPjqE3VWPawl4RTC11LvetiiZdHcujUCPM8aaUw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@oxc-transform/binding-linux-x64-musl@0.117.0':
resolution: {integrity: sha512-3wqWbTSaIFZvDr1aqmTul4cg8PRWYh6VC52E8bLI7ytgS/BwJLW+sDUU2YaGIds4sAf/1yKeJRmudRCDPW9INg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@oxc-transform/binding-openharmony-arm64@0.117.0':
resolution: {integrity: sha512-Ebxx6NPqhzlrjvx4+PdSqbOq+li0f7X59XtJljDghkbJsbnkHvhLmPR09ifHt5X32UlZN63ekjwcg/nbmHLLlA==}
@@ -1190,36 +1220,42 @@ packages:
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
+ libc: [glibc]
'@parcel/watcher-linux-arm-musl@2.5.6':
resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==}
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
+ libc: [musl]
'@parcel/watcher-linux-arm64-glibc@2.5.6':
resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@parcel/watcher-linux-arm64-musl@2.5.6':
resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@parcel/watcher-linux-x64-glibc@2.5.6':
resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@parcel/watcher-linux-x64-musl@2.5.6':
resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@parcel/watcher-wasm@2.5.6':
resolution: {integrity: sha512-byAiBZ1t3tXQvc8dMD/eoyE7lTXYorhn+6uVW5AC+JGI1KtJC/LvDche5cfUE+qiefH+Ybq0bUCJU0aB1cSHUA==}
@@ -1439,66 +1475,79 @@ packages:
resolution: {integrity: sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==}
cpu: [arm]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.60.0':
resolution: {integrity: sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==}
cpu: [arm]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.60.0':
resolution: {integrity: sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.60.0':
resolution: {integrity: sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-loong64-gnu@4.60.0':
resolution: {integrity: sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==}
cpu: [loong64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-loong64-musl@4.60.0':
resolution: {integrity: sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==}
cpu: [loong64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-ppc64-gnu@4.60.0':
resolution: {integrity: sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-ppc64-musl@4.60.0':
resolution: {integrity: sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==}
cpu: [ppc64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-riscv64-gnu@4.60.0':
resolution: {integrity: sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.60.0':
resolution: {integrity: sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==}
cpu: [riscv64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.60.0':
resolution: {integrity: sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.60.0':
resolution: {integrity: sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.60.0':
resolution: {integrity: sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-openbsd-x64@4.60.0':
resolution: {integrity: sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==}
@@ -1585,24 +1634,28 @@ packages:
engines: {node: '>= 20'}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@tailwindcss/oxide-linux-arm64-musl@4.2.2':
resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==}
engines: {node: '>= 20'}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@tailwindcss/oxide-linux-x64-gnu@4.2.2':
resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==}
engines: {node: '>= 20'}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@tailwindcss/oxide-linux-x64-musl@4.2.2':
resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==}
engines: {node: '>= 20'}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@tailwindcss/oxide-wasm32-wasi@4.2.2':
resolution: {integrity: sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==}
@@ -1823,6 +1876,16 @@ packages:
peerDependencies:
'@tiptap/core': ^3.20.4
+ '@tiptap/extension-task-item@3.22.5':
+ resolution: {integrity: sha512-OVJKiq67lU+RiC6slIhhgTJBlP/Vads6MZ7Ld5wxzCtWMdGKDuzQ1dgF7vrMEs7mhSeSH3phNcIdQ5ypYftZ9w==}
+ peerDependencies:
+ '@tiptap/extension-list': 3.22.5
+
+ '@tiptap/extension-task-list@3.22.5':
+ resolution: {integrity: sha512-SfZeJSALtFODs0i3fml1TSi4vQ4Uopu0p/LndK+mX5FGNBtNmWiy7Wr5cH03ANfzj8c2EzfGIyH+F2/V0HLK9g==}
+ peerDependencies:
+ '@tiptap/extension-list': 3.22.5
+
'@tiptap/extension-text-align@3.22.2':
resolution: {integrity: sha512-pgqyXzVHo4WmDhK26rDwhK2lxQwnjl/9DP816C2k3To/fZRK1eW7q0pSAYteHWmKkaYAxwj/0UvCU0nXKlPujw==}
peerDependencies:
@@ -3229,24 +3292,28 @@ packages:
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
lightningcss-linux-arm64-musl@1.32.0:
resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
+ libc: [musl]
lightningcss-linux-x64-gnu@1.32.0:
resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
+ libc: [glibc]
lightningcss-linux-x64-musl@1.32.0:
resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
+ libc: [musl]
lightningcss-win32-arm64-msvc@1.32.0:
resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
@@ -6702,6 +6769,14 @@ snapshots:
dependencies:
'@tiptap/core': 3.20.4(@tiptap/pm@3.20.4)
+ '@tiptap/extension-task-item@3.22.5(@tiptap/extension-list@3.20.4(@tiptap/core@3.20.4(@tiptap/pm@3.20.4))(@tiptap/pm@3.20.4))':
+ dependencies:
+ '@tiptap/extension-list': 3.20.4(@tiptap/core@3.20.4(@tiptap/pm@3.20.4))(@tiptap/pm@3.20.4)
+
+ '@tiptap/extension-task-list@3.22.5(@tiptap/extension-list@3.20.4(@tiptap/core@3.20.4(@tiptap/pm@3.20.4))(@tiptap/pm@3.20.4))':
+ dependencies:
+ '@tiptap/extension-list': 3.20.4(@tiptap/core@3.20.4(@tiptap/pm@3.20.4))(@tiptap/pm@3.20.4)
+
'@tiptap/extension-text-align@3.22.2(@tiptap/core@3.20.4(@tiptap/pm@3.20.4))':
dependencies:
'@tiptap/core': 3.20.4(@tiptap/pm@3.20.4)
From 19ddb49f5a43c2bfd8de3142371ad4d0fcf85382 Mon Sep 17 00:00:00 2001
From: swaminathanR04
Date: Tue, 28 Apr 2026 03:11:37 -0500
Subject: [PATCH 26/30] Added ability to filter clients list by assigned
clinicians (allows multiple selections of clinicians)
---
app/pages/clients/index.vue | 710 +++++++++++++++++--------------
server/api/clients/counts.get.ts | 16 +-
server/api/clients/index.get.ts | 38 +-
3 files changed, 426 insertions(+), 338 deletions(-)
diff --git a/app/pages/clients/index.vue b/app/pages/clients/index.vue
index 00afe37..ac4d720 100644
--- a/app/pages/clients/index.vue
+++ b/app/pages/clients/index.vue
@@ -1,348 +1,380 @@
@@ -379,28 +411,46 @@
Client list
-
-
+
+
+ Assigned clinician
+
+
+
+
+
- {{ tab.label }} ({{ tab.count }})
-
-
+
+ {{ tab.label }} ({{ tab.count }})
+
+
+
{
const user = requireStaff(event)
const isClinicianViewer = event.context.isClinician === true && !event.context.isAdmin
+ const isAdminViewer = event.context.isAdmin === true
+ const query = getQuery(event)
+ const clinicianUserIds =
+ isAdminViewer && typeof query.clinicianUserId === 'string'
+ ? query.clinicianUserId
+ .split(',')
+ .map((value) => value.trim())
+ .filter(Boolean)
+ : []
+ const hasClinicianUserIdFilter = clinicianUserIds.length > 0
const users = await prisma.user.findMany({
where: {
role: 'CLIENT',
...(isClinicianViewer
? { client: { clinicianUserId: user.id } }
- : {}),
+ : hasClinicianUserIdFilter
+ ? { client: { clinicianUserId: { in: clinicianUserIds } } }
+ : {}),
},
select: {
email: true,
diff --git a/server/api/clients/index.get.ts b/server/api/clients/index.get.ts
index e5d36a4..d4db92e 100644
--- a/server/api/clients/index.get.ts
+++ b/server/api/clients/index.get.ts
@@ -20,9 +20,18 @@ import type { ClientStatus } from '../../../prisma/generated/client'
export default defineEventHandler(async (event) => {
const user = requireStaff(event)
const isClinicianViewer = event.context.isClinician === true && !event.context.isAdmin
+ const isAdminViewer = event.context.isAdmin === true
const query = getQuery(event)
const statusFilter = query.status as string | undefined
+ const clinicianUserIds =
+ isAdminViewer && typeof query.clinicianUserId === 'string'
+ ? query.clinicianUserId
+ .split(',')
+ .map((value) => value.trim())
+ .filter(Boolean)
+ : []
+ const hasClinicianUserIdFilter = clinicianUserIds.length > 0
const hasStatusFilter = Boolean(statusFilter && isClientStatusLabel(statusFilter))
const dbStatusFilter = toDbClientStatus(statusFilter)
@@ -39,14 +48,31 @@ export default defineEventHandler(async (event) => {
}
if (hasStatusFilter) clientFilter.status = dbStatusFilter as ClientStatus
where = { ...where, client: clientFilter }
- } else if (hasStatusFilter) {
- if (dbStatusFilter === 'INCOMPLETE') {
- where = {
- ...where,
- OR: [{ client: null }, { client: { status: 'INCOMPLETE' as ClientStatus } }],
+ } else {
+ const adminClientFilter: {
+ clinicianUserId?: string | { in: string[] }
+ status?: ClientStatus
+ } = {}
+ if (hasClinicianUserIdFilter) adminClientFilter.clinicianUserId = { in: clinicianUserIds }
+
+ if (hasStatusFilter) {
+ if (dbStatusFilter === 'INCOMPLETE') {
+ where = {
+ ...where,
+ OR: hasClinicianUserIdFilter
+ ? [{ client: { ...adminClientFilter, status: 'INCOMPLETE' as ClientStatus } }]
+ : [{ client: null }, { client: { status: 'INCOMPLETE' as ClientStatus } }],
+ }
+ } else {
+ where = {
+ ...where,
+ client: { ...adminClientFilter, status: dbStatusFilter as ClientStatus },
+ }
}
} else {
- where = { ...where, client: { status: dbStatusFilter as ClientStatus } }
+ if (hasClinicianUserIdFilter) {
+ where = { ...where, client: adminClientFilter }
+ }
}
}
From 74ec157110e28f6918456b58ba7f876e0a90ed6f Mon Sep 17 00:00:00 2001
From: swaminathanR04
Date: Tue, 28 Apr 2026 03:44:20 -0500
Subject: [PATCH 27/30] Added ability for admins to filter calandar events by
assigned clinicians and clients. Clinicians can also filter calendar events
by their clients.
---
app/pages/calendar.vue | 241 ++++++++++++++++++++-------
server/api/appointments/index.get.ts | 75 +++++++--
2 files changed, 243 insertions(+), 73 deletions(-)
diff --git a/app/pages/calendar.vue b/app/pages/calendar.vue
index 629319b..66c1241 100644
--- a/app/pages/calendar.vue
+++ b/app/pages/calendar.vue
@@ -9,6 +9,7 @@
const isMobile = ref(process.client && window.innerWidth < 768)
const calendarRef = ref()
+ const datePickerRef = ref(null)
const session = authClient.useSession()
const currentUser = computed(
() =>
@@ -32,7 +33,79 @@
{ immediate: true }
)
const toast = useToast()
- const clients = ref([])
+ const isAdminViewer = computed(() => adminData.value?.isAdmin === true)
+
+ type ClinicianOption = {
+ id: string
+ name: string
+ email: string
+ }
+
+ type CalendarClient = {
+ id: string
+ name: string
+ email: string
+ status: string
+ }
+
+ type AppointmentResponse = {
+ id: string
+ clientId: string
+ title: string
+ sessionName: string
+ sessionNumber: number
+ start: string
+ end: string
+ clientName: string
+ description: string | null
+ status: string
+ videoProvider: string | null
+ videoJoinUrl: string | null
+ assignedClinicianName: string | null
+ }
+
+ type SelectedCalendarEvent = {
+ id: string
+ title: string
+ sessionName: string
+ sessionNumber: number | null
+ clientId: string
+ start: Date
+ end: Date
+ clientName: string
+ description: string | null
+ status: string
+ videoProvider: string | null
+ videoJoinUrl: string | null
+ assignedClinicianName: string | null
+ }
+
+ const { data: clinicians } = await useFetch('/api/clinicians', {
+ getCachedData: () => undefined,
+ })
+ const clinicianFilter = ref([])
+ const clientFilter = ref([])
+ const clinicianFilterItems = computed(() =>
+ (clinicians.value ?? []).map((clinician) => ({
+ label: clinician.name ? `${clinician.name} (${clinician.email})` : clinician.email,
+ value: clinician.id,
+ }))
+ )
+ const clientOptionsQueryParams = computed(() => {
+ const params: Record = {}
+ if (isAdminViewer.value && clinicianFilter.value.length > 0) {
+ params.clinicianUserId = clinicianFilter.value.join(',')
+ }
+ return params
+ })
+ const calendarQueryParams = computed(() => {
+ const params = { ...clientOptionsQueryParams.value }
+ if (clientFilter.value.length > 0) {
+ params.clientId = clientFilter.value.join(',')
+ }
+ return params
+ })
+ const clients = ref([])
const events = ref([])
const isAdmin = computed(() => adminData.value?.isStaff ?? false)
const clientColors = [
@@ -49,23 +122,9 @@
let touchEndX = 0
async function loadEvents() {
try {
- const data = await $fetch<
- {
- id: string
- clientId: string
- title: string
- sessionName: string
- sessionNumber: number
- start: string
- end: string
- clientName: string
- description: string | null
- status: string
- videoProvider: string | null
- videoJoinUrl: string | null
- }[]
- >('/api/appointments', {
+ const data = await $fetch('/api/appointments', {
credentials: 'include',
+ query: calendarQueryParams.value,
})
events.value = data.map((e) => ({
@@ -82,6 +141,7 @@
status: e.status,
videoProvider: e.videoProvider,
videoJoinUrl: e.videoJoinUrl,
+ assignedClinicianName: e.assignedClinicianName,
},
}))
} catch (err) {
@@ -97,8 +157,9 @@
}
try {
- const data = await $fetch('/api/clients', {
+ const data = await $fetch('/api/clients', {
credentials: 'include',
+ query: clientOptionsQueryParams.value,
})
console.log('CLIENTS:', data)
@@ -123,24 +184,33 @@
}
function goToDate(event: any) {
- const calendarApi = calendarRef.value.getApi()
+ const calendarApi = calendarRef.value?.getApi?.()
+ if (!calendarApi) return
calendarApi.gotoDate(event.target.value)
}
function next() {
- calendarRef.value.getApi().next()
+ const calendarApi = calendarRef.value?.getApi?.()
+ if (!calendarApi) return
+ calendarApi.next()
}
function prev() {
- calendarRef.value.getApi().prev()
+ const calendarApi = calendarRef.value?.getApi?.()
+ if (!calendarApi) return
+ calendarApi.prev()
}
function handleTouchStart(e: TouchEvent) {
- touchStartX = e.changedTouches[0].screenX
+ const touch = e.changedTouches[0]
+ if (!touch) return
+ touchStartX = touch.screenX
}
function handleTouchEnd(e: TouchEvent) {
- touchEndX = e.changedTouches[0].screenX
+ const touch = e.changedTouches[0]
+ if (!touch) return
+ touchEndX = touch.screenX
handleSwipe()
}
@@ -160,11 +230,14 @@
}
function today() {
- calendarRef.value.getApi().today()
+ const calendarApi = calendarRef.value?.getApi?.()
+ if (!calendarApi) return
+ calendarApi.today()
}
function changeView(view: string) {
- const calendar = calendarRef.value.getApi()
+ const calendar = calendarRef.value?.getApi?.()
+ if (!calendar) return
const mobile = window.innerWidth < 768
if (view === 'week') {
@@ -218,8 +291,18 @@
}
})
+ watch(calendarQueryParams, async () => {
+ if (!currentUser.value?.id) return
+ await syncCalendarData()
+ })
+
+ watch(clients, (availableClients) => {
+ const allowedClientIds = new Set(availableClients.map((client) => client.id))
+ clientFilter.value = clientFilter.value.filter((id) => allowedClientIds.has(id))
+ })
+
const isViewModalOpen = ref(false)
- const selectedEvent = ref(null)
+ const selectedEvent = ref(null)
const isEditMode = ref(false)
const isDeleteConfirming = ref(false)
const mobileView = ref('week')
@@ -287,7 +370,7 @@
allDaySlot: false,
slotEventOverlap: true,
- datesSet(info) {
+ datesSet(info: any) {
const view = info.view.type
if (view.includes('Day')) mobileView.value = 'day'
@@ -295,7 +378,7 @@
if (view.includes('Month')) mobileView.value = 'month'
},
- dayHeaderDidMount(info) {
+ dayHeaderDidMount(info: any) {
if (info.el) {
info.el.style.cursor = 'pointer'
@@ -305,7 +388,7 @@
const events = section.querySelectorAll('.fc-list-event')
- events.forEach((e) => {
+ events.forEach((e: Element) => {
e.classList.toggle('hidden')
})
}
@@ -314,7 +397,7 @@
initialView: isMobile.value ? 'listWeek' : 'dayGridMonth',
- headerToolbar: false,
+ headerToolbar: false as const,
// listDayFormat: {
// weekday: 'long',
// day: 'numeric',
@@ -359,6 +442,7 @@
clientId: ext.clientId ?? null,
clientName: clientName, // Make sure clientName is included
id: info.event.id,
+ clientId: ext.clientId,
title: info.event.title,
sessionName: ext.sessionName || info.event.title,
sessionNumber: ext.sessionNumber ?? null,
@@ -368,6 +452,7 @@
status: ext.status,
videoProvider: ext.videoProvider ?? null,
videoJoinUrl: ext.videoJoinUrl ?? null,
+ assignedClinicianName: ext.assignedClinicianName ?? null,
}
console.log('selectedEvent after click:', selectedEvent.value)
@@ -376,18 +461,18 @@
}
function enterEditMode() {
+ const event = selectedEvent.value
+ if (!event) return
isEditMode.value = true
- editForm.description = selectedEvent.value.description || ''
- const d = selectedEvent.value.start
+ editForm.description = event.description || ''
+ const d = event.start
editForm.date = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
- editForm.startTime = selectedEvent.value.start.toTimeString().slice(0, 5)
- editForm.endTime = selectedEvent.value.end.toTimeString().slice(0, 5)
- editForm.includeVideo = Boolean(
- selectedEvent.value.videoJoinUrl || selectedEvent.value.videoProvider
- )
- editForm.videoJoinUrl = selectedEvent.value.videoJoinUrl || ''
+ editForm.startTime = event.start.toTimeString().slice(0, 5)
+ editForm.endTime = event.end.toTimeString().slice(0, 5)
+ editForm.includeVideo = Boolean(event.videoJoinUrl || event.videoProvider)
+ editForm.videoJoinUrl = event.videoJoinUrl || ''
editForm.videoProvider = editForm.includeVideo
- ? (selectedEvent.value.videoProvider as typeof editForm.videoProvider) || 'OTHER'
+ ? (event.videoProvider as typeof editForm.videoProvider) || 'OTHER'
: ''
editTimeRangeError.value = ''
editModalError.value = ''
@@ -401,13 +486,20 @@
async function saveEdit() {
editModalError.value = ''
+ const event = selectedEvent.value
+ if (!event) return
if (editForm.includeVideo && !editForm.videoJoinUrl?.trim()) {
setEditModalError('Add a video link or uncheck Video.')
return
}
- editTimeRangeError.value = getTimeRangeError(editForm.date, editForm.startTime, editForm.endTime, {
- allowPastStart: true,
- })
+ editTimeRangeError.value = getTimeRangeError(
+ editForm.date,
+ editForm.startTime,
+ editForm.endTime,
+ {
+ allowPastStart: true,
+ }
+ )
if (editTimeRangeError.value) {
toast.add({
title: 'Invalid date/time range',
@@ -417,10 +509,10 @@
return
}
try {
- await $fetch(`/api/appointments/${selectedEvent.value.id}`, {
+ await $fetch(`/api/appointments/${event.id}`, {
method: 'PUT',
body: {
- id: selectedEvent.value.id,
+ id: event.id,
description: editForm.description,
date: editForm.date,
startTime: editForm.startTime,
@@ -455,8 +547,10 @@
}
async function deleteEvent() {
+ const event = selectedEvent.value
+ if (!event) return
try {
- await $fetch(`/api/appointments/${selectedEvent.value.id}`, {
+ await $fetch(`/api/appointments/${event.id}`, {
method: 'DELETE',
credentials: 'include',
})
@@ -519,8 +613,8 @@
const clientOptions = computed(() =>
clients.value
- .filter((c) => c.status !== 'Archived')
- .map((c) => ({
+ .filter((c: CalendarClient) => c.status !== 'Archived')
+ .map((c: CalendarClient) => ({
label: c.name || c.email,
value: c.id,
}))
@@ -617,7 +711,9 @@
() => [editForm.date, editForm.startTime, editForm.endTime] as const,
([date, startTime, endTime]) => {
if (!isEditMode.value) return
- editTimeRangeError.value = getTimeRangeError(date, startTime, endTime, { allowPastStart: true })
+ editTimeRangeError.value = getTimeRangeError(date, startTime, endTime, {
+ allowPastStart: true,
+ })
}
)
@@ -637,9 +733,9 @@
-
+
@@ -659,8 +755,27 @@
-
-
+
@@ -701,7 +816,9 @@
-
+
Session name will be auto-generated as Firstname_Lastname_## .
@@ -790,7 +907,12 @@
Client: {{ selectedClientName }}
-
Session Name: {{ selectedEvent?.sessionName || selectedEvent?.title }}
+
+ Assigned Clinician: {{ selectedEvent.assignedClinicianName }}
+
+
+ Session Name: {{ selectedEvent?.sessionName || selectedEvent?.title }}
+
Date: {{ selectedEvent?.start?.toLocaleDateString() }}
Time:
@@ -854,7 +976,9 @@
>
{{ editModalError }}
-
+
Session name is auto-generated and cannot be edited.
@@ -943,7 +1067,12 @@
Cancel
-
+
Save
diff --git a/server/api/appointments/index.get.ts b/server/api/appointments/index.get.ts
index 868803a..a5916ee 100644
--- a/server/api/appointments/index.get.ts
+++ b/server/api/appointments/index.get.ts
@@ -1,7 +1,27 @@
import { requireUser } from '../../utils/guard'
-import { defineEventHandler, getHeaders, createError } from 'h3'
+import { defineEventHandler, getHeaders, createError, getQuery } from 'h3'
import { isAppointmentTableMissingError } from '../../utils/is-appointment-table-error'
import { prisma } from '../../utils/prisma'
+import type { Prisma } from '../../../prisma/generated/client'
+
+const appointmentInclude = {
+ client: {
+ select: {
+ name: true,
+ client: {
+ select: {
+ clinician: {
+ select: { name: true, email: true },
+ },
+ },
+ },
+ },
+ },
+} satisfies Prisma.AppointmentInclude
+
+type AppointmentWithClient = Prisma.AppointmentGetPayload<{
+ include: typeof appointmentInclude
+}>
export default defineEventHandler(async (event) => {
const headers = new Headers()
@@ -26,41 +46,60 @@ export default defineEventHandler(async (event) => {
throw createError({ statusCode: 403 })
}
- let appointments: Awaited
> = []
+ const query = getQuery(event)
+ const clinicianUserIds =
+ event.context.isAdmin && typeof query.clinicianUserId === 'string'
+ ? query.clinicianUserId
+ .split(',')
+ .map((value) => value.trim())
+ .filter(Boolean)
+ : []
+ const hasClinicianUserIdFilter = clinicianUserIds.length > 0
+ const clientIds =
+ typeof query.clientId === 'string'
+ ? query.clientId
+ .split(',')
+ .map((value) => value.trim())
+ .filter(Boolean)
+ : []
+ const hasClientIdFilter = clientIds.length > 0
+
+ let appointments: AppointmentWithClient[] = []
try {
if (event.context.isAdmin) {
appointments = await prisma.appointment.findMany({
- include: {
- client: {
- select: { name: true },
- },
+ where: {
+ ...(hasClientIdFilter ? { clientId: { in: clientIds } } : {}),
+ ...(hasClinicianUserIdFilter
+ ? {
+ client: {
+ client: {
+ clinicianUserId: { in: clinicianUserIds },
+ },
+ },
+ }
+ : {}),
},
+ include: appointmentInclude,
})
} else if (event.context.isClinician) {
// CLINICIAN → only appointments whose client is assigned to them
appointments = await prisma.appointment.findMany({
where: {
+ ...(hasClientIdFilter ? { clientId: { in: clientIds } } : {}),
client: {
client: { clinicianUserId: userId },
},
},
- include: {
- client: {
- select: { name: true },
- },
- },
+ include: appointmentInclude,
})
} else {
appointments = await prisma.appointment.findMany({
where: {
- clientId: userId,
- },
- include: {
- client: {
- select: { name: true },
- },
+ clientId: hasClientIdFilter ? { in: clientIds } : userId,
},
+ include: appointmentInclude,
})
}
} catch (e: unknown) {
@@ -84,5 +123,7 @@ export default defineEventHandler(async (event) => {
status: a.status,
videoProvider: a.videoProvider,
videoJoinUrl: a.videoJoinUrl,
+ assignedClinicianName:
+ a.client.client?.clinician?.name ?? a.client.client?.clinician?.email ?? null,
}))
})
From 9c3b867854a2545c2e3debabe16efb45189542cd Mon Sep 17 00:00:00 2001
From: swaminathanR04
Date: Tue, 28 Apr 2026 12:36:17 -0500
Subject: [PATCH 28/30] Resolve calendar filter merge integration on stage
---
app/pages/calendar.vue | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/app/pages/calendar.vue b/app/pages/calendar.vue
index 66c1241..f497898 100644
--- a/app/pages/calendar.vue
+++ b/app/pages/calendar.vue
@@ -439,7 +439,6 @@
const ext = info.event.extendedProps || info.event._def?.extendedProps || {}
selectedEvent.value = {
...ext,
- clientId: ext.clientId ?? null,
clientName: clientName, // Make sure clientName is included
id: info.event.id,
clientId: ext.clientId,
@@ -954,7 +953,7 @@
:label="
selectedEvent?.videoProvider === 'GOOGLE_MEET'
? 'Join Google Meet'
- : `Join ${VIDEO_PROVIDER_LABEL[selectedEvent?.videoProvider] ?? 'meeting'}`
+ : `Join ${selectedEvent?.videoProvider ? VIDEO_PROVIDER_LABEL[selectedEvent.videoProvider] ?? 'meeting' : 'meeting'}`
"
/>
From b315d262fd2da59e9bee6a980a70cbe6eb68bac0 Mon Sep 17 00:00:00 2001
From: swaminathanR04
Date: Tue, 28 Apr 2026 13:13:54 -0500
Subject: [PATCH 29/30] Added Carl to seed.ts as a clinician.
Co-authored-by: Copilot
---
prisma/seed.ts | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/prisma/seed.ts b/prisma/seed.ts
index 142f27f..df323a9 100644
--- a/prisma/seed.ts
+++ b/prisma/seed.ts
@@ -245,6 +245,19 @@ async function main() {
console.log(`Seeded Admin: ${admin.email}`)
}
+ await prisma.user.upsert({
+ where: { email: 'carl@c.com' },
+ update: { role: 'CLINICIAN', name: 'Carl Karl' },
+ create: {
+ id: 'carl_id',
+ email: 'carl@c.com',
+ name: 'Carl Karl',
+ emailVerified: true,
+ role: 'CLINICIAN',
+ },
+ })
+ console.log('Seeded Clinician: carl@c.com')
+
// Create / Upsert Bob (Client)
const bob = await prisma.user.upsert({
where: { email: 'bob@b.com' },
From cea9824196213fa851738aafd2eb463f131884a8 Mon Sep 17 00:00:00 2001
From: TusharW4ni
Date: Tue, 28 Apr 2026 22:36:52 -0500
Subject: [PATCH 30/30] chore: update package-lock.json after merging main
---
package-lock.json | 65 ++++++++---------------------------------------
1 file changed, 10 insertions(+), 55 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 44880bd..8f4b126 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -94,7 +94,6 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
@@ -468,7 +467,6 @@
"version": "1.4.18",
"resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.4.18.tgz",
"integrity": "sha512-q+awYgC7nkLEBdx2sW0iJjkzgSHlIxGnOpsN1r/O1+a4m7osJNHtfK2mKJSL1I+GfNyIlxJF8WvD/NLuYMpmcg==",
- "peer": true,
"dependencies": {
"@standard-schema/spec": "^1.0.0",
"zod": "^4.3.5"
@@ -498,14 +496,12 @@
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.3.0.tgz",
"integrity": "sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw==",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/@better-fetch/fetch": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.1.21.tgz",
- "integrity": "sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A==",
- "peer": true
+ "integrity": "sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A=="
},
"node_modules/@bomb.sh/tab": {
"version": "0.0.14",
@@ -650,8 +646,7 @@
"resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.3.15.tgz",
"integrity": "sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ==",
"devOptional": true,
- "license": "Apache-2.0",
- "peer": true
+ "license": "Apache-2.0"
},
"node_modules/@electric-sql/pglite-socket": {
"version": "0.0.20",
@@ -1137,7 +1132,6 @@
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz",
"integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@floating-ui/core": "^1.7.5",
"@floating-ui/utils": "^0.2.11"
@@ -1899,7 +1893,6 @@
"resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.4.2.tgz",
"integrity": "sha512-5+IPRNX2CjkBhuWUwz0hBuLqiaJPRoKzQ+SvcdrQDbAyE+VDeFt74VpSFr5/R0ujrK4b+XnSHUJWdS72w6hsog==",
"license": "MIT",
- "peer": true,
"dependencies": {
"c12": "^3.3.3",
"consola": "^3.4.2",
@@ -3714,7 +3707,6 @@
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-7.3.0.tgz",
"integrity": "sha512-FXBIxirqQfdC6b6HnNgxGmU7ydCPEPk7maHMOduJJfnTP+MuOGa15X4omjR/zpPUUpm8ef/mEFQjJudOGkXFcQ==",
"license": "Apache-2.0",
- "peer": true,
"dependencies": {
"@prisma/client-runtime-utils": "7.3.0"
},
@@ -4863,7 +4855,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.22.4.tgz",
"integrity": "sha512-vGIGm/HpqLg8EAAQXQ+koV+/S828OEpzocfWcPOwo1u2QUVf9dQG47Yy6JJ8zFFaJwfv4dBcOXli+7BrJwsxDQ==",
"license": "MIT",
- "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -4960,7 +4951,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/extension-collaboration/-/extension-collaboration-3.20.5.tgz",
"integrity": "sha512-IalIm6BznHds2VzR4+6gMAgi4VXwZAXdYkl28EPZ8/xscBaUn1tCxcTBbCpmN3UhkABaCoJtmmER5TDy+x72Ag==",
"license": "MIT",
- "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -4990,7 +4980,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/extension-drag-handle/-/extension-drag-handle-3.20.5.tgz",
"integrity": "sha512-D2W2fkpmXKRG4i0K0XVfbsTRYQMU9RudQIXBB7HnYZFosyJs3dvsT1cFurDUANKLPCxbI24eiubAKs6b1vzGpA==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@floating-ui/dom": "^1.6.13"
},
@@ -5151,7 +5140,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.22.4.tgz",
"integrity": "sha512-Xe8UFvvHmyp/c/TJsFwlwU9CWACYbBirNsluJ3U1+H8BTu1wqdrT/AXR5uIXeyCl5kiWKgX5q71eHWbYFOrqrg==",
"license": "MIT",
- "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -5207,7 +5195,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/extension-node-range/-/extension-node-range-3.20.5.tgz",
"integrity": "sha512-6CbgZULF+dQ9KTothAORBZAXPdGneWicMWTV3Gyeh9gNySC18QsGQj3D2GxnllpMekmZXydtDbNFSoCiWjKFWQ==",
"license": "MIT",
- "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -5339,7 +5326,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.20.5.tgz",
"integrity": "sha512-c4am6SznqfMnbUNSh4MvufiD7cMLdqL1BArok22uBgSWkS1sB9RVBYe8+x0jrOkk0UPEVlzDHbQ+nU+WmIyS2Q==",
"license": "MIT",
- "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -5371,7 +5357,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.22.4.tgz",
"integrity": "sha512-hj8Qka6WcHRllHUdeSjDnq2XaisUo4KsoGJc1WcFpoa1Yd+OeD861zUMnV7DFVGdZRy45Obht0CUYJpXQ4yA4w==",
"license": "MIT",
- "peer": true,
"dependencies": {
"prosemirror-changeset": "^2.3.0",
"prosemirror-commands": "^1.6.2",
@@ -5432,7 +5417,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-3.20.5.tgz",
"integrity": "sha512-5fqRNgnzYdJ1oDpyLqwrbVsZwvI+5VW/U89LPMvBYM7sFS7Xd0xfyxyAOWcJN4V0zLeTcuElWN3R+IUTLKbU+Q==",
"license": "MIT",
- "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -5447,7 +5431,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/vue-3/-/vue-3-3.20.5.tgz",
"integrity": "sha512-5uUK3RAMNvUetZOv56Kz8nurhxHxMH60GgCCrVFgIBZoTc14u3d3v7EpcA6gNgzogutrR8GxvyFU3iIkj4kkHA==",
"license": "MIT",
- "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -5898,7 +5881,6 @@
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.2.1.tgz",
"integrity": "sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/web-bluetooth": "^0.0.21",
"@vueuse/metadata": "14.2.1",
@@ -6024,7 +6006,6 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
"integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"license": "MIT",
- "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -6359,7 +6340,6 @@
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz",
"integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==",
"license": "Apache-2.0",
- "peer": true,
"peerDependencies": {
"bare-abort-controller": "*"
},
@@ -6583,7 +6563,6 @@
"resolved": "https://registry.npmjs.org/better-call/-/better-call-1.1.8.tgz",
"integrity": "sha512-XMQ2rs6FNXasGNfMjzbyroSwKwYbZ/T3IxruSS6U2MJRsSYh3wYtG3o6H00ZlKZ/C/UPOAD97tqgQJNsxyeTXw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@better-auth/utils": "^0.3.0",
"@better-fetch/fetch": "^1.1.4",
@@ -6729,7 +6708,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -6831,7 +6809,6 @@
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=8"
}
@@ -6949,7 +6926,6 @@
"resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz",
"integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"consola": "^3.2.3"
}
@@ -7700,8 +7676,7 @@
"version": "8.6.0",
"resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz",
"integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/embla-carousel-auto-height": {
"version": "8.6.0",
@@ -8278,7 +8253,6 @@
"resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.1.0.tgz",
"integrity": "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==",
"license": "Apache-2.0",
- "peer": true,
"engines": {
"node": ">=10"
}
@@ -8532,7 +8506,6 @@
"integrity": "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==",
"devOptional": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=16.9.0"
}
@@ -8926,6 +8899,7 @@
"resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz",
"integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==",
"license": "MIT",
+ "peer": true,
"funding": {
"type": "GitHub Sponsors ❤",
"url": "https://github.com/sponsors/dmonad"
@@ -8960,7 +8934,6 @@
"resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz",
"integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==",
"license": "MIT",
- "peer": true,
"funding": {
"url": "https://github.com/sponsors/panva"
}
@@ -9024,7 +8997,6 @@
"resolved": "https://registry.npmjs.org/kysely/-/kysely-0.28.10.tgz",
"integrity": "sha512-ksNxfzIW77OcZ+QWSAPC7yDqUSaIVwkTWnTPNiIy//vifNbwsSgQ57OkkncHxxpcBHM3LRfLAZVEh7kjq5twVA==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=20.0.0"
}
@@ -9086,6 +9058,7 @@
"resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.117.tgz",
"integrity": "sha512-DeXj9X5xDCjgKLU/7RR+/HQEVzuuEUiwldwOGsHK/sfAfELGWEyTcf0x+uOvCvK3O2zPmZePXWL85vtia6GyZw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"isomorphic.js": "^0.2.4"
},
@@ -9795,7 +9768,6 @@
"integrity": "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==",
"devOptional": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"aws-ssl-profiles": "^1.1.1",
"denque": "^2.1.0",
@@ -9852,7 +9824,6 @@
}
],
"license": "MIT",
- "peer": true,
"engines": {
"node": "^20.0.0 || >=22.0.0"
}
@@ -10189,7 +10160,6 @@
"resolved": "https://registry.npmjs.org/nuxt/-/nuxt-4.4.2.tgz",
"integrity": "sha512-iWVFpr/YEqVU/CenqIHMnIkvb2HE/9f+q8oxZ+pj2et+60NljGRClCgnmbvGPdmNFE0F1bEhoBCYfqbDOCim3Q==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@dxup/nuxt": "^0.4.0",
"@nuxt/cli": "^3.34.0",
@@ -10542,7 +10512,6 @@
"resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.117.0.tgz",
"integrity": "sha512-l3cbgK5wUvWDVNWM/JFU77qDdGZK1wudnLsFcrRyNo/bL1CyU8pC25vDhMHikVY29lbK2InTWsX42RxVSutUdQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@oxc-project/types": "^0.117.0"
},
@@ -10742,7 +10711,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -11231,6 +11199,7 @@
"resolved": "https://registry.npmjs.org/preact/-/preact-10.12.1.tgz",
"integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==",
"license": "MIT",
+ "peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
@@ -11268,7 +11237,6 @@
"integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -11377,7 +11345,6 @@
"devOptional": true,
"hasInstallScript": true,
"license": "Apache-2.0",
- "peer": true,
"dependencies": {
"@prisma/config": "7.3.0",
"@prisma/dev": "0.20.0",
@@ -11509,7 +11476,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.4.tgz",
"integrity": "sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==",
"license": "MIT",
- "peer": true,
"dependencies": {
"orderedmap": "^2.0.0"
}
@@ -11530,7 +11496,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz",
"integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==",
"license": "MIT",
- "peer": true,
"dependencies": {
"prosemirror-model": "^1.0.0",
"prosemirror-transform": "^1.0.0",
@@ -11564,7 +11529,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.7.tgz",
"integrity": "sha512-jUwKNCEIGiqdvhlS91/2QAg21e4dfU5bH2iwmSDQeosXJgKF7smG0YSplOWK0cjSNgIqXe7VXqo7EIfUFJdt3w==",
"license": "MIT",
- "peer": true,
"dependencies": {
"prosemirror-model": "^1.20.0",
"prosemirror-state": "^1.0.0",
@@ -11916,7 +11880,6 @@
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.0.tgz",
"integrity": "sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/estree": "1.0.8"
},
@@ -12203,7 +12166,8 @@
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
"devOptional": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/scule": {
"version": "1.3.0",
@@ -12771,7 +12735,6 @@
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.5.0.tgz",
"integrity": "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==",
"license": "MIT",
- "peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/dcastil"
@@ -12800,8 +12763,7 @@
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz",
"integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/tapable": {
"version": "2.3.2",
@@ -13047,7 +13009,6 @@
"integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
"devOptional": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"esbuild": "~0.27.0",
"get-tsconfig": "^4.7.5"
@@ -13522,7 +13483,6 @@
"integrity": "sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==",
"devOptional": true,
"license": "MIT",
- "peer": true,
"peerDependencies": {
"typescript": ">=5"
},
@@ -13645,7 +13605,6 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
"license": "MIT",
- "peer": true,
"dependencies": {
"esbuild": "^0.27.0",
"fdir": "^6.5.0",
@@ -14001,7 +13960,6 @@
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.31.tgz",
"integrity": "sha512-iV/sU9SzOlmA/0tygSmjkEN6Jbs3nPoIPFhCMLD2STrjgOU8DX7ZtzMhg4ahVwf5Rp9KoFzcXeB1ZrVbLBp5/Q==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@vue/compiler-dom": "3.5.31",
"@vue/compiler-sfc": "3.5.31",
@@ -14044,7 +14002,6 @@
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz",
"integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@vue/devtools-api": "^6.6.4"
},
@@ -14243,7 +14200,6 @@
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
"license": "ISC",
- "peer": true,
"bin": {
"yaml": "bin.mjs"
},
@@ -14360,7 +14316,6 @@
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
"license": "MIT",
- "peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}