Skip to content

Conversation

@SebastianSchuetze
Copy link
Contributor

@SebastianSchuetze SebastianSchuetze commented Oct 14, 2025

This pull request refactors media storage path logic across several collections to use a unified, predictable pattern via a shared computeStorage hook. It also improves seed script reliability and consistency, updates documentation, and simplifies ownership enforcement for user profile media. The most important changes are grouped below.

Media Storage Path Refactoring

  • Unified storage path computation for platform, doctor, and user profile media by replacing custom logic in their respective hooks with the shared computeStorage utility, ensuring consistent hashed folder keys and owner scoping. (src/collections/DoctorMedia/hooks/beforeChangeDoctorMedia.ts, src/collections/PlatformContentMedia/hooks/beforeChangePlatformContentMedia.ts, src/collections/UserProfileMedia/index.ts) [1] [2] [3] [4] [5] [6]
  • Removed the old, complex beforeChangeUserProfileMedia hook and replaced it with a declarative set of hooks, including ownership freezing and createdBy stamping, in UserProfileMedia. (src/collections/UserProfileMedia/hooks/beforeChangeUserProfileMedia.ts, src/collections/UserProfileMedia/index.ts) [1] [2] [3]

Documentation Improvements

  • Updated storage integration documentation to describe the new folder structure, naming conventions, and how the shared hook applies these rules for all media types. (docs/integrations/storage.md)

Seed Script Reliability and Consistency

  • Ensured numeric type for uploader IDs in clinic seeding and improved logging for missing city assignments. (src/endpoints/seed/clinics/clinics-seed.ts) [1] [2] [3]
  • Updated doctor seeding to remove profile image/media creation (pending redesign), clarified clinic lookup, and improved logging. (src/endpoints/seed/clinics/doctors-seed.ts) [1] [2]
  • Made specialty assignment in treatment seeding more robust by providing a fallback if the named specialty is missing. (src/endpoints/seed/clinics/treatments-seed.ts) [1] [2] [3]

Demo Seeding Improvements

  • Fixed demo author creation to include a password field for compatibility with server-side validation during demo seeding. (src/endpoints/seed/demo/index.ts) [1] [2] [3]

- Replace direct payload.create calls with upsertByUniqueField(payload, 'posts', 'slug', ...)
  to make seeding idempotent
- Build post data objects first (p1Data, p2Data, p3Data) and upsert them
- Use returned p?.doc.id when linking relatedPosts; preserve disableRevalidate context
- Rename media target key from `filename` to `label`
- Query `platformContentMedia` by the explicit `alt` field (uses `t.label`)
- Set created media `alt` to the label to avoid relying on implicit upload filename values
Copilot AI review requested due to automatic review settings October 14, 2025 20:23
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request introduces deterministic hash-based media storage paths to replace document ID-based keys, ensuring stable and predictable storage paths for media files. The changes also refactor seeding logic to improve reliability and maintainability.

  • Replaced document ID-based storage keys with SHA-1 hash-based deterministic keys for doctor and platform media
  • Updated seeding logic to use numeric uploader IDs and improved error handling with fallbacks
  • Enhanced demo seeding with better media creation helpers and added validation support

Reviewed Changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/hooks/media/computeStorage.ts Added hash-based fallback for storage key generation when document ID unavailable
src/collections/DoctorMedia/hooks/beforeChangeDoctorMedia.ts Replaced document ID with deterministic hash for doctor media storage paths
src/collections/PlatformContentMedia/hooks/beforeChangePlatformContentMedia.ts Implemented hash-based storage path generation for platform content media
src/endpoints/seed/demo/index.ts Updated demo seeding with numeric uploader IDs and createMediaFromURL helper
src/endpoints/seed/clinics/clinics-seed.ts Converted uploader ID to number type for consistency
src/endpoints/seed/clinics/doctors-seed.ts Temporarily disabled doctor media seeding and improved logging
src/endpoints/seed/clinics/treatments-seed.ts Added fallback specialty assignment to prevent undefined values
src/endpoints/seed/posts/posts-seed.ts Refactored to use upsertByUniqueField helper for better idempotency
src/endpoints/seed/posts/post-1.ts Replaced code block with generic text paragraph for clarity

@github-actions
Copy link

github-actions bot commented Oct 14, 2025

Coverage Report for Unit Tests

Status Category Percentage Covered / Total
🟢 Lines 55.49% (🎯 50%) 5169 / 9314
🟢 Statements 55.49% (🎯 50%) 5169 / 9314
🟢 Functions 59.56% (🎯 55%) 165 / 277
🟢 Branches 78.56% (🎯 75%) 568 / 723
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/collections/DoctorMedia/hooks/beforeChangeDoctorMedia.ts 91.83% 57.14% 100% 91.83% 16-17, 38-39
src/collections/PlatformContentMedia/hooks/beforeChangePlatformContentMedia.ts 100% 83.33% 100% 100%
src/collections/UserProfileMedia/index.ts 96.63% 73.52% 100% 96.63% 33-37
src/hooks/media/computeStorage.ts 79.61% 65% 100% 79.61% 89-95, 102-103, 113-123, 126
src/utilities/requestFileUtils.ts 38.88% 50% 100% 38.88% 10-11, 15-18, 22-26
Unchanged Files
src/Footer/Component.tsx 0% 0% 0% 0% 1-115
src/Footer/RowLabel.tsx 0% 100% 100% 0% 3-13
src/Footer/config.ts 100% 100% 0% 100%
src/Footer/hooks/revalidateFooter.ts 25% 100% 0% 25% 6-13
src/Header/Component.client.tsx 0% 100% 100% 0% 2-25
src/Header/Component.tsx 0% 0% 0% 0% 1-11
src/Header/RowLabel.tsx 0% 100% 100% 0% 3-13
src/Header/config.ts 100% 100% 0% 100%
src/Header/Nav/index.tsx 0% 100% 100% 0% 3-30
src/Header/hooks/revalidateHeader.ts 25% 100% 0% 25% 6-13
src/access/anyone.ts 100% 100% 100% 100%
src/access/authenticated.ts 100% 100% 100% 100%
src/access/authenticatedAndAdmin.ts 100% 100% 100% 100%
src/access/authenticatedOrApprovedClinic.ts 100% 100% 100% 100%
src/access/authenticatedOrPublished.ts 100% 100% 100% 100%
src/access/clinicGallery.ts 95% 90.9% 100% 95% 29-30
src/access/fieldAccess.ts 100% 100% 100% 100%
src/access/isClinicBasicUser.ts 100% 100% 100% 100%
src/access/isPatient.ts 100% 100% 100% 100%
src/access/isPlatformBasicUser.ts 30.76% 100% 50% 30.76% 10-18
src/access/scopeFilters.ts 100% 100% 100% 100%
src/access/utils/getClinicAssignment.ts 91.66% 80% 100% 91.66% 10-11
src/access/utils/getDoctorClinic.ts 58.82% 20% 100% 58.82% 5-6, 13-14, 17-19
src/app/(frontend)/not-found.tsx 0% 0% 0% 0% 1-18
src/app/(frontend)/page.tsx 0% 0% 0% 0% 1-72
src/app/(frontend)/(sitemaps)/pages-sitemap.xml/route.ts 0% 0% 0% 0% 1-68
src/app/(frontend)/(sitemaps)/posts-sitemap.xml/route.ts 0% 0% 0% 0% 1-55
src/app/(frontend)/[slug]/page.tsx 0% 0% 0% 0% 1-110
src/app/(frontend)/admin/first-admin/page.tsx 0% 0% 0% 0% 1-58
src/app/(frontend)/admin/login/page.tsx 0% 0% 0% 0% 1-25
src/app/(frontend)/admin/logout/page.tsx 0% 100% 100% 0% 3-47
src/app/(frontend)/clinic/[slug]/page.tsx 0% 0% 0% 0% 1-182
src/app/(frontend)/login/patient/page.tsx 0% 0% 0% 0% 1-19
src/app/(frontend)/next/exit-preview/route.ts 0% 0% 0% 0% 1-7
src/app/(frontend)/next/preview/route.ts 0% 100% 100% 0% 2-60
src/app/(frontend)/posts/page.tsx 0% 100% 100% 0% 3-56
src/app/(frontend)/posts/[slug]/page.tsx 0% 0% 0% 0% 1-104
src/app/(frontend)/posts/page/[pageNumber]/page.tsx 0% 0% 0% 0% 1-81
src/app/(frontend)/register/clinic/page.tsx 0% 0% 0% 0% 1-29
src/app/(frontend)/register/patient/page.tsx 0% 0% 0% 0% 1-54
src/app/(frontend)/search/page.tsx 0% 100% 100% 0% 3-88
src/app/api/auth/login/route.ts 0% 0% 0% 0% 1-72
src/app/api/auth/register/first-admin/route.ts 0% 0% 0% 0% 1-79
src/app/api/auth/register/patient/route.ts 0% 100% 100% 0% 8-38
src/app/api/forms/[slug]/route.ts 0% 0% 0% 0% 1-36
src/app/api/register/clinic/route.ts 90.38% 14.28% 100% 90.38% 26-27, 57-59
src/auth/index.ts 100% 100% 100% 100%
src/auth/config/authConfig.ts 100% 100% 100% 100%
src/auth/strategies/supabaseStrategy.ts 100% 100% 100% 100%
src/auth/types/authTypes.ts 0% 0% 0% 0%
src/auth/utilities/accessValidation.ts 100% 100% 100% 100%
src/auth/utilities/firstAdminCheck.ts 0% 0% 0% 0% 1-30
src/auth/utilities/jwtValidation.ts 100% 100% 100% 100%
src/auth/utilities/loginHandler.ts 0% 100% 100% 0% 8-32
src/auth/utilities/registration.ts 0% 0% 0% 0% 1-74
src/auth/utilities/supaBaseClient.ts 0% 0% 0% 0% 1-8
src/auth/utilities/supaBaseServer.ts 7.01% 100% 0% 7.01% 7-66
src/auth/utilities/supabaseProvision.ts 0% 0% 0% 0% 1-44
src/auth/utilities/userCreation.ts 100% 100% 100% 100%
src/auth/utilities/userLookup.ts 82.85% 60% 100% 82.85% 32-34, 56-58
src/blocks/RenderBlocks.tsx 0% 0% 0% 0% 1-58
src/blocks/ArchiveBlock/config.ts 91.86% 100% 0% 91.86% 19-25
src/blocks/Banner/config.ts 93.33% 100% 0% 93.33% 29-30
src/blocks/BenefitsBlock/config.ts 100% 100% 100% 100%
src/blocks/BenefitsBlock/types/dbNameOverride.ts 0% 0% 0% 0%
src/blocks/CallToAction/config.ts 78.78% 100% 0% 78.78% 21-27
src/blocks/Content/config.ts 95.09% 100% 0% 95.09% 23-27
src/blocks/Form/config.ts 83.72% 100% 0% 83.72% 33-39
src/blocks/Form/fields.tsx 0% 0% 0% 0% 1-21
src/blocks/Form/Checkbox/index.tsx 0% 100% 100% 0% 4-45
src/blocks/Form/Country/index.tsx 0% 100% 100% 0% 4-65
src/blocks/Form/Email/index.tsx 0% 100% 100% 0% 4-38
src/blocks/Form/Error/index.tsx 0% 0% 0% 0% 1-5
src/blocks/Form/Message/index.tsx 0% 0% 0% 0% 1-13
src/blocks/Form/Number/index.tsx 0% 100% 100% 0% 4-36
src/blocks/Form/Select/index.tsx 0% 100% 100% 0% 4-74
src/blocks/Form/State/index.tsx 0% 100% 100% 0% 4-64
src/blocks/Form/Text/index.tsx 0% 100% 100% 0% 4-32
src/blocks/Form/Textarea/index.tsx 0% 100% 100% 0% 4-40
src/blocks/Form/Width/index.tsx 0% 0% 0% 0% 1-13
src/blocks/LayoutBlock/config.ts 100% 100% 100% 100%
src/blocks/MediaBlock/config.ts 100% 100% 100% 100%
src/blocks/NewsletterBlock/config.ts 100% 100% 100% 100%
src/blocks/SearchBlock/config.ts 100% 100% 100% 100%
src/collections/Accreditation.ts 100% 100% 100% 100%
src/collections/Categories.ts 100% 100% 100% 100%
src/collections/Cities.ts 100% 100% 100% 100%
src/collections/ClinicApplications.ts 98.23% 100% 33.33% 98.23% 146-148
src/collections/ClinicStaff.ts 93.02% 90.9% 66.66% 93.02% 53-56, 89-90
src/collections/Clinics.ts 97.36% 100% 0% 97.36% 204-208, 246-247
src/collections/Countries.ts 100% 100% 100% 100%
src/collections/DoctorSpecialties.ts 100% 100% 100% 100%
src/collections/DoctorTreatments.ts 100% 100% 0% 100%
src/collections/Doctors.ts 96.87% 100% 0% 96.87% 71-76
src/collections/FavoriteClinics.ts 100% 100% 100% 100%
src/collections/MedicalSpecialties.ts 100% 100% 100% 100%
src/collections/PlatformStaff.ts 92.3% 100% 66.66% 92.3% 33-36
src/collections/Reviews.ts 78.6% 100% 57.14% 78.6% 50-54, 186-201, 206-245
src/collections/Tags.ts 100% 100% 100% 100%
src/collections/Treatments.ts 100% 100% 100% 100%
src/collections/BasicUsers/index.ts 100% 100% 0% 100%
src/collections/BasicUsers/hooks/createSupabaseUser.ts 100% 76.92% 100% 100%
src/collections/BasicUsers/hooks/createUserProfile.ts 100% 93.75% 100% 100%
src/collections/BasicUsers/hooks/deleteSupabaseUser.ts 66.66% 54.54% 100% 66.66% 35-40, 52-56, 58-59, 61-65
src/collections/ClinicGalleryEntries/index.ts 100% 83.33% 100% 100%
src/collections/ClinicGalleryEntries/hooks/beforeChangeClinicGalleryEntry.ts 6.66% 100% 0% 6.66% 12-35, 44-72
src/collections/ClinicGalleryMedia/index.ts 98.12% 83.33% 50% 98.12% 19-21
src/collections/ClinicMedia/index.ts 100% 90% 100% 100%
src/collections/ClinicTreatments/index.ts 100% 100% 100% 100%
src/collections/ClinicTreatments/hooks/averagePriceUtils.ts 87.5% 62.5% 100% 87.5% 4, 31-33, 52-53
src/collections/ClinicTreatments/hooks/updateAveragePriceAfterChange.ts 69.23% 25% 100% 69.23% 19-24, 26-27
src/collections/ClinicTreatments/hooks/updateAveragePriceAfterDelete.ts 86.66% 25% 100% 86.66% 15-16
src/collections/DoctorMedia/index.ts 100% 77.77% 100% 100%
src/collections/Pages/index.ts 91.66% 100% 66.66% 91.66% 48-55, 58-62
src/collections/Pages/hooks/populatePublishedAt.ts 10% 100% 0% 10% 4-13
src/collections/Pages/hooks/revalidatePage.ts 10% 100% 0% 10% 6-31, 34-41
src/collections/Patients/index.ts 100% 100% 66.66% 100%
src/collections/Patients/hooks/patientSupabaseCreate.ts 85% 72.72% 100% 85% 20-22
src/collections/Patients/hooks/patientSupabaseDelete.ts 88.23% 40% 100% 88.23% 17-18
src/collections/PlatformContentMedia/index.ts 100% 100% 100% 100%
src/collections/Posts/index.ts 86.38% 100% 40% 86.38% 53-60, 63-67, 107-115, 145-150, 205-209
src/collections/Posts/hooks/populateAuthors.ts 2.77% 100% 0% 2.77% 9-49
src/collections/Posts/hooks/revalidatePost.ts 10% 100% 0% 10% 6-31, 34-42
src/collections/common/mediaPathHelpers.ts 70.94% 73.21% 100% 70.94% 20-28, 37-61, 93-94, 132-133
src/collections/common/selectionOptions.ts 100% 100% 100% 100%
src/components/ClinicCard.tsx 0% 0% 0% 0% 1-37
src/components/AdminBar/index.tsx 0% 100% 100% 0% 5-86
src/components/Auth/BaseLoginForm.tsx 0% 100% 100% 0% 4-174
src/components/Auth/BaseRegistrationForm.tsx 0% 100% 100% 0% 4-155
src/components/Auth/types/loginTypes.ts 0% 0% 0% 0%
src/components/Card/index.tsx 0% 100% 100% 0% 2-84
src/components/CollectionArchive/index.tsx 0% 0% 0% 0% 1-32
src/components/Container/index.tsx 0% 0% 0% 0% 1-9
src/components/DeveloperDashboard/index.tsx 0% 0% 0% 0% 1-36
src/components/DeveloperDashboard/Seeding/SeedingCard.tsx 0% 100% 100% 0% 2-154
src/components/Link/index.tsx 0% 0% 0% 0% 1-54
src/components/LivePreviewListener/index.tsx 0% 100% 100% 0% 2-10
src/components/Logo/Logo.tsx 0% 0% 0% 0% 1-35
src/components/Media/index.tsx 0% 0% 0% 0% 1-25
src/components/Media/types.ts 0% 0% 0% 0%
src/components/Media/ImageMedia/index.tsx 0% 100% 100% 0% 5-76
src/components/Media/VideoMedia/index.tsx 0% 100% 100% 0% 3-46
src/components/PageRange/index.tsx 0% 0% 0% 0% 1-57
src/components/Pagination/index.tsx 0% 100% 100% 0% 2-101
src/components/PayloadRedirects/index.tsx 0% 100% 100% 0% 4-48
src/components/RichText/index.tsx 0% 0% 0% 0% 1-71
src/fields/defaultLexical.ts 42.5% 100% 0% 42.5% 29-52
src/fields/link.ts 98.33% 83.33% 33.33% 98.33% 117-118
src/fields/linkGroup.ts 100% 100% 100% 100%
src/heros/config.ts 88.88% 100% 0% 88.88% 46-52
src/hooks/createdBy.ts 100% 75% 100% 100%
src/hooks/immutability.ts 26.66% 100% 100% 26.66% 24-36
src/hooks/ownership.ts 93.33% 78.26% 100% 93.33% 18-19
src/hooks/publishedAt.ts 27.77% 50% 100% 27.77% 27-40
src/hooks/revalidateRedirects.ts 33.33% 100% 0% 33.33% 6-11
src/hooks/calculations/updateAverageRatings.ts 1.38% 100% 0% 1.38% 4-76, 79-141, 144-178
src/plugins/index.ts 77.97% 0% 0% 77.97% 19-20, 23-26, 42-53, 77-94, 110-111
src/providers/index.tsx 0% 0% 0% 0% 1-7
src/search/Component.tsx 0% 100% 100% 0% 2-41
src/search/beforeSync.ts 2.85% 100% 0% 2.85% 4-44
src/search/fieldOverrides.ts 100% 100% 100% 100%
src/security/permission-matrix.config.ts 0% 100% 100% 0% 114-562
src/utilities/canUseDOM.ts 100% 0% 100% 100%
src/utilities/deepMerge.ts 95% 90% 100% 95% 24
src/utilities/formatAuthors.ts 100% 100% 100% 100%
src/utilities/formatDateTime.ts 100% 100% 100% 100%
src/utilities/generateMeta.ts 96.87% 95.65% 100% 96.87% 58
src/utilities/generatePreviewPath.ts 100% 100% 100% 100%
src/utilities/getDocument.ts 0% 100% 100% 0% 3-48
src/utilities/getForm.ts 100% 100% 100% 100%
src/utilities/getGlobals.ts 0% 100% 100% 0% 3-42
src/utilities/getMediaUrl.ts 100% 100% 100% 100%
src/utilities/getRedirects.ts 0% 0% 0% 0% 1-37
src/utilities/getURL.ts 78.26% 90.9% 100% 78.26% 42-47
src/utilities/mergeOpenGraph.ts 100% 100% 100% 100%
src/utilities/nameUtils.ts 100% 100% 100% 100%
src/utilities/slugify.ts 100% 100% 100% 100%
src/utilities/submitForm.ts 100% 100% 100% 100%
src/utilities/ui.ts 100% 100% 100% 100%
src/utilities/useClickableCard.ts 0% 100% 100% 0% 4-140
src/utilities/useDebounce.ts 0% 0% 0% 0% 1-31
Generated in workflow #843 for commit 83deb31 by the Vitest Coverage Report Action

…aths

- Add vi.mock('crypto') in platformContentMediaBeforeChange and doctorMediaBeforeChange tests to produce stable short-hash values
- Update expected filename and storagePath assertions to use the mocked hash prefix (first 10 chars)
- Adjust comments to clarify hashing expectations in assertions
@github-actions
Copy link

github-actions bot commented Oct 15, 2025

Coverage Report for Integration Tests

Status Category Percentage Covered / Total
🟢 Lines 48.12% (🎯 40%) 4482 / 9314
🟢 Statements 48.12% (🎯 40%) 4482 / 9314
🟢 Functions 38.21% (🎯 35%) 107 / 280
🟢 Branches 57.85% (🎯 55%) 151 / 261
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/collections/DoctorMedia/hooks/beforeChangeDoctorMedia.ts 8.16% 100% 0% 8.16% 7-62
src/collections/PlatformContentMedia/hooks/beforeChangePlatformContentMedia.ts 6.89% 100% 0% 6.89% 5-36
src/collections/UserProfileMedia/index.ts 70.58% 100% 0% 70.58% 15-19, 22-37, 49-53, 63-74
src/hooks/media/computeStorage.ts 8.73% 100% 33.33% 8.73% 17-19, 37-132, 146-161
src/utilities/requestFileUtils.ts 5.55% 100% 0% 5.55% 6-29
Unchanged Files
src/Footer/Component.tsx 0% 0% 0% 0% 1-115
src/Footer/RowLabel.tsx 0% 100% 100% 0% 3-13
src/Footer/config.ts 100% 100% 0% 100%
src/Footer/hooks/revalidateFooter.ts 100% 100% 100% 100%
src/Header/Component.client.tsx 0% 100% 100% 0% 2-25
src/Header/Component.tsx 0% 0% 0% 0% 1-11
src/Header/RowLabel.tsx 0% 100% 100% 0% 3-13
src/Header/config.ts 100% 100% 0% 100%
src/Header/Nav/index.tsx 0% 100% 100% 0% 3-30
src/Header/hooks/revalidateHeader.ts 100% 100% 100% 100%
src/access/anyone.ts 100% 100% 0% 100%
src/access/authenticated.ts 0% 100% 100% 0% 7-9
src/access/authenticatedAndAdmin.ts 0% 100% 100% 0% 10-15
src/access/authenticatedOrApprovedClinic.ts 0% 100% 100% 0% 3-13
src/access/authenticatedOrPublished.ts 0% 100% 100% 0% 3-13
src/access/clinicGallery.ts 12.5% 100% 0% 12.5% 16-37, 43-59
src/access/fieldAccess.ts 33.33% 100% 0% 33.33% 14-15
src/access/isClinicBasicUser.ts 18.18% 100% 0% 18.18% 5-6, 10-16
src/access/isPatient.ts 14.28% 100% 0% 14.28% 5-6, 10-21
src/access/isPlatformBasicUser.ts 15.38% 100% 0% 15.38% 5-6, 10-18
src/access/scopeFilters.ts 11.65% 100% 0% 11.65% 21-39, 47-62, 70-88, 94-101, 109-127, 135-145, 153-163, 171-181
src/access/utils/getClinicAssignment.ts 0% 100% 0% 0% 7-34
src/access/utils/getDoctorClinic.ts 0% 100% 0% 0% 3-20
src/app/(frontend)/not-found.tsx 0% 0% 0% 0% 1-18
src/app/(frontend)/page.tsx 0% 0% 0% 0% 1-72
src/app/(frontend)/(sitemaps)/pages-sitemap.xml/route.ts 0% 0% 0% 0% 1-68
src/app/(frontend)/(sitemaps)/posts-sitemap.xml/route.ts 0% 0% 0% 0% 1-55
src/app/(frontend)/[slug]/page.tsx 0% 0% 0% 0% 1-110
src/app/(frontend)/admin/first-admin/page.tsx 0% 0% 0% 0% 1-58
src/app/(frontend)/admin/login/page.tsx 0% 0% 0% 0% 1-25
src/app/(frontend)/admin/logout/page.tsx 0% 100% 100% 0% 3-47
src/app/(frontend)/clinic/[slug]/page.tsx 0% 0% 0% 0% 1-182
src/app/(frontend)/login/patient/page.tsx 0% 0% 0% 0% 1-19
src/app/(frontend)/next/exit-preview/route.ts 0% 0% 0% 0% 1-7
src/app/(frontend)/next/preview/route.ts 0% 100% 100% 0% 2-60
src/app/(frontend)/posts/page.tsx 0% 100% 100% 0% 3-56
src/app/(frontend)/posts/[slug]/page.tsx 0% 0% 0% 0% 1-104
src/app/(frontend)/posts/page/[pageNumber]/page.tsx 0% 0% 0% 0% 1-81
src/app/(frontend)/register/clinic/page.tsx 0% 0% 0% 0% 1-29
src/app/(frontend)/register/patient/page.tsx 0% 0% 0% 0% 1-54
src/app/(frontend)/search/page.tsx 0% 100% 100% 0% 3-88
src/app/api/auth/login/route.ts 0% 0% 0% 0% 1-72
src/app/api/auth/register/first-admin/route.ts 0% 0% 0% 0% 1-79
src/app/api/auth/register/patient/route.ts 0% 100% 100% 0% 8-38
src/app/api/forms/[slug]/route.ts 0% 0% 0% 0% 1-36
src/app/api/register/clinic/route.ts 0% 0% 0% 0% 1-60
src/auth/index.ts 0% 100% 100% 0% 8-45
src/auth/config/authConfig.ts 79.06% 100% 0% 79.06% 76-79, 85-89
src/auth/strategies/supabaseStrategy.ts 22.91% 100% 0% 22.91% 25-40, 43-78
src/auth/types/authTypes.ts 0% 0% 0% 0%
src/auth/utilities/accessValidation.ts 4.25% 100% 0% 4.25% 17-47, 55-85
src/auth/utilities/firstAdminCheck.ts 0% 0% 0% 0% 1-30
src/auth/utilities/jwtValidation.ts 8.77% 100% 0% 8.77% 16-24, 32-42, 50-100
src/auth/utilities/loginHandler.ts 0% 100% 100% 0% 8-32
src/auth/utilities/registration.ts 0% 0% 0% 0% 1-74
src/auth/utilities/supaBaseClient.ts 0% 0% 0% 0% 1-8
src/auth/utilities/supaBaseServer.ts 7.01% 100% 0% 7.01% 7-66
src/auth/utilities/supabaseProvision.ts 0% 0% 0% 0% 1-44
src/auth/utilities/userCreation.ts 3.12% 100% 0% 3.12% 15-57
src/auth/utilities/userLookup.ts 2.85% 100% 0% 2.85% 15-59
src/blocks/RenderBlocks.tsx 0% 0% 0% 0% 1-58
src/blocks/ArchiveBlock/config.ts 100% 100% 20% 100%
src/blocks/Banner/config.ts 100% 100% 100% 100%
src/blocks/BenefitsBlock/config.ts 100% 100% 100% 100%
src/blocks/BenefitsBlock/types/dbNameOverride.ts 0% 0% 0% 0%
src/blocks/CallToAction/config.ts 100% 100% 100% 100%
src/blocks/Content/config.ts 100% 100% 50% 100%
src/blocks/Form/config.ts 100% 100% 50% 100%
src/blocks/Form/fields.tsx 0% 0% 0% 0% 1-21
src/blocks/Form/Checkbox/index.tsx 0% 100% 100% 0% 4-45
src/blocks/Form/Country/index.tsx 0% 100% 100% 0% 4-65
src/blocks/Form/Email/index.tsx 0% 100% 100% 0% 4-38
src/blocks/Form/Error/index.tsx 0% 0% 0% 0% 1-5
src/blocks/Form/Message/index.tsx 0% 0% 0% 0% 1-13
src/blocks/Form/Number/index.tsx 0% 100% 100% 0% 4-36
src/blocks/Form/Select/index.tsx 0% 100% 100% 0% 4-74
src/blocks/Form/State/index.tsx 0% 100% 100% 0% 4-64
src/blocks/Form/Text/index.tsx 0% 100% 100% 0% 4-32
src/blocks/Form/Textarea/index.tsx 0% 100% 100% 0% 4-40
src/blocks/Form/Width/index.tsx 0% 0% 0% 0% 1-13
src/blocks/LayoutBlock/config.ts 100% 100% 100% 100%
src/blocks/MediaBlock/config.ts 100% 100% 100% 100%
src/blocks/NewsletterBlock/config.ts 100% 100% 100% 100%
src/blocks/SearchBlock/config.ts 100% 100% 100% 100%
src/collections/Accreditation.ts 100% 100% 100% 100%
src/collections/Categories.ts 100% 100% 100% 100%
src/collections/Cities.ts 100% 100% 100% 100%
src/collections/ClinicApplications.ts 98.23% 100% 33.33% 98.23% 146-148
src/collections/ClinicStaff.ts 77.9% 100% 0% 77.9% 19-32, 35-37, 53-56, 89-90
src/collections/Clinics.ts 99.24% 40% 100% 99.24% 205-206
src/collections/Countries.ts 100% 100% 100% 100%
src/collections/DoctorSpecialties.ts 100% 100% 100% 100%
src/collections/DoctorTreatments.ts 100% 100% 0% 100%
src/collections/Doctors.ts 100% 100% 100% 100%
src/collections/FavoriteClinics.ts 100% 100% 0% 100%
src/collections/MedicalSpecialties.ts 100% 100% 100% 100%
src/collections/PlatformStaff.ts 100% 100% 33.33% 100%
src/collections/Reviews.ts 91.26% 63.63% 42.85% 91.26% 26-27, 32-33, 187-198, 211-212, 239-242
src/collections/Tags.ts 100% 100% 100% 100%
src/collections/Treatments.ts 100% 100% 100% 100%
src/collections/BasicUsers/index.ts 100% 100% 100% 100%
src/collections/BasicUsers/hooks/createSupabaseUser.ts 89.65% 50% 100% 89.65% 24-27
src/collections/BasicUsers/hooks/createUserProfile.ts 76.31% 28.57% 100% 76.31% 18-20, 27-32
src/collections/BasicUsers/hooks/deleteSupabaseUser.ts 57.4% 12.5% 100% 57.4% 15-17, 35-40, 49-50, 52-56, 58-59, 61-65
src/collections/ClinicGalleryEntries/index.ts 92.85% 100% 0% 92.85% 23-33
src/collections/ClinicGalleryEntries/hooks/beforeChangeClinicGalleryEntry.ts 6.66% 100% 0% 6.66% 12-35, 44-72
src/collections/ClinicGalleryMedia/index.ts 92.5% 100% 0% 92.5% 19-21, 38-48
src/collections/ClinicMedia/index.ts 90.32% 100% 0% 90.32% 28-39
src/collections/ClinicTreatments/index.ts 100% 100% 100% 100%
src/collections/ClinicTreatments/hooks/averagePriceUtils.ts 89.58% 68.75% 100% 89.58% 31-33, 52-53
src/collections/ClinicTreatments/hooks/updateAveragePriceAfterChange.ts 80.76% 20% 100% 80.76% 21-23, 26-27
src/collections/ClinicTreatments/hooks/updateAveragePriceAfterDelete.ts 86.66% 25% 100% 86.66% 15-16
src/collections/DoctorMedia/index.ts 89.58% 100% 0% 89.58% 32-44
src/collections/Pages/index.ts 91.66% 100% 0% 91.66% 48-55, 58-62
src/collections/Pages/hooks/populatePublishedAt.ts 10% 100% 0% 10% 4-13
src/collections/Pages/hooks/revalidatePage.ts 10% 100% 0% 10% 6-31, 34-41
src/collections/Patients/index.ts 92.26% 100% 33.33% 92.26% 25-36, 39-41
src/collections/Patients/hooks/patientSupabaseCreate.ts 70% 16.66% 100% 70% 8-10, 20-22
src/collections/Patients/hooks/patientSupabaseDelete.ts 70.58% 20% 100% 70.58% 10-12, 17-18
src/collections/PlatformContentMedia/index.ts 100% 100% 0% 100%
src/collections/Posts/index.ts 90.21% 100% 10% 90.21% 53-60, 63-67, 145-150, 205-209
src/collections/Posts/hooks/populateAuthors.ts 2.77% 100% 0% 2.77% 9-49
src/collections/Posts/hooks/revalidatePost.ts 10% 100% 0% 10% 6-31, 34-42
src/collections/common/mediaPathHelpers.ts 10.25% 100% 0% 10.25% 17-28, 31-61, 64-77, 80-117, 120-133, 136-140, 143-148, 151-156, 159-169
src/collections/common/selectionOptions.ts 100% 100% 100% 100%
src/components/ClinicCard.tsx 0% 0% 0% 0% 1-37
src/components/AdminBar/index.tsx 0% 100% 100% 0% 5-86
src/components/Auth/BaseLoginForm.tsx 0% 100% 100% 0% 4-174
src/components/Auth/BaseRegistrationForm.tsx 0% 100% 100% 0% 4-155
src/components/Auth/types/loginTypes.ts 0% 0% 0% 0%
src/components/Card/index.tsx 0% 100% 100% 0% 2-84
src/components/CollectionArchive/index.tsx 0% 0% 0% 0% 1-32
src/components/Container/index.tsx 0% 0% 0% 0% 1-9
src/components/DeveloperDashboard/index.tsx 0% 0% 0% 0% 1-36
src/components/DeveloperDashboard/Seeding/SeedingCard.tsx 0% 100% 100% 0% 2-154
src/components/Link/index.tsx 0% 0% 0% 0% 1-54
src/components/LivePreviewListener/index.tsx 0% 100% 100% 0% 2-10
src/components/Logo/Logo.tsx 0% 0% 0% 0% 1-35
src/components/Media/index.tsx 0% 0% 0% 0% 1-25
src/components/Media/types.ts 0% 0% 0% 0%
src/components/Media/ImageMedia/index.tsx 0% 100% 100% 0% 5-76
src/components/Media/VideoMedia/index.tsx 0% 100% 100% 0% 3-46
src/components/PageRange/index.tsx 0% 0% 0% 0% 1-57
src/components/Pagination/index.tsx 0% 100% 100% 0% 2-101
src/components/PayloadRedirects/index.tsx 0% 100% 100% 0% 4-48
src/components/RichText/index.tsx 0% 0% 0% 0% 1-71
src/fields/defaultLexical.ts 87.5% 100% 25% 87.5% 45-49
src/fields/link.ts 98.33% 87.5% 100% 98.33% 117-118
src/fields/linkGroup.ts 100% 100% 100% 100%
src/heros/config.ts 100% 100% 50% 100%
src/hooks/createdBy.ts 45.45% 50% 100% 45.45% 13-18
src/hooks/immutability.ts 26.66% 100% 100% 26.66% 24-36
src/hooks/ownership.ts 26.66% 100% 50% 26.66% 6-19, 35-42
src/hooks/publishedAt.ts 27.77% 50% 100% 27.77% 27-40
src/hooks/revalidateRedirects.ts 33.33% 100% 0% 33.33% 6-11
src/hooks/calculations/updateAverageRatings.ts 80.55% 57.69% 100% 80.55% 46-48, 74-75, 82-83, 114-116, 120-122, 126-134, 137-138, 147-148, 174-175
src/plugins/index.ts 97.02% 92.3% 75% 97.02% 19-20, 23-26
src/providers/index.tsx 0% 0% 0% 0% 1-7
src/search/Component.tsx 0% 100% 100% 0% 2-41
src/search/beforeSync.ts 2.85% 100% 0% 2.85% 4-44
src/search/fieldOverrides.ts 100% 100% 100% 100%
src/security/permission-matrix.config.ts 0% 100% 100% 0% 114-562
src/utilities/canUseDOM.ts 100% 0% 100% 100%
src/utilities/deepMerge.ts 95% 87.5% 100% 95% 24
src/utilities/formatAuthors.ts 0% 100% 100% 0% 13-24
src/utilities/formatDateTime.ts 0% 100% 100% 0% 17-26
src/utilities/generateMeta.ts 0% 100% 100% 0% 5-64
src/utilities/generatePreviewPath.ts 35.71% 100% 0% 35.71% 32-42
src/utilities/getDocument.ts 0% 100% 100% 0% 3-48
src/utilities/getForm.ts 0% 100% 100% 0% 12-27
src/utilities/getGlobals.ts 0% 100% 100% 0% 3-42
src/utilities/getMediaUrl.ts 0% 100% 100% 0% 16-27
src/utilities/getRedirects.ts 0% 0% 0% 0% 1-37
src/utilities/getURL.ts 34.78% 25% 50% 34.78% 18-19, 22-23, 41-54
src/utilities/mergeOpenGraph.ts 0% 100% 100% 0% 2-37
src/utilities/nameUtils.ts 100% 50% 100% 100%
src/utilities/slugify.ts 100% 50% 100% 100%
src/utilities/submitForm.ts 0% 100% 100% 0% 17-39
src/utilities/ui.ts 0% 100% 100% 0% 7-12
src/utilities/useClickableCard.ts 0% 100% 100% 0% 4-140
src/utilities/useDebounce.ts 0% 0% 0% 0% 1-31
Generated in workflow #843 for commit 83deb31 by the Vitest Coverage Report Action

…omputeStorage

- Replace duplicated per-collection hashing/filename logic with computeStorage:
  - DoctorMedia and PlatformContentMedia now call computeStorage for filename/storagePath.
  - Remove legacy beforeChangeUserProfileMedia and switch UserProfileMedia to use beforeChangeComputeStorage with ownership freeze and createdBy stamping.
- Extend computeStorage:
  - Add key.type = 'hash' to derive short deterministic folder keys from owner, filename, and optional file size.
  - Add ownerRequired option to allow owner-less collections (e.g., platform assets).
  - Improve keySource reporting and logging formatting.
- Tests: mock crypto for stable hashes; add tests for hash key derivation and ownerRequired=false; update user profile hook tests to reflect new hash-based behavior.
- Docs: clarify media ownership/access and storage path pattern in docs/integrations/storage.md.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 5 comments.

…action

- docs: update storage.md to use `platform` as the top-level namespace/S3 prefix instead of `media`
- hooks: computeStorage imports extractFileSizeFromRequest, derives/sets a keySource, and uses the helper for hash/fallback folder-key derivation; keySource included in telemetry
- util: add extractFileSizeFromRequest to normalize file size extraction from varied request shapes
- seed: remove unused uploaderId from seedDoctors and calling demo runner; minor formatting cleanup in doctors seed
- test: move stable crypto mock in beforeChangeComputeStorage tests to top-level to avoid duplicate mocks and adjust import order
@SebastianSchuetze SebastianSchuetze merged commit be4b90f into main Oct 15, 2025
9 checks passed
@SebastianSchuetze SebastianSchuetze deleted the fix/media-storage-hash branch October 15, 2025 19:54
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 6 comments.

Comment on lines +41 to +48
// Platform (no owner segment)
beforeChangeComputeStorage({ ownerField: undefined as any, key: { type: 'hash' }, storagePrefix: 'media' })

// Clinics (owner = clinic id)
beforeChangeComputeStorage({ ownerField: 'clinic', key: { type: 'hash' }, storagePrefix: 'clinics' })

// Users (owner = user id)
beforeChangeComputeStorage({ ownerField: 'user', key: { type: 'hash' }, storagePrefix: 'users' })
Copy link

Copilot AI Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The platform example is inconsistent with the implementation and tests. It should use a real (optional) owner field with ownerRequired: false and the 'platform' prefix; also avoid 'undefined as any'. Suggest updating to: beforeChangeComputeStorage({ ownerField: 'platformOwner', key: { type: 'hash' }, storagePrefix: 'platform', ownerRequired: false }).

Copilot uses AI. Check for mistakes.
Comment on lines +51 to +56
Resulting path shapes:
- Platform content: `media/<hash>/<basename>`
- Clinic media: `clinics/<clinicId>/<hash>/<basename>`
- Clinic gallery media: `clinics/<clinicId>/gallery/<hash>/<basename>`
- Doctor media: `doctors/<doctorId>/<hash>/<basename>`
- User profile media: `users/<userId>/<hash>/<basename>`
Copy link

Copilot AI Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The platform path should align with code/tests which use the 'platform' namespace, not 'media'. Update line 52 to: - Platform content: platform/<hash>/<basename>.

Copilot uses AI. Check for mistakes.
Comment on lines +51 to +56
Resulting path shapes:
- Platform content: `media/<hash>/<basename>`
- Clinic media: `clinics/<clinicId>/<hash>/<basename>`
- Clinic gallery media: `clinics/<clinicId>/gallery/<hash>/<basename>`
- Doctor media: `doctors/<doctorId>/<hash>/<basename>`
- User profile media: `users/<userId>/<hash>/<basename>`
Copy link

Copilot AI Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs state clinic gallery media includes a 'gallery/' segment, but the shared hook examples do not describe how that segment is introduced. Please either add a specific example showing how the collection inserts 'gallery/' (e.g., dedicated beforeChange for clinicGalleryMedia) or adjust the documented path to match the current computeStorage behavior.

Copilot uses AI. Check for mistakes.
Comment on lines +78 to +95
// Always derive a hash-based folder key
const fileSize = extractFileSizeFromRequest(req)
const ownerSegment = owner ?? 'platform'
const filenameSegment = base ?? 'unknown'
const raw = `${ownerSegment}:${filenameSegment}${fileSize ? `:${fileSize}` : ''}`
folderKey = shortHash(raw)
keySource = 'hash'
}

// Ensure a stable key even when the configured source is missing.
if (!folderKey && operation === 'create') {
const fileSize = extractFileSizeFromRequest(req)
const ownerSegment = owner ?? 'platform'
const filenameSegment = base ?? 'unknown'
const raw = `${ownerSegment}:${filenameSegment}${fileSize ? `:${fileSize}` : ''}`
folderKey = shortHash(raw)
keySource = 'derived-hash'
}
Copy link

Copilot AI Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hash key derivation logic is duplicated. Consider extracting a small helper (e.g., deriveHashKey(owner, base, req)) to compute the raw string and shortHash once, then reuse it for both the 'hash' and 'derived-hash' branches.

Copilot uses AI. Check for mistakes.
@@ -1,3 +1,4 @@
import crypto from 'crypto'
Copy link

Copilot AI Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer importing from 'node:crypto' in ESM environments to avoid ambiguity and unintended polyfills: import crypto from 'node:crypto'. If updated, align the tests' vi.mock to mock 'node:crypto' accordingly.

Suggested change
import crypto from 'crypto'
import crypto from 'node:crypto'

Copilot uses AI. Check for mistakes.
expect(result.storagePath).toBe('platform/8686b7a110/hero.png')
})

test('preserves existing storage path on update without filename', async () => {
Copy link

Copilot AI Oct 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test name no longer matches the behavior (the hook now derives a hashed path on update using the original filename). Rename the test to reflect the new behavior, for example: 'derives hashed storage path on update without filename'.

Copilot generated this review using guidance from repository custom instructions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant