Skip to content

Enhance site content management and support for Supabase client#70

Merged
callofcode07 merged 8 commits into
mainfrom
new-feature
Jun 16, 2026
Merged

Enhance site content management and support for Supabase client#70
callofcode07 merged 8 commits into
mainfrom
new-feature

Conversation

@Harish-Naruto

@Harish-Naruto Harish-Naruto commented Jun 16, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features
    • Added site content management functionality, allowing admins to update hero images, captions, and gallery photos with alt text and ordering.
    • Introduced site action management with visibility controls and URL configuration.
    • New endpoints for retrieving and managing all site page content components.

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Harish-Naruto, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 20 minutes and 9 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0f9decbd-4ad9-4ea7-a6a5-d00dae70e710

📥 Commits

Reviewing files that changed from the base of the PR and between 5130843 and ed5acdb.

📒 Files selected for processing (1)
  • src/controllers/site-content.controller.ts
📝 Walkthrough

Walkthrough

Adds two new Prisma models (SitePageContent, SiteAction) with a SQL migration, extracts the Supabase client into a shared utility, removes the injected Supabase dependency from existing router factories, and introduces a full site content API (hero image, gallery photos, site actions) with TypeScript types, a service layer, Express controllers, route wiring, and tests.

Changes

Dynamic Site Content Feature

Layer / File(s) Summary
Database schema: SitePageContent and SiteAction models
prisma/migrations/.../migration.sql, prisma/schema.prisma
Migration creates SitePageContent and SiteAction tables with hero/gallery/action fields and FK constraints to Member. Prisma schema adds the two models and Member back-relations.
TypeScript types and shared Supabase client
src/types/site-content.d.ts, src/utils/supabaseClient.ts, src/app.ts
Global interfaces for GalleryPhoto, SiteActionItem, SiteContentResponse, and all input types are declared. Supabase client is extracted to a shared utility; app.ts drops its local client and updates docs route.
Supabase injection removal across existing routers and controllers
src/routes/achievements.ts, src/routes/projects.ts, src/routes/members.ts, src/routes/index.ts, src/controllers/achievement.controller.ts, src/controllers/project.controller.ts, tests/Achievement.test.ts, tests/Project.test.ts
supabase parameter removed from router factory signatures for achievements, projects, and members; controllers import from the shared utility; root routes function drops the supabase argument; existing test mocks updated to target supabaseClient.
Site content service
src/services/site-content.service.ts
Implements assertManager guard, gallery JSON parsing/sorting, SiteContentResponse builder, and all CRUD exports: getSiteContent, updateSitePageContent, updateSiteAction, addGalleryPhoto, updateGalleryPhoto, deleteGalleryPhoto, getGalleryPhoto.
Site content controller and route wiring
src/controllers/site-content.controller.ts, src/routes/site-content.ts, src/routes/index.ts
Controller handlers added for all six site content endpoints with JSON body parsing helpers. Router factory wires GET/PATCH /, PATCH /actions/:key, and POST/PATCH/DELETE /gallery/:photoId; mounted at /site-content in the root index.
SiteContent test suite
tests/SiteContent.test.ts
Tests cover all controller endpoints and service-level guard conditions, asserting correct argument passing, image upload/delete calls, HTTP status codes, and ApiError throws for invalid inputs.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant SiteContentRouter
    participant SiteContentController
    participant SiteContentService
    participant Supabase
    participant Prisma

    rect rgba(100, 149, 237, 0.5)
        Note over Client,Prisma: Gallery Photo Add Flow
        Client->>SiteContentRouter: POST /site-content/gallery (multipart)
        SiteContentRouter->>SiteContentRouter: parsePhotoData middleware
        SiteContentRouter->>SiteContentController: addGalleryPhoto(req, res)
        SiteContentController->>Supabase: uploadImage(file)
        Supabase-->>SiteContentController: imageUrl
        SiteContentController->>SiteContentService: addGalleryPhoto(adminId, {imageUrl, caption, ...})
        SiteContentService->>SiteContentService: assertManager(adminId)
        SiteContentService->>Prisma: findFirst SitePageContent
        Prisma-->>SiteContentService: current galleryPhotos JSON
        SiteContentService->>SiteContentService: generate UUID, compute sortOrder
        SiteContentService->>Prisma: update SitePageContent galleryPhotos
        SiteContentService-->>SiteContentController: SiteContentResponse
        SiteContentController-->>Client: 201 { success, data }
    end

    rect rgba(144, 238, 144, 0.5)
        Note over Client,Prisma: Gallery Photo Delete Flow
        Client->>SiteContentRouter: DELETE /site-content/gallery/:photoId
        SiteContentRouter->>SiteContentController: deleteGalleryPhoto(req, res)
        SiteContentController->>SiteContentService: deleteGalleryPhoto(adminId, photoId)
        SiteContentService->>Prisma: findFirst and update SitePageContent
        SiteContentService-->>SiteContentController: deleted imageUrl
        SiteContentController->>Supabase: deleteImage(imageUrl)
        SiteContentController-->>Client: 200 { success, message }
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • call-0f-code/COC-API#6: Introduces uploadImage/deleteImage utilities that the new site-content controller and service directly call for hero and gallery image management.
  • call-0f-code/COC-API#9: Adds achievement controller and routes in the same module where this PR rewires the supabase import source.
  • call-0f-code/COC-API#15: Touches src/routes/index.ts router wiring and member routes that this PR modifies to remove the supabase injection pattern.

Suggested reviewers

  • i-am-that-guy

Poem

🐇 Hop, hop, the gallery grows,
A hero image, sorted rows,
Supabase shared, no more passed around,
Actions and photos, safely found.
The rabbit grins — new routes abound! 🖼️

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the two main changes: adding site content management functionality and refactoring Supabase client initialization for broader use.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch new-feature

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (1)
tests/SiteContent.test.ts (1)

190-258: ⚡ Quick win

Add coverage for updateGalleryPhoto image replacement flow.

This suite currently exercises add/delete paths but does not assert the update path behavior (new upload + old image cleanup + service payload). Adding this test would guard the most failure-prone media mutation path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/SiteContent.test.ts` around lines 190 - 258, Add a test case for the
updateGalleryPhoto function to complete the gallery photo mutation test
coverage. Create a new describe block following the deleteGalleryPhoto tests
that exercises the image replacement flow: set up request/response mocks similar
to the existing tests, mock mockedUploadImage to resolve with a new image URL
and siteContentService.updateGalleryPhoto to resolve with updated content, call
the updateGalleryPhoto handler, then assert that mockedDeleteImage is called
with the old image URL, mockedUploadImage is called with the new file buffer,
siteContentService.updateGalleryPhoto is called with the adminId and updated
photo data (including the new imageUrl), and res.status is called with 200.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@prisma/migrations/20260614203131_add_dynamic_site_feature/migration.sql`:
- Around line 15-28: The SiteAction table migration creates an empty table, but
the updateSiteAction service expects rows to exist and uses findUnique with a
key field that will return 404 if missing. To fix this, add INSERT statements at
the end of the migration to seed all built-in SiteAction keys (such as
'recruitment') with their respective labels and default values, ensuring the
update-only API can function on a fresh database without requiring out-of-band
seeding.

In `@src/app.ts`:
- Line 10: Remove the unused import statement for `supabase` from
"./utils/supabaseClient" at the top of the file. This import is not referenced
anywhere in the code and is triggering the `@typescript-eslint/no-unused-vars`
lint error. Simply delete the entire import line to resolve the lint violation.

In `@src/controllers/site-content.controller.ts`:
- Around line 163-170: The previous image is being deleted twice during gallery
photo replacement: once within the uploadImage function call when passing
existing.imageUrl, and again with a separate deleteImage call. Remove the
redundant deleteImage(previousImageUrl) call that runs after uploadImage in both
locations (around line 163-170 and around line 194-196) since uploadImage
already handles deletion of the old image internally. This prevents a failure
from occurring after the database has been successfully updated.
- Around line 60-64: The controller methods lack authentication protection and
incorrectly accept adminId directly from client-supplied request data instead of
binding it to the authenticated user's identity. Add authentication middleware
to all mutating routes and modify the updateSiteContent, updateSiteAction,
addGalleryPhoto, updateGalleryPhoto, and deleteGalleryPhoto methods to extract
adminId from the authenticated user's identity (e.g., req.user.id from JWT or
session) rather than from the request body or parameters. Verify that the
authenticated user is authorized to act as that adminId before proceeding with
validation and service calls. Apply the same authentication and binding pattern
to similar methods in the topic, question, and member controllers.

In `@src/services/site-content.service.ts`:
- Around line 149-170: The gallery photo mutations in the service have a
read-modify-write race condition where concurrent requests can lose writes
because they all read the same snapshot and overwrite the full galleryPhotos
field. Wrap the read-modify-write operations in a Prisma transaction using
prisma.$transaction to ensure atomicity. This should be applied consistently
across all gallery mutation methods that modify the galleryPhotos field (the
addPhoto method shown, plus the update and delete operations mentioned in the
comment). The transaction should encompass both the getPageContent call and the
subsequent prisma.sitePageContent.update call to prevent concurrent requests
from clobbering each other's changes.

In `@tests/SiteContent.test.ts`:
- Around line 81-82: The test file tests/SiteContent.test.ts violates the
no-explicit-any lint rule by using `any` type annotations for request and
response mock objects at multiple locations. Replace each `any` type annotation
with proper TypeScript types: use `Partial<Request>` for request mock objects
and `Pick<Response, "status" | "json">` (or similar pick syntax listing only the
required properties) for response mock objects, or create dedicated mock
interfaces that define only the necessary properties for each test case. Apply
this fix consistently across all occurrences at lines 81-82 (anchor), 103, 112,
135, 142, 155, 166, 192, 205, 232, and 236 in tests/SiteContent.test.ts to
restore lint compliance and maintain type safety.

---

Nitpick comments:
In `@tests/SiteContent.test.ts`:
- Around line 190-258: Add a test case for the updateGalleryPhoto function to
complete the gallery photo mutation test coverage. Create a new describe block
following the deleteGalleryPhoto tests that exercises the image replacement
flow: set up request/response mocks similar to the existing tests, mock
mockedUploadImage to resolve with a new image URL and
siteContentService.updateGalleryPhoto to resolve with updated content, call the
updateGalleryPhoto handler, then assert that mockedDeleteImage is called with
the old image URL, mockedUploadImage is called with the new file buffer,
siteContentService.updateGalleryPhoto is called with the adminId and updated
photo data (including the new imageUrl), and res.status is called with 200.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 522f2783-b50c-489f-93cb-0ab6728b823a

📥 Commits

Reviewing files that changed from the base of the PR and between fc4aa9a and 5130843.

📒 Files selected for processing (17)
  • prisma/migrations/20260614203131_add_dynamic_site_feature/migration.sql
  • prisma/schema.prisma
  • src/app.ts
  • src/controllers/achievement.controller.ts
  • src/controllers/project.controller.ts
  • src/controllers/site-content.controller.ts
  • src/routes/achievements.ts
  • src/routes/index.ts
  • src/routes/members.ts
  • src/routes/projects.ts
  • src/routes/site-content.ts
  • src/services/site-content.service.ts
  • src/types/site-content.d.ts
  • src/utils/supabaseClient.ts
  • tests/Achievement.test.ts
  • tests/Project.test.ts
  • tests/SiteContent.test.ts

Comment on lines +15 to +28
CREATE TABLE "SiteAction" (
"id" SERIAL NOT NULL,
"key" TEXT NOT NULL,
"label" TEXT,
"url" TEXT,
"isVisible" BOOLEAN NOT NULL DEFAULT false,
"updatedById" TEXT,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "SiteAction_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "SiteAction_key_key" ON "SiteAction"("key");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Seed the built-in SiteAction keys before shipping the update-only API.

The migration creates an empty SiteAction table, but the supplied service path first does findUnique({ where: { key } }) and throws 404 when the row is missing; the stack lists updateSiteAction but no create action route/service. On a fresh database, keys such as recruitment cannot be managed until seeded out-of-band. Seed every supported key here, or change the service to upsert by key.

Example migration direction
 CREATE UNIQUE INDEX "SiteAction_key_key" ON "SiteAction"("key");
+
+-- Seed every fixed action key supported by the site-content API.
+-- Keep this list in sync with the API/types.
+INSERT INTO "SiteAction" ("key", "label", "url", "isVisible", "updatedAt")
+VALUES
+    ('recruitment', NULL, NULL, false, CURRENT_TIMESTAMP)
+ON CONFLICT ("key") DO NOTHING;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@prisma/migrations/20260614203131_add_dynamic_site_feature/migration.sql`
around lines 15 - 28, The SiteAction table migration creates an empty table, but
the updateSiteAction service expects rows to exist and uses findUnique with a
key field that will return 404 if missing. To fix this, add INSERT statements at
the end of the migration to seed all built-in SiteAction keys (such as
'recruitment') with their respective labels and default values, ensuring the
update-only API can function on a fresh database without requiring out-of-band
seeding.

Comment thread src/app.ts
Comment thread src/controllers/site-content.controller.ts
Comment thread src/controllers/site-content.controller.ts
Comment thread src/services/site-content.service.ts
Comment thread tests/SiteContent.test.ts
@callofcode07 callofcode07 self-requested a review June 16, 2026 14:14
@callofcode07 callofcode07 merged commit 6cc634b into main Jun 16, 2026
3 checks passed
@Harish-Naruto Harish-Naruto deleted the new-feature branch June 16, 2026 18:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants