Skip to content

feat: refactor claude prisma guidelines, schemas dir, and implement b… - #618

Merged
matt2415 merged 5 commits into
masterfrom
feat/prisma-rules-and-refactor
May 26, 2026
Merged

feat: refactor claude prisma guidelines, schemas dir, and implement b…#618
matt2415 merged 5 commits into
masterfrom
feat/prisma-rules-and-refactor

Conversation

@matt2415

@matt2415 matt2415 commented May 14, 2026

Copy link
Copy Markdown
Collaborator

…est practises

Jira link

https://tools.hmcts.net/jira/browse/VIBE-450

Change description

  • Reorganised schemas to now live in libs/postgres-prisma
  • Introduced clearer claude guidelines for Prisma usage
  • Implemented Prisma query improvements:
    • Replaced include with explicit select clauses across all queries
    • Moved all filtering from JavaScript to Prisma where clauses
    • Moved all sorting from JavaScript to Prisma orderBy
    • Eliminated N+1 patterns with batch queries

Testing done

Security Vulnerability Assessment

CVE Suppression: Are there any CVEs present in the codebase (either newly introduced or pre-existing) that are being intentionally suppressed or ignored by this commit?

  • Yes
  • No

Checklist

  • commit messages are meaningful and follow good commit message guidelines
  • README and other documentation has been updated / added (if needed)
  • tests have been updated / new tests has been added (if needed)
  • Does this PR introduce a breaking change

Summary by CodeRabbit

  • New Features

    • Added comprehensive email subscription flows: add-by-location, case-name and case-reference subscriptions, list-type selection, language/version selection, preview/confirm screens, and edit/manage flows.
  • Performance Improvements

    • Bulk location lookups and batched validations; more work done by the database (filtered/ordered queries) for faster page rendering.
  • Bug Fixes

    • Fixed ordering and rendering issues; ensured uploaded proof-of-ID files are removed when applications are rejected.
  • Documentation

    • Centralised guidance for database schema management and module configuration.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 14, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough
📝 Walkthrough
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/prisma-rules-and-refactor

@github-actions

github-actions Bot commented May 14, 2026

Copy link
Copy Markdown
Contributor

🎭 Playwright E2E Test Results

84 tests   52 ✅  3m 37s ⏱️
33 suites  32 💤
 1 files     0 ❌

Results for commit f144944.

♻️ This comment has been updated with latest results.

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
libs/system-admin-pages/src/third-party-user/queries.test.ts (1)

178-199: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove incorrect await usage.

getHighestSensitivity is a synchronous function that returns a string immediately. The await keyword serves no purpose here and may mislead readers into thinking the function is asynchronous.

🔧 Proposed fix to remove await
   it("should return unselected for empty array", async () => {
-    const result = await getHighestSensitivity([]);
+    const result = getHighestSensitivity([]);
     expect(result).toBe("unselected");
   });

   it("should return CLASSIFIED when present", async () => {
     const subscriptions = [{ sensitivity: "PUBLIC" }, { sensitivity: "CLASSIFIED" }, { sensitivity: "PRIVATE" }];
-    const result = await getHighestSensitivity(subscriptions);
+    const result = getHighestSensitivity(subscriptions);
     expect(result).toBe("CLASSIFIED");
   });

   it("should return PRIVATE when CLASSIFIED is not present", async () => {
     const subscriptions = [{ sensitivity: "PUBLIC" }, { sensitivity: "PRIVATE" }];
-    const result = await getHighestSensitivity(subscriptions);
+    const result = getHighestSensitivity(subscriptions);
     expect(result).toBe("PRIVATE");
   });

   it("should return PUBLIC when only PUBLIC is present", async () => {
     const subscriptions = [{ sensitivity: "PUBLIC" }];
-    const result = await getHighestSensitivity(subscriptions);
+    const result = getHighestSensitivity(subscriptions);
     expect(result).toBe("PUBLIC");
   });
libs/api/src/blob-ingestion/repository/queries.ts (1)

40-48: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Extract duplicated mapping logic to eliminate code repetition.

Both getIngestionLogsByDateRange and getRecentErrorLogs contain identical mapping logic that transforms Prisma results into IngestionLog types. This violates the DRY principle and increases maintenance burden.

♻️ Proposed refactor to extract common mapping logic
+function mapPrismaLogToIngestionLog(log: {
+  id: string;
+  timestamp: Date;
+  sourceSystem: string;
+  courtId: string;
+  status: string;
+  errorMessage: string | null;
+  artefactId: string | null;
+}): IngestionLog {
+  return {
+    id: log.id,
+    timestamp: log.timestamp,
+    sourceSystem: log.sourceSystem,
+    courtId: log.courtId,
+    status: log.status as "SUCCESS" | "VALIDATION_ERROR" | "SYSTEM_ERROR",
+    errorMessage: log.errorMessage || undefined,
+    artefactId: log.artefactId || undefined
+  };
+}
+
 export async function getIngestionLogsByDateRange(startDate: Date, endDate: Date): Promise<IngestionLog[]> {
   const logs = await prisma.ingestionLog.findMany({
     where: {
       timestamp: {
         gte: startDate,
         lte: endDate
       }
     },
     orderBy: {
       timestamp: "desc"
     },
     select: {
       id: true,
       timestamp: true,
       sourceSystem: true,
       courtId: true,
       status: true,
       errorMessage: true,
       artefactId: true
     }
   });
 
-  return logs.map((log) => ({
-    id: log.id,
-    timestamp: log.timestamp,
-    sourceSystem: log.sourceSystem,
-    courtId: log.courtId,
-    status: log.status as "SUCCESS" | "VALIDATION_ERROR" | "SYSTEM_ERROR",
-    errorMessage: log.errorMessage || undefined,
-    artefactId: log.artefactId || undefined
-  }));
+  return logs.map(mapPrismaLogToIngestionLog);
 }
 
 export async function getRecentErrorLogs(limit = 10): Promise<IngestionLog[]> {
   const logs = await prisma.ingestionLog.findMany({
     where: {
       status: {
         in: ["VALIDATION_ERROR", "SYSTEM_ERROR"]
       }
     },
     orderBy: {
       timestamp: "desc"
     },
     take: limit,
     select: {
       id: true,
       timestamp: true,
       sourceSystem: true,
       courtId: true,
       status: true,
       errorMessage: true,
       artefactId: true
     }
   });
 
-  return logs.map((log) => ({
-    id: log.id,
-    timestamp: log.timestamp,
-    sourceSystem: log.sourceSystem,
-    courtId: log.courtId,
-    status: log.status as "SUCCESS" | "VALIDATION_ERROR" | "SYSTEM_ERROR",
-    errorMessage: log.errorMessage || undefined,
-    artefactId: log.artefactId || undefined
-  }));
+  return logs.map(mapPrismaLogToIngestionLog);
 }

Based on learnings: Follow DRY principle: Don't repeat yourself. Factor out code used in multiple places into reusable functions or utilities.

Also applies to: 73-81

libs/location/src/filtering/service.ts (1)

67-77: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid serial awaits in the jurisdiction loop.

Line 68 runs one DB call at a time, so total latency scales with jurisdiction count. Run these calls concurrently to keep response time stable.

Proposed change
-  for (const jurisdiction of allJurisdictions) {
-    const subJurisdictionsForJurisdiction = await getSubJurisdictionsByJurisdiction(jurisdiction.jurisdictionId);
-
-    subJurisdictionItemsByJurisdiction[jurisdiction.jurisdictionId] = subJurisdictionsForJurisdiction
-      .map((sub) => ({
-        value: sub.subJurisdictionId.toString(),
-        text: locale === "cy" ? sub.welshName : sub.name,
-        checked: selectedSubJurisdictions.includes(sub.subJurisdictionId)
-      }))
-      .sort((a, b) => a.text.localeCompare(b.text));
-  }
+  const entries = await Promise.all(
+    allJurisdictions.map(async (jurisdiction) => {
+      const subJurisdictionsForJurisdiction = await getSubJurisdictionsByJurisdiction(jurisdiction.jurisdictionId);
+      const items = subJurisdictionsForJurisdiction
+        .map((sub) => ({
+          value: sub.subJurisdictionId.toString(),
+          text: locale === "cy" ? sub.welshName : sub.name,
+          checked: selectedSubJurisdictions.includes(sub.subJurisdictionId)
+        }))
+        .sort((a, b) => a.text.localeCompare(b.text));
+      return [jurisdiction.jurisdictionId, items] as const;
+    })
+  );
+
+  for (const [jurisdictionId, items] of entries) {
+    subJurisdictionItemsByJurisdiction[jurisdictionId] = items;
+  }
🧹 Nitpick comments (7)
libs/system-admin-pages/src/third-party-user/queries.ts (1)

8-22: ⚡ Quick win

Extract duplicated select structure to eliminate repetition.

The identical select configuration is repeated in both findAllThirdPartyUsers and findThirdPartyUserById, violating the DRY principle.

♻️ Proposed refactor to extract shared select
+const THIRD_PARTY_USER_SELECT = {
+  id: true,
+  name: true,
+  createdDate: true,
+  subscriptions: {
+    select: {
+      id: true,
+      userId: true,
+      listTypeId: true,
+      channel: true,
+      sensitivity: true,
+      createdDate: true
+    }
+  }
+} as const;
+
 export async function findAllThirdPartyUsers() {
   return prisma.legacyThirdPartyUser.findMany({
     orderBy: {
       createdDate: "desc"
     },
-    select: {
-      id: true,
-      name: true,
-      createdDate: true,
-      subscriptions: {
-        select: {
-          id: true,
-          userId: true,
-          listTypeId: true,
-          channel: true,
-          sensitivity: true,
-          createdDate: true
-        }
-      }
-    }
+    select: THIRD_PARTY_USER_SELECT
   });
 }

 export async function findThirdPartyUserById(id: string) {
   return prisma.legacyThirdPartyUser.findUnique({
     where: { id },
-    select: {
-      id: true,
-      name: true,
-      createdDate: true,
-      subscriptions: {
-        select: {
-          id: true,
-          userId: true,
-          listTypeId: true,
-          channel: true,
-          sensitivity: true,
-          createdDate: true
-        }
-      }
-    }
+    select: THIRD_PARTY_USER_SELECT
   });
 }

As per coding guidelines: "Follow DRY principle: Don't repeat yourself. Factor out code used in multiple places into reusable functions or utilities."

Also applies to: 29-43

libs/location/src/repository/queries.ts (2)

17-26: ⚡ Quick win

Consider removing redundant length checks.

The filters.regions.length > 0 and filters.subJurisdictions.length > 0 checks are unnecessary. Prisma's in: [] operator naturally matches no rows when the array is empty, so the filter would have no effect. Removing these checks simplifies the logic without changing behaviour.

♻️ Simplified version
-      ...(filters?.regions &&
-        filters.regions.length > 0 && {
+      ...(filters?.regions && {
           locationRegions: {
             some: {
               regionId: {
                 in: filters.regions
               }
             }
           }
         }),
-      ...(filters?.subJurisdictions &&
-        filters.subJurisdictions.length > 0 && {
+      ...(filters?.subJurisdictions && {
           locationSubJurisdictions: {
             some: {
               subJurisdictionId: {
                 in: filters.subJurisdictions
               }
             }
           }
         })

Also applies to: 27-36


66-72: ⚡ Quick win

Extract duplicate mapping logic into helper function.

The logic for mapping nested locationRegions and locationSubJurisdictions to flat arrays of IDs is duplicated across four functions (getAllLocations, searchLocationsByName, getLocationById, and getLocationsByIds). Extracting this into a helper would reduce duplication and improve maintainability.

♻️ Suggested helper function
function mapLocationWithIds(loc: {
  locationId: number;
  name: string;
  welshName: string;
  locationRegions: Array<{ region: { regionId: number } }>;
  locationSubJurisdictions: Array<{ subJurisdiction: { subJurisdictionId: number } }>;
}): Location {
  return {
    locationId: loc.locationId,
    name: loc.name,
    welshName: loc.welshName,
    regions: loc.locationRegions.map((lr) => lr.region.regionId),
    subJurisdictions: loc.locationSubJurisdictions.map((lsj) => lsj.subJurisdiction.subJurisdictionId)
  };
}

Then replace the duplicated mapping with:

- return locations.map((loc) => ({
-   locationId: loc.locationId,
-   name: loc.name,
-   welshName: loc.welshName,
-   regions: loc.locationRegions.map((lr) => lr.region.regionId),
-   subJurisdictions: loc.locationSubJurisdictions.map((lsj) => lsj.subJurisdiction.subJurisdictionId)
- }));
+ return locations.map(mapLocationWithIds);

Based on learnings: Follow DRY principle: Don't repeat yourself. Factor out code used in multiple places into reusable functions or utilities.

Also applies to: 115-121, 159-165, 201-207

libs/verified-pages/src/pages/pending-subscriptions/index.ts (1)

31-37: ⚡ Quick win

Extract duplicate location-fetching logic and validate IDs.

Two issues:

  1. The location-fetching and mapping logic is duplicated between the GET handler and POST error path.
  2. Non-numeric strings in pendingLocationIds will produce NaN values when parsed, potentially causing unexpected behaviour.

Consider extracting the location-enrichment logic into a helper function and adding validation to filter out invalid IDs.

♻️ Suggested refactor
async function enrichPendingLocations(pendingLocationIds: string[], locale: string) {
  const locationIds = pendingLocationIds
    .map((id: string) => Number.parseInt(id, 10))
    .filter((id) => !Number.isNaN(id));
  const locations = await getLocationsByIds(locationIds);
  
  return locations.map((location) => ({
    locationId: location.locationId.toString(),
    name: locale === "cy" ? location.welshName : location.name
  }));
}

Then replace both occurrences with:

const pendingLocations = await enrichPendingLocations(pendingLocationIds, locale);

Based on learnings: Follow DRY principle: Don't repeat yourself. Factor out code used in multiple places into reusable functions or utilities.

Also applies to: 110-116

libs/subscriptions/src/repository/service.ts (1)

140-142: ⚡ Quick win

De-duplicate IDs before batch location fetches.

Both call sites can pass repeated IDs to getLocationsByIds, which adds avoidable query and mapping overhead.

Proposed change
-  const locationIds = subscriptions.map((sub) => Number.parseInt(sub.searchValue, 10)).filter((id) => !Number.isNaN(id));
+  const locationIds = [
+    ...new Set(subscriptions.map((sub) => Number.parseInt(sub.searchValue, 10)).filter((id) => !Number.isNaN(id)))
+  ];
   const locations = await getLocationsByIds(locationIds);
-  const locationIds = subscriptions.map((sub) => Number.parseInt(sub.searchValue, 10)).filter((id) => !Number.isNaN(id));
+  const locationIds = [
+    ...new Set(subscriptions.map((sub) => Number.parseInt(sub.searchValue, 10)).filter((id) => !Number.isNaN(id)))
+  ];
   const locations = await getLocationsByIds(locationIds);

Also applies to: 176-178

libs/publication/src/repository/queries.test.ts (2)

822-822: ⚡ Quick win

Remove obsolete mock.

The implementation no longer calls prisma.listType.findMany as it now uses nested selection via artefact.listType. This mock setup is dead code and should be removed.

♻️ Suggested cleanup
     vi.mocked(prisma.artefact.findMany).mockResolvedValue(mockArtefacts);
-    vi.mocked(prisma.listType.findMany).mockResolvedValue([]);

     const result = await getArtefactSummariesByLocation("123");

939-940: ⚡ Quick win

Remove obsolete listType mocks.

The implementation of getArtefactMetadata now uses nested selection on artefact.listType instead of separate prisma.listType.findUnique calls. These mock setups are no longer needed and should be removed.

♻️ Suggested cleanup
     vi.mocked(prisma.artefact.findUnique).mockResolvedValue(mockArtefact);
-    vi.mocked(prisma.listType.findUnique).mockResolvedValue(mockListType);
     vi.mocked(getLocationById).mockResolvedValue(mockLocation);

Also applies to: 970-971, 1004-1005, 1043-1044


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8abff8f5-c2a8-4880-9217-26f909235bb8

📥 Commits

Reviewing files that changed from the base of the PR and between 77d4d4d and 87545bc.

📒 Files selected for processing (69)
  • .claude/agents/full-stack-engineer.md
  • .claude/rules/backend.md
  • .github/workflows/e2e.yml
  • CLAUDE.md
  • README.md
  • apps/postgres/package.json
  • apps/postgres/prisma.config.ts
  • apps/postgres/prisma/seed.ts
  • docs/ARCHITECTURE.md
  • libs/admin-pages/src/pages/non-strategic-upload/index.test.ts
  • libs/admin-pages/src/pages/non-strategic-upload/index.ts
  • libs/api/src/blob-ingestion/repository/queries.test.ts
  • libs/api/src/blob-ingestion/repository/queries.ts
  • libs/audit-log/package.json
  • libs/audit-log/src/config.ts
  • libs/audit-log/tsconfig.json
  • libs/list-search-config/package.json
  • libs/list-search-config/src/config.test.ts
  • libs/list-search-config/src/config.ts
  • libs/location/src/config.test.ts
  • libs/location/src/config.ts
  • libs/location/src/filtering/service.test.ts
  • libs/location/src/filtering/service.ts
  • libs/location/src/index.ts
  • libs/location/src/repository/queries.test.ts
  • libs/location/src/repository/queries.ts
  • libs/location/src/repository/service.test.ts
  • libs/location/src/repository/service.ts
  • libs/notifications/package.json
  • libs/notifications/src/config.test.ts
  • libs/notifications/src/config.ts
  • libs/notifications/src/notification/subscription-queries.test.ts
  • libs/notifications/src/notification/subscription-queries.ts
  • libs/postgres-prisma/package.json
  • libs/postgres-prisma/prisma.config.ts
  • libs/postgres-prisma/prisma/schema/audit-log.prisma
  • libs/postgres-prisma/prisma/schema/base.prisma
  • libs/postgres-prisma/prisma/schema/list-search-config.prisma
  • libs/postgres-prisma/prisma/schema/location.prisma
  • libs/postgres-prisma/prisma/schema/notification.prisma
  • libs/postgres-prisma/prisma/schema/subscription.prisma
  • libs/postgres-prisma/src/collate-schema.test.ts
  • libs/postgres-prisma/src/collate-schema.ts
  • libs/postgres-prisma/src/schema-discovery.test.ts
  • libs/postgres-prisma/src/schema-discovery.ts
  • libs/publication/src/repository/queries.test.ts
  • libs/publication/src/repository/queries.ts
  • libs/subscriptions/package.json
  • libs/subscriptions/src/config.ts
  • libs/subscriptions/src/repository/service.test.ts
  • libs/subscriptions/src/repository/service.ts
  • libs/subscriptions/src/validation/validation.ts
  • libs/system-admin-pages/src/list-type/queries.test.ts
  • libs/system-admin-pages/src/list-type/queries.ts
  • libs/system-admin-pages/src/pages/blob-explorer-publications/index.test.ts
  • libs/system-admin-pages/src/pages/blob-explorer-publications/index.ts
  • libs/system-admin-pages/src/pages/configure-list-type-enter-details/index.test.ts
  • libs/system-admin-pages/src/pages/configure-list-type-enter-details/index.ts
  • libs/system-admin-pages/src/pages/configure-list-type-preview/index.test.ts
  • libs/system-admin-pages/src/pages/configure-list-type-preview/index.ts
  • libs/system-admin-pages/src/reference-data-upload/services/download-service.ts
  • libs/system-admin-pages/src/reference-data-upload/services/enrichment-service.ts
  • libs/system-admin-pages/src/third-party-user/queries.test.ts
  • libs/system-admin-pages/src/third-party-user/queries.ts
  • libs/verified-pages/src/pages/pending-subscriptions/index.test.ts
  • libs/verified-pages/src/pages/pending-subscriptions/index.ts
  • libs/verified-pages/src/pages/subscription-confirmed/index.test.ts
  • libs/verified-pages/src/pages/subscription-confirmed/index.ts
  • tsconfig.json
💤 Files with no reviewable changes (23)
  • libs/audit-log/package.json
  • libs/postgres-prisma/prisma/schema/list-search-config.prisma
  • libs/postgres-prisma/src/schema-discovery.test.ts
  • libs/postgres-prisma/src/schema-discovery.ts
  • libs/audit-log/tsconfig.json
  • libs/location/src/config.ts
  • libs/notifications/src/config.ts
  • libs/subscriptions/src/config.ts
  • libs/notifications/src/config.test.ts
  • tsconfig.json
  • libs/audit-log/src/config.ts
  • libs/notifications/package.json
  • libs/list-search-config/src/config.ts
  • libs/list-search-config/src/config.test.ts
  • libs/subscriptions/package.json
  • libs/postgres-prisma/src/collate-schema.test.ts
  • libs/postgres-prisma/src/collate-schema.ts
  • libs/postgres-prisma/prisma/schema/notification.prisma
  • .github/workflows/e2e.yml
  • libs/list-search-config/package.json
  • libs/location/src/config.test.ts
  • libs/postgres-prisma/prisma/schema/audit-log.prisma
  • libs/postgres-prisma/prisma/schema/subscription.prisma

Comment thread .claude/rules/backend.md Outdated
Comment thread apps/postgres/package.json
Comment thread apps/postgres/package.json Outdated
Comment thread docs/ARCHITECTURE.md Outdated
Comment on lines +17 to +18
const locationIds = confirmedLocationIds.map((id: string) => Number.parseInt(id, 10));
const locations = await getLocationsByIds(locationIds);

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 | 🟡 Minor | ⚡ Quick win

Validate location IDs before parsing.

If confirmedLocationIds contains non-numeric strings, Number.parseInt(id, 10) will return NaN. Passing NaN values to getLocationsByIds could result in unexpected behaviour. Consider filtering out invalid IDs or adding validation to ensure all values are numeric.

🛡️ Suggested validation
  const locationIds = confirmedLocationIds.map((id: string) => Number.parseInt(id, 10));
+ const validLocationIds = locationIds.filter((id) => !Number.isNaN(id));
+ const locations = await getLocationsByIds(validLocationIds);
- const locations = await getLocationsByIds(locationIds);

Comment thread README.md
@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/e2e.yml (1)

88-88: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove duplicate ENABLE_CFT_IDAM definition.

ENABLE_CFT_IDAM is defined twice: at line 61 and line 88. Remove the duplicate at line 88.

🔧 Proposed fix
       CFT_INVALID_TEST_ACCOUNT_PASSWORD: ${{ secrets.CFT_INVALID_TEST_ACCOUNT_PASSWORD }}

-      # Crime IDAM Configuration
-      ENABLE_CFT_IDAM: true
+      # Crime IDAM Configuration
       CRIME_IDAM_BASE_URL: https://login.sit.cjscp.org.uk
🧹 Nitpick comments (1)
e2e-tests/global-setup.ts (1)

20-22: 💤 Low value

Consider making the initial delay configurable.

The hardcoded 5-second delay may be too long for fast environments or too short for slow ones. However, given the robust retry loop (60 attempts), this is acceptable as it primarily reduces log noise during startup.

💡 Optional: Make delay configurable
-    // Add initial delay to allow services to start
-    console.log("Waiting 5 seconds for services to initialize...");
-    await new Promise((resolve) => setTimeout(resolve, 5000));
+    // Add initial delay to allow services to start
+    const initialDelay = Number(process.env.E2E_INITIAL_DELAY_MS) || 5000;
+    console.log(`Waiting ${initialDelay}ms for services to initialize...`);
+    await new Promise((resolve) => setTimeout(resolve, initialDelay));

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 40e2516e-3850-4a61-8fff-232a2598c5ff

📥 Commits

Reviewing files that changed from the base of the PR and between 0017091 and f492285.

📒 Files selected for processing (5)
  • .github/workflows/e2e.yml
  • apps/postgres/Dockerfile
  • apps/postgres/package.json
  • e2e-tests/global-setup.ts
  • e2e-tests/playwright.config.ts
💤 Files with no reviewable changes (1)
  • apps/postgres/Dockerfile
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/postgres/package.json

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

@matt2415
matt2415 force-pushed the feat/prisma-rules-and-refactor branch from 8a11758 to a3c60dd Compare May 14, 2026 12:31
@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

@matt2415
matt2415 force-pushed the feat/prisma-rules-and-refactor branch from 1d522d7 to 62dbbdd Compare May 15, 2026 08:19
@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

@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: 5


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f4e6c701-e715-4b3e-b2c8-518a41ce3a4b

📥 Commits

Reviewing files that changed from the base of the PR and between f492285 and 62dbbdd.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (71)
  • .claude/agents/full-stack-engineer.md
  • .claude/rules/backend.md
  • .github/workflows/e2e.yml
  • CLAUDE.md
  • README.md
  • apps/postgres/Dockerfile
  • apps/postgres/package.json
  • apps/postgres/prisma.config.ts
  • apps/postgres/prisma/seed.ts
  • docs/ARCHITECTURE.md
  • libs/admin-pages/src/pages/non-strategic-upload/index.test.ts
  • libs/admin-pages/src/pages/non-strategic-upload/index.ts
  • libs/api/src/blob-ingestion/repository/queries.test.ts
  • libs/api/src/blob-ingestion/repository/queries.ts
  • libs/audit-log/package.json
  • libs/audit-log/src/config.ts
  • libs/audit-log/tsconfig.json
  • libs/list-search-config/package.json
  • libs/list-search-config/src/config.test.ts
  • libs/list-search-config/src/config.ts
  • libs/location/src/config.test.ts
  • libs/location/src/config.ts
  • libs/location/src/filtering/service.test.ts
  • libs/location/src/filtering/service.ts
  • libs/location/src/index.ts
  • libs/location/src/repository/queries.test.ts
  • libs/location/src/repository/queries.ts
  • libs/location/src/repository/service.test.ts
  • libs/location/src/repository/service.ts
  • libs/notifications/package.json
  • libs/notifications/src/config.test.ts
  • libs/notifications/src/config.ts
  • libs/notifications/src/notification/subscription-queries.test.ts
  • libs/notifications/src/notification/subscription-queries.ts
  • libs/postgres-prisma/package.json
  • libs/postgres-prisma/prisma.config.ts
  • libs/postgres-prisma/prisma/schema/audit-log.prisma
  • libs/postgres-prisma/prisma/schema/base.prisma
  • libs/postgres-prisma/prisma/schema/list-search-config.prisma
  • libs/postgres-prisma/prisma/schema/location.prisma
  • libs/postgres-prisma/prisma/schema/notification.prisma
  • libs/postgres-prisma/prisma/schema/subscription.prisma
  • libs/postgres-prisma/src/collate-schema.test.ts
  • libs/postgres-prisma/src/collate-schema.ts
  • libs/postgres-prisma/src/schema-discovery.test.ts
  • libs/postgres-prisma/src/schema-discovery.ts
  • libs/publication/src/repository/queries.test.ts
  • libs/publication/src/repository/queries.ts
  • libs/subscriptions/package.json
  • libs/subscriptions/src/config.ts
  • libs/subscriptions/src/repository/service.test.ts
  • libs/subscriptions/src/repository/service.ts
  • libs/subscriptions/src/validation/validation.test.ts
  • libs/subscriptions/src/validation/validation.ts
  • libs/system-admin-pages/src/list-type/queries.test.ts
  • libs/system-admin-pages/src/list-type/queries.ts
  • libs/system-admin-pages/src/pages/blob-explorer-publications/index.test.ts
  • libs/system-admin-pages/src/pages/blob-explorer-publications/index.ts
  • libs/system-admin-pages/src/pages/configure-list-type-enter-details/index.test.ts
  • libs/system-admin-pages/src/pages/configure-list-type-enter-details/index.ts
  • libs/system-admin-pages/src/pages/configure-list-type-preview/index.test.ts
  • libs/system-admin-pages/src/pages/configure-list-type-preview/index.ts
  • libs/system-admin-pages/src/reference-data-upload/services/download-service.ts
  • libs/system-admin-pages/src/reference-data-upload/services/enrichment-service.ts
  • libs/system-admin-pages/src/third-party-user/queries.test.ts
  • libs/system-admin-pages/src/third-party-user/queries.ts
  • libs/verified-pages/src/pages/pending-subscriptions/index.test.ts
  • libs/verified-pages/src/pages/pending-subscriptions/index.ts
  • libs/verified-pages/src/pages/subscription-confirmed/index.test.ts
  • libs/verified-pages/src/pages/subscription-confirmed/index.ts
  • tsconfig.json
💤 Files with no reviewable changes (24)
  • libs/postgres-prisma/src/schema-discovery.test.ts
  • libs/audit-log/tsconfig.json
  • libs/notifications/src/config.ts
  • libs/subscriptions/package.json
  • libs/postgres-prisma/prisma/schema/notification.prisma
  • libs/postgres-prisma/src/collate-schema.ts
  • libs/notifications/package.json
  • libs/postgres-prisma/prisma/schema/audit-log.prisma
  • libs/postgres-prisma/prisma/schema/subscription.prisma
  • libs/location/src/config.ts
  • .github/workflows/e2e.yml
  • libs/list-search-config/src/config.test.ts
  • libs/audit-log/src/config.ts
  • libs/audit-log/package.json
  • libs/location/src/config.test.ts
  • tsconfig.json
  • libs/list-search-config/package.json
  • libs/postgres-prisma/prisma/schema/list-search-config.prisma
  • libs/notifications/src/config.test.ts
  • libs/postgres-prisma/src/schema-discovery.ts
  • libs/list-search-config/src/config.ts
  • libs/postgres-prisma/src/collate-schema.test.ts
  • apps/postgres/Dockerfile
  • libs/subscriptions/src/config.ts
✅ Files skipped from review due to trivial changes (5)
  • libs/verified-pages/src/pages/pending-subscriptions/index.test.ts
  • libs/location/src/index.ts
  • libs/admin-pages/src/pages/non-strategic-upload/index.test.ts
  • libs/notifications/src/notification/subscription-queries.ts
  • docs/ARCHITECTURE.md
🚧 Files skipped from review as they are similar to previous changes (32)
  • libs/verified-pages/src/pages/subscription-confirmed/index.test.ts
  • libs/postgres-prisma/prisma.config.ts
  • libs/system-admin-pages/src/third-party-user/queries.ts
  • libs/verified-pages/src/pages/subscription-confirmed/index.ts
  • libs/api/src/blob-ingestion/repository/queries.ts
  • apps/postgres/prisma.config.ts
  • libs/system-admin-pages/src/pages/configure-list-type-enter-details/index.test.ts
  • libs/api/src/blob-ingestion/repository/queries.test.ts
  • libs/admin-pages/src/pages/non-strategic-upload/index.ts
  • libs/system-admin-pages/src/pages/configure-list-type-preview/index.test.ts
  • libs/system-admin-pages/src/reference-data-upload/services/enrichment-service.ts
  • libs/location/src/filtering/service.test.ts
  • libs/system-admin-pages/src/pages/configure-list-type-preview/index.ts
  • libs/system-admin-pages/src/pages/blob-explorer-publications/index.ts
  • libs/system-admin-pages/src/third-party-user/queries.test.ts
  • libs/system-admin-pages/src/reference-data-upload/services/download-service.ts
  • libs/verified-pages/src/pages/pending-subscriptions/index.ts
  • libs/system-admin-pages/src/pages/blob-explorer-publications/index.test.ts
  • libs/postgres-prisma/prisma/schema/base.prisma
  • libs/publication/src/repository/queries.ts
  • libs/postgres-prisma/package.json
  • libs/system-admin-pages/src/list-type/queries.test.ts
  • libs/location/src/repository/queries.ts
  • libs/postgres-prisma/prisma/schema/location.prisma
  • libs/location/src/filtering/service.ts
  • libs/notifications/src/notification/subscription-queries.test.ts
  • apps/postgres/prisma/seed.ts
  • libs/publication/src/repository/queries.test.ts
  • libs/subscriptions/src/repository/service.test.ts
  • libs/subscriptions/src/validation/validation.ts
  • .claude/rules/backend.md
  • apps/postgres/package.json

Comment thread .claude/agents/full-stack-engineer.md
Comment thread .claude/agents/full-stack-engineer.md
Comment thread CLAUDE.md
Comment thread CLAUDE.md
Comment on lines 186 to +191
it("should return locations sorted alphabetically by name", async () => {
const results = await getAllLocations("en");

for (let i = 0; i < results.length - 1; i++) {
expect(results[i].name.localeCompare(results[i + 1].name)).toBeLessThanOrEqual(0);
}
// Verify results are returned (database orderBy handles sorting via collation)
expect(results.length).toBeGreaterThan(0);
expect(results.every((loc) => loc.name && loc.welshName)).toBe(true);

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 | 🟡 Minor | ⚡ Quick win

Restore deterministic sort verification in these sorting tests.

Line 186 and Line 194 say the results are alphabetically sorted, but Line 189-Line 191 and Line 197-Line 199 only check presence. This will pass even if ordering breaks. Assert the DB orderBy contract instead.

Suggested test adjustment
   it("should return locations sorted alphabetically by name", async () => {
     const results = await getAllLocations("en");

-    // Verify results are returned (database orderBy handles sorting via collation)
-    expect(results.length).toBeGreaterThan(0);
-    expect(results.every((loc) => loc.name && loc.welshName)).toBe(true);
+    expect(results.length).toBeGreaterThan(0);
+    expect(prisma.location.findMany).toHaveBeenCalledWith(
+      expect.objectContaining({
+        orderBy: { name: "asc" }
+      })
+    );
   });

   it("should return locations sorted alphabetically by Welsh name when language is cy", async () => {
     const results = await getAllLocations("cy");

-    // Verify results are returned (database orderBy handles sorting via collation)
-    expect(results.length).toBeGreaterThan(0);
-    expect(results.every((loc) => loc.name && loc.welshName)).toBe(true);
+    expect(results.length).toBeGreaterThan(0);
+    expect(prisma.location.findMany).toHaveBeenCalledWith(
+      expect.objectContaining({
+        orderBy: { welshName: "asc" }
+      })
+    );
   });

Also applies to: 194-199

@matt2415
matt2415 force-pushed the feat/prisma-rules-and-refactor branch from 736d5cf to 347aac2 Compare May 15, 2026 14:46
@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

@matt2415
matt2415 force-pushed the feat/prisma-rules-and-refactor branch from 5830b85 to c2bfa47 Compare May 21, 2026 18:22
@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment Successful 🚀

Your preview environment is ready:

The environment will be automatically cleaned up when this PR is closed.

matt2415 and others added 4 commits May 26, 2026 11:41
…est practises

feat: refactor claude prisma guidelines, schemas dir, and implement best practises
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Deduplicate yarn lockfile entries after rebase (std-env, opentelemetry packages, etc)
- Deduplicate yarn lockfile entries after rebase (std-env, opentelemetry packages, etc)
- Increase Helm timeout from 5m to 15m for complex deployments
- Prevents deployment timeouts when deploying 4 apps + PostgreSQL + Redis
…mcts/cath-service into feat/prisma-rules-and-refactor"

This reverts commit b21b895, reversing
changes made to abc95fc.
@matt2415
matt2415 force-pushed the feat/prisma-rules-and-refactor branch from ec71c69 to f218fee Compare May 26, 2026 10:41
Restored Redis sync calls that were accidentally removed during Prisma
optimization refactor. Maintains batch query performance improvement
(getLocationsByIds instead of N+1 getLocationById calls).

Changes:
- Re-added savePendingSubscriptions/deletePendingSubscriptions calls
- Re-added savePendingCaseSubscriptions/deletePendingCaseSubscriptions calls
- Added 9 missing tests for full coverage (27 tests vs 22 in master)
- Fixed TypeScript errors in test file
- All 236 tests passing

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@matt2415
matt2415 merged commit 67649e9 into master May 26, 2026
29 of 30 checks passed
@matt2415
matt2415 deleted the feat/prisma-rules-and-refactor branch May 27, 2026 10:26
alexbottenberg pushed a commit that referenced this pull request May 27, 2026
The timeout fix from e362e27 was lost as collateral when f218fee
reverted a merge commit. With the prisma-rules-and-refactor changes
(PR #618) making deployments heavier, the 5m timeout is insufficient
for deploying 4 apps + PostgreSQL + Redis.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants