Skip to content

feat(301): third-party user management - #458

Merged
junaidiqbalmoj merged 80 commits into
masterfrom
feature/301-third-party-user-management
Jul 8, 2026
Merged

feat(301): third-party user management#458
junaidiqbalmoj merged 80 commits into
masterfrom
feature/301-third-party-user-management

Conversation

@alexbottenberg

@alexbottenberg alexbottenberg commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Implements third-party user management for system admins ([VIBE-313] Third Party User Management - Future #301)
  • Adds create, view, delete flows for third-party users
  • Adds subscription management with LaunchDarkly-gated radio button UI (third-party-subscriptions-radio-buttons flag)
  • Fixes dotenv loading order in both servers so env vars are available at module initialisation time (fixes LaunchDarkly SDK key not being picked up)

Test plan

  • Log in as a system admin
  • Navigate to third-party users list
  • Create a new third-party user and verify confirmation page
  • View a user and manage their subscriptions
  • Enable the third-party-subscriptions-radio-buttons flag in LaunchDarkly — subscriptions page should show radio buttons instead of dropdowns
  • Delete a user and verify confirmation page
  • Run yarn test — all unit tests pass

🤖 Generated with Claude Code

Summary by CodeRabbit

New Features

  • Added comprehensive third-party user management system for System Admin users, including:
    • Multi-step user creation flow with name validation and confirmation
    • Subscription management with paginated interface and A/B tested UI variants (via feature flag)
    • User deletion with explicit confirmation and dependency handling
    • Complete Welsh language support across all admin pages
    • Audit logging for create, update, and delete actions
    • Accessibility compliance (WCAG 2.2 AA)

Tests

  • Added end-to-end test coverage for third-party user management workflows

@alexbottenberg alexbottenberg linked an issue Mar 20, 2026 that may be closed by this pull request
@coderabbitai

coderabbitai Bot commented Mar 20, 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

This PR introduces a complete third-party user management system for System Admin users, including database tables, a service layer, a multi-step web UI for creating/managing/deleting third-party users with paginated subscription configuration (A/B tested via LaunchDarkly), comprehensive E2E tests, and supporting infrastructure updates.

Changes

Third-Party User Database Schema and Service Layer

Layer / File(s) Summary
Database tables and Prisma schema
apps/postgres/prisma/migrations/20260318000000_add_third_party_user/migration.sql, libs/third-party-user/prisma/schema.prisma
PostgreSQL migration adds third_party_user and third_party_subscription tables with foreign keys and unique constraints; Prisma schema maps these models with bidirectional relations and cascade delete.
Core service API and name validation
libs/third-party-user/src/third-party-user-service.ts, libs/third-party-user/src/name-validation.ts, libs/third-party-user/src/index.ts, libs/third-party-user/src/third-party-user-service.test.ts, libs/third-party-user/src/name-validation.test.ts
Service layer provides findAll, findById, create (idempotent), updateSubscriptions (transactional), and delete functions; name validation enforces length/character constraints with error mapping for form rendering.
Package configuration and exports
libs/third-party-user/package.json, libs/third-party-user/src/config.ts, libs/third-party-user/tsconfig.json, tsconfig.json
ESM package exposes public API via main entry point and /config export; TypeScript path aliases wire the library into the root monorepo configuration.
Schema discovery integration
libs/postgres-prisma/src/schema-discovery.test.ts
Schema discovery updated to include the new third-party-user Prisma schema in the multi-schema discovery list.

Feature Flag Integration for Subscription UI

Layer / File(s) Summary
LaunchDarkly SDK wrapper
libs/system-admin-pages/src/feature-flags/launch-darkly.ts
Lazy-loading singleton client that evaluates boolean flags with a 5ms initialization timeout; returns false when SDK key is absent or initialization fails, enabling safe defaults.

User Listing and Creation Flow

Layer / File(s) Summary
List page and template
libs/system-admin-pages/src/pages/third-party-users/index.ts, libs/system-admin-pages/src/pages/third-party-users/index.njk, libs/system-admin-pages/src/pages/third-party-users/index.test.ts, libs/system-admin-pages/src/pages/third-party-users/en.ts, libs/system-admin-pages/src/pages/third-party-users/cy.ts
GET handler fetches and formats all users; template renders table with manage action links or empty state; English and Welsh translations included.
Create page (entry point)
libs/system-admin-pages/src/pages/third-party-users/create/index.ts, libs/system-admin-pages/src/pages/third-party-users/create/index.njk, libs/system-admin-pages/src/pages/third-party-users/create/index.test.ts, libs/system-admin-pages/src/pages/third-party-users/create/en.ts, libs/system-admin-pages/src/pages/third-party-users/create/cy.ts
GET renders form with optional session-backed name pre-fill; POST validates name, stores in session, and redirects to summary; language-aware routing via lngParam.
Create summary and confirmation
libs/system-admin-pages/src/pages/third-party-users/create/summary/index.ts, libs/system-admin-pages/src/pages/third-party-users/create/summary/index.njk, libs/system-admin-pages/src/pages/third-party-users/create/summary/index.test.ts, libs/system-admin-pages/src/pages/third-party-users/create/summary/en.ts, libs/system-admin-pages/src/pages/third-party-users/create/summary/cy.ts, libs/system-admin-pages/src/pages/third-party-users/create/confirmation/index.ts, libs/system-admin-pages/src/pages/third-party-users/create/confirmation/index.njk, libs/system-admin-pages/src/pages/third-party-users/create/confirmation/index.test.ts, libs/system-admin-pages/src/pages/third-party-users/create/confirmation/en.ts, libs/system-admin-pages/src/pages/third-party-users/create/confirmation/cy.ts
Summary GET validates session presence and renders review page; POST calls createThirdPartyUser, persists result to session (idempotent on re-submission), sets audit metadata, and redirects to confirmation. Confirmation page reads session data, clears it, and displays success message with created user name.

Subscription Management Flow

Layer / File(s) Summary
Subscription manage page (paginated)
libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/manage/index.ts, libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/manage/index.njk, libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/manage/index.test.ts, libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/manage/en.ts, libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/manage/cy.ts
GET initializes session-backed pending subscriptions, applies LaunchDarkly feature flag to select UI mode (radio buttons or dropdown), paginates list types (20 per page), and renders control state. POST updates session pending values for the current page, redirects to next page or persists all subscriptions via transaction if final page, then clears session and sets audit metadata.
Subscription success page
libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/success/index.ts, libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/success/index.njk, libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/success/index.test.ts, libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/success/en.ts, libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/success/cy.ts
GET handler selects language and renders success confirmation; used as redirect target after transactional subscription update.

User Management and Deletion Flow

Layer / File(s) Summary
Manage user page
libs/system-admin-pages/src/pages/third-party-users/[id]/manage/index.ts, libs/system-admin-pages/src/pages/third-party-users/[id]/manage/index.njk, libs/system-admin-pages/src/pages/third-party-users/[id]/manage/index.test.ts, libs/system-admin-pages/src/pages/third-party-users/[id]/manage/en.ts, libs/system-admin-pages/src/pages/third-party-users/[id]/manage/cy.ts
GET handler fetches user by id, computes subscription summary (unique sensitivity values or dash if empty), and renders management page with action buttons to manage subscriptions or delete.
Delete confirmation page
libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/index.ts, libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/index.njk, libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/index.test.ts, libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/en.ts, libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/cy.ts
GET renders confirmation form with yes/no radio and user name in title; POST validates radio selection, calls deleteThirdPartyUser on confirmation, sets audit metadata, and redirects to success page.
Delete success page
libs/system-admin-pages/src/pages/third-party-users/[id]/delete/success/index.ts, libs/system-admin-pages/src/pages/third-party-users/[id]/delete/success/index.njk, libs/system-admin-pages/src/pages/third-party-users/[id]/delete/success/index.test.ts, libs/system-admin-pages/src/pages/third-party-users/[id]/delete/success/en.ts, libs/system-admin-pages/src/pages/third-party-users/[id]/delete/success/cy.ts
GET handler renders success confirmation panel with navigation options back to manage another user or dashboard.

System Integration, Testing, and Infrastructure

Layer / File(s) Summary
System admin package wiring
libs/system-admin-pages/package.json
Added dependencies on @hmcts/third-party-user, @hmcts/list-types-common, and @launchdarkly/node-server-sdk (^9.7.0).
End-to-end test scenarios
e2e-tests/tests/system-admin/third-party-user-management.spec.ts, e2e-tests/utils/test-support-api.ts
E2E spec covers full journeys: create with validation/Welsh toggle/accessibility, manage subscriptions with optional feature-flag UI variant, and delete with confirmation. Test utilities provide API helpers for creating/fetching/deleting test users and subscriptions.
Documentation
docs/tickets/301/ticket.md, docs/tickets/301/plan.md, docs/tickets/301/tasks.md
Ticket specification, technical plan (including architecture, session handling, audit logging, error cases), and completed/remaining implementation tasks.
Post-write hook optimization
.claude/hooks/post-write.sh
Updated to read CLAUDE_FILE_PATHS and conditionally run Biome formatting/linting only on changed TypeScript files when paths are provided, with logging to run.log instead of console output and non-blocking failure handling.

Sequence Diagram(s)

sequenceDiagram
    actor Admin as System Admin
    participant UI as Create/Manage<br/>Pages
    participant Session as Express<br/>Session
    participant Service as Third-Party<br/>User Service
    participant DB as PostgreSQL
    participant LD as LaunchDarkly<br/>(Subscriptions)
    
    rect rgb(200, 150, 255, 0.5)
    Note over Admin,DB: Create Third-Party User Flow
    Admin->>UI: GET /third-party-users/create
    UI->>Session: Load stored name
    UI-->>Admin: Render create form
    
    Admin->>UI: POST name
    UI->>Service: validateName()
    Service-->>UI: Valid ✓
    UI->>Session: Store { name }
    UI-->>Admin: Redirect to /create/summary
    
    Admin->>UI: GET /create/summary
    UI->>Session: Fetch stored name
    UI-->>Admin: Render review page
    
    Admin->>UI: POST confirm
    UI->>Service: createThirdPartyUser(name)
    Service->>DB: INSERT third_party_user
    DB-->>Service: { id, name, createdAt }
    Service-->>UI: User created
    UI->>Session: Store { createdId, createdName }
    UI-->>Admin: Redirect to /create/confirmation
    
    Admin->>UI: GET /create/confirmation
    UI->>Session: Load createdName
    UI->>Session: Clear stored data
    UI-->>Admin: Render success + name
    end
    
    rect rgb(200, 150, 255, 0.5)
    Note over Admin,LD: Manage Subscriptions Flow
    Admin->>UI: GET /[id]/subscriptions/manage?page=1
    UI->>Service: findThirdPartyUserById(id)
    Service->>DB: SELECT user + subscriptions
    DB-->>Service: User + current subscriptions
    Service-->>UI: User data
    UI->>LD: isFeatureEnabled("subscription-ui-variant", userId)
    LD-->>UI: Use radio buttons (true) or dropdown (false)
    UI->>Session: Initialize { pending: {...} }
    UI-->>Admin: Render form with controls
    
    Admin->>UI: POST selected sensitivities (page 1)
    UI->>Session: Update pending values for page 1
    UI-->>Admin: Redirect to ?page=2 (next page)
    
    Admin->>UI: POST final page sensitivities
    UI->>Session: Update pending values for final page
    UI->>Service: updateThirdPartySubscriptions(userId, pending)
    Service->>DB: Transaction: DELETE old, INSERT new
    DB-->>Service: Updated
    Service-->>UI: Done
    UI->>Session: Clear pending state
    UI-->>Admin: Redirect to /subscriptions/success
    end
Loading

Possibly related PRs

  • hmcts/cath-service#316: Main PR's third-party user handlers emit req.auditMetadata for CREATE/UPDATE/DELETE actions, which are designed to be consumed by the audit-log schema and middleware introduced in this related PR.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/301-third-party-user-management

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.

@github-actions

github-actions Bot commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

🎭 Playwright E2E Test Results

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

Results for commit c4d70f6.

♻️ 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: 15

🧹 Nitpick comments (13)
libs/system-admin-pages/src/feature-flags/launch-darkly.ts (1)

14-18: Please avoid silent LaunchDarkly initialisation failures.

Line 16 swallows the error completely. Add a warning/error log (ideally once) so LD outages or bad SDK config are observable in production.

libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/confirmation/index.njk (1)

8-11: Prefer text over html for panel body content.

If panelBody is plain copy, render it with text to reduce XSS exposure from future content changes.

Suggested change
-    {{ govukPanel({
-      titleText: panelTitle,
-      html: panelBody
-    }) }}
+    {{ govukPanel({
+      titleText: panelTitle,
+      text: panelBody
+    }) }}
libs/system-admin-pages/src/pages/third-party-users/index.njk (1)

4-4: Unused import: govukBackLink macro.

The macro is imported but the backLink block uses a plain anchor tag instead. Remove the unused import for consistency.

🧹 Proposed fix
 {% from "govuk/components/table/macro.njk" import govukTable %}
-{% from "govuk/components/back-link/macro.njk" import govukBackLink %}
libs/system-admin-pages/src/pages/third-party-users/create/confirmation/index.njk (1)

3-3: Unused import: govukButton macro.

The button macro is imported but not used on this confirmation page. Remove to keep imports clean.

🧹 Proposed fix
 {% from "govuk/components/panel/macro.njk" import govukPanel %}
-{% from "govuk/components/button/macro.njk" import govukButton %}
libs/system-admin-pages/src/pages/third-party-users/create/index.njk (1)

5-5: Unused import: govukBackLink macro.

Same as other templates - the macro is imported but the backLink block uses a plain anchor. Remove for consistency.

🧹 Proposed fix
 {% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}
-{% from "govuk/components/back-link/macro.njk" import govukBackLink %}
libs/third-party-user/src/name-validation.ts (1)

2-2: ASCII regex limits names to basic Latin characters, inconsistent with potential international users.

The regex currently restricts names to ASCII letters (a–z, A–Z). Whilst this works for English and Welsh, if third-party users include those with accented characters (é, ñ, ü) or non-Latin scripts, names will be rejected. The codebase supports only English and Welsh locales currently, so this is not an immediate concern, but consider using Unicode-aware patterns (/^[\p{L}\p{N} '-]+$/u) if international character support becomes required.

libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/index.njk (2)

1-5: Missing error handling with govukErrorSummary.

The template imports govukRadios but doesn't use it (raw HTML radio inputs are used instead). More importantly, there's no govukErrorSummary import or usage for displaying validation errors. As per coding guidelines, Nunjucks templates should include error handling with govukErrorSummary.

Consider adding error handling:

{% from "govuk/components/error-summary/macro.njk" import govukErrorSummary %}

And conditionally render it when errors exist.


6-8: Consider using the govukBackLink macro.

The back link is implemented with a raw anchor element, but govukBackLink is imported and unused. Using the macro ensures consistent styling and behaviour.

♻️ Suggested change
 {% block backLink %}
-  <a href="/third-party-users/{{ userId }}{{ lngParam }}" class="govuk-back-link">{{ back }}</a>
+  {{ govukBackLink({
+    href: "/third-party-users/" + userId + lngParam,
+    text: back
+  }) }}
 {% endblock %}
libs/system-admin-pages/src/pages/third-party-users/[id]/index.ts (1)

29-29: Date locale is hardcoded regardless of language selection.

The date is formatted with "en-GB" locale even when Welsh (cy) is selected. Consider using the selected language for date formatting.

♻️ Suggested fix
-    createdAt: user.createdAt.toLocaleDateString("en-GB"),
+    createdAt: user.createdAt.toLocaleDateString(language === "cy" ? "cy-GB" : "en-GB"),
libs/system-admin-pages/src/pages/third-party-users/[id]/delete/index.test.ts (1)

24-51: Consider adding Welsh language test for getHandler.

The postHandler tests include Welsh parameter handling (line 116-128), but getHandler lacks a test verifying Welsh content rendering when req.query.lng === "cy".

libs/third-party-user/src/third-party-user-service.ts (1)

44-46: Consider handling non-existent user deletion gracefully.

prisma.delete throws PrismaClientKnownRequestError with code P2025 if the record doesn't exist. Depending on requirements, you may want to handle this case explicitly.

docs/tickets/301/tasks.md (1)

19-19: Incomplete task: CATH_LD_KEY environment variable configuration.

This task remains unchecked. Ensure the environment variable is documented in .env.example before merging, or track it as a follow-up issue.

Would you like me to open an issue to track adding CATH_LD_KEY to .env.example?

libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/index.test.ts (1)

142-185: Consider adding a test for pagination redirect.

The postHandler tests cover the final-page save scenario but don't verify the redirect to the next page when isLastPage is false. This is an important code path in the source handler (lines 90-93).

📝 Suggested test case
+    it("should redirect to next page when not on last page", async () => {
+      // Arrange
+      vi.mocked(findThirdPartyUserById).mockResolvedValue(mockUser as never);
+      req.session = { thirdPartySubscriptions: { userId: "user-1", pending: {} } } as never;
+      req.query = { page: "1" };
+      req.body = { CIVIL_DAILY_CAUSE_LIST: "PUBLIC" };
+      // Mock more list types to have multiple pages
+      vi.mocked(await import("@hmcts/list-types-common")).mockListTypes = Array(25).fill(mockUser.subscriptions[0]);
+
+      // Act
+      await postHandler(req as Request, res as Response);
+
+      // Assert
+      expect(res.redirect).toHaveBeenCalledWith("/third-party-users/user-1/subscriptions?page=2");
+    });

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c38d5512-3025-4a16-8ff4-05d82f7ec3f2

📥 Commits

Reviewing files that changed from the base of the PR and between 7ea04f2 and fbc3def.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (67)
  • .claude/hooks/post-write.sh
  • apps/api/src/server.ts
  • apps/postgres/prisma/migrations/20260318000000_add_third_party_user/migration.sql
  • apps/postgres/src/schema-discovery.ts
  • apps/web/package.json
  • apps/web/src/server.ts
  • docs/tickets/301/plan.md
  • docs/tickets/301/tasks.md
  • docs/tickets/301/ticket.md
  • e2e-tests/tests/third-party-user-management.spec.ts
  • libs/system-admin-pages/package.json
  • libs/system-admin-pages/src/feature-flags/launch-darkly.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/cy.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/cy.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/index.njk
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/index.test.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/index.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/cy.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/index.njk
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/index.test.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/index.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/index.njk
  • libs/system-admin-pages/src/pages/third-party-users/[id]/index.test.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/index.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/confirmation/cy.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/confirmation/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/confirmation/index.njk
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/confirmation/index.test.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/confirmation/index.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/cy.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/index.njk
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/index.test.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/index.ts
  • libs/system-admin-pages/src/pages/third-party-users/create/confirmation/cy.ts
  • libs/system-admin-pages/src/pages/third-party-users/create/confirmation/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/create/confirmation/index.njk
  • libs/system-admin-pages/src/pages/third-party-users/create/confirmation/index.test.ts
  • libs/system-admin-pages/src/pages/third-party-users/create/confirmation/index.ts
  • libs/system-admin-pages/src/pages/third-party-users/create/cy.ts
  • libs/system-admin-pages/src/pages/third-party-users/create/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/create/index.njk
  • libs/system-admin-pages/src/pages/third-party-users/create/index.test.ts
  • libs/system-admin-pages/src/pages/third-party-users/create/index.ts
  • libs/system-admin-pages/src/pages/third-party-users/create/summary/cy.ts
  • libs/system-admin-pages/src/pages/third-party-users/create/summary/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/create/summary/index.njk
  • libs/system-admin-pages/src/pages/third-party-users/create/summary/index.test.ts
  • libs/system-admin-pages/src/pages/third-party-users/create/summary/index.ts
  • libs/system-admin-pages/src/pages/third-party-users/cy.ts
  • libs/system-admin-pages/src/pages/third-party-users/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/index.njk
  • libs/system-admin-pages/src/pages/third-party-users/index.test.ts
  • libs/system-admin-pages/src/pages/third-party-users/index.ts
  • libs/third-party-user/package.json
  • libs/third-party-user/prisma/schema.prisma
  • libs/third-party-user/src/config.ts
  • libs/third-party-user/src/index.ts
  • libs/third-party-user/src/name-validation.test.ts
  • libs/third-party-user/src/name-validation.ts
  • libs/third-party-user/src/third-party-user-service.test.ts
  • libs/third-party-user/src/third-party-user-service.ts
  • libs/third-party-user/tsconfig.json
  • tsconfig.json

Comment on lines +42 to +57
# Filter to only TypeScript/JavaScript files (skip .njk, .json, .prisma, .sh, etc.)
TS_FILES=""
while IFS= read -r f; do
case "$f" in
*.ts|*.tsx|*.js|*.jsx)
if [ -f "$f" ]; then
TS_FILES="$TS_FILES $f"
fi
;;
esac
done <<< "$FILES_TO_CHECK"

if [ -z "$TS_FILES" ]; then
log_hook "No TS/JS files to check"
exit 0
fi

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

Paths with spaces will break due to word-splitting.

The $TS_FILES variable is built by concatenation and later expanded unquoted (lines 63, 67). Filenames containing spaces will be incorrectly split.

🛠️ Suggested fix using an array
-# Filter to only TypeScript/JavaScript files (skip .njk, .json, .prisma, .sh, etc.)
-TS_FILES=""
-while IFS= read -r f; do
-    case "$f" in
-        *.ts|*.tsx|*.js|*.jsx)
-            if [ -f "$f" ]; then
-                TS_FILES="$TS_FILES $f"
-            fi
-            ;;
-    esac
-done <<< "$FILES_TO_CHECK"
-
-if [ -z "$TS_FILES" ]; then
-    log_hook "No TS/JS files to check"
-    exit 0
-fi
+# Filter to only TypeScript/JavaScript files (skip .njk, .json, .prisma, .sh, etc.)
+TS_FILES=()
+while IFS= read -r f; do
+    case "$f" in
+        *.ts|*.tsx|*.js|*.jsx)
+            if [ -f "$f" ]; then
+                TS_FILES+=("$f")
+            fi
+            ;;
+    esac
+done <<< "$FILES_TO_CHECK"
+
+if [ ${`#TS_FILES`[@]} -eq 0 ]; then
+    log_hook "No TS/JS files to check"
+    exit 0
+fi

Then update the biome invocations:

-if ! $BIOME_BIN format --write $TS_FILES 2>&1; then
+if ! "$BIOME_BIN" format --write "${TS_FILES[@]}" 2>&1; then
     log_hook "Format had issues (non-blocking)"
 fi

-if ! $BIOME_BIN check --write $TS_FILES 2>&1; then
+if ! "$BIOME_BIN" check --write "${TS_FILES[@]}" 2>&1; then
     log_hook "Lint had issues (non-blocking)"
 fi

Comment thread docs/tickets/301/plan.md
Comment thread docs/tickets/301/tasks.md
Comment on lines +84 to +85
- LaunchDarkly flag key: `third-party-subscriptions-radio-buttons` (false = dropdown, true = radio buttons)
- `CATH_LD_KEY` environment variable must be set for LaunchDarkly to function; the feature flag defaults to `false` (radio button variant) when unavailable.

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

Same inconsistency as in ticket.md regarding feature flag default.

Line 84 says false = dropdown, but line 85 says it defaults to "radio button variant". Please align with the correction in ticket.md.

Comment thread docs/tickets/301/ticket.md
Comment thread e2e-tests/tests/system-admin/third-party-user-management.spec.ts
Comment thread libs/third-party-user/package.json
Comment on lines +10 to +17
model ThirdPartyUser {
id String @id @default(cuid())
name String @db.VarChar(255)
createdAt DateTime @default(now()) @map("created_at")
subscriptions ThirdPartySubscription[]

@@map("third_party_user")
}

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

Consider adding a unique constraint on name.

Without a unique constraint, the idempotent create logic in third-party-user-service.ts is vulnerable to race conditions, potentially creating duplicate users with the same name.

♻️ Suggested change
 model ThirdPartyUser {
   id            String                   `@id` `@default`(cuid())
-  name          String                   `@db.VarChar`(255)
+  name          String                   `@unique` `@db.VarChar`(255)
   createdAt     DateTime                 `@default`(now()) `@map`("created_at")
   subscriptions ThirdPartySubscription[]

   @@map("third_party_user")
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
model ThirdPartyUser {
id String @id @default(cuid())
name String @db.VarChar(255)
createdAt DateTime @default(now()) @map("created_at")
subscriptions ThirdPartySubscription[]
@@map("third_party_user")
}
model ThirdPartyUser {
id String `@id` `@default`(cuid())
name String `@unique` `@db.VarChar`(255)
createdAt DateTime `@default`(now()) `@map`("created_at")
subscriptions ThirdPartySubscription[]
@@map("third_party_user")
}

Comment thread libs/third-party-user/tsconfig.json Outdated
@sonarqubecloud

Copy link
Copy Markdown

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

🧹 Nitpick comments (2)
e2e-tests/utils/test-support-api.ts (1)

535-537: Remove the redundant cast in the name lookup.

find() already returns ThirdPartyUserRecord | undefined; the explicit cast is unnecessary and weakens type-safety if the return shape changes.

Proposed tidy-up
 export async function findTestThirdPartyUserByName(name: string): Promise<ThirdPartyUserRecord | null> {
   const users = await getTestThirdPartyUsers();
-  return (users.find((u) => u.name === name) as ThirdPartyUserRecord) || null;
+  return users.find((u) => u.name === name) ?? null;
 }
e2e-tests/tests/system-admin/third-party-user-management.spec.ts (1)

135-137: Prefer accessible locators for radio controls.

Using raw CSS selectors for radios is brittle; use getByRole/getByLabel for stability and accessibility alignment.

As per coding guidelines "E2E tests should ... use getByRole() first, getByLabel() for inputs, getByText() for text, and getByTestId() as last resort."

Also applies to: 195-196, 203-204


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 657a35b0-1393-44b0-a7dc-85558d882519

📥 Commits

Reviewing files that changed from the base of the PR and between 5d9bbc9 and f630276.

📒 Files selected for processing (2)
  • e2e-tests/tests/system-admin/third-party-user-management.spec.ts
  • e2e-tests/utils/test-support-api.ts

Comment thread e2e-tests/tests/system-admin/third-party-user-management.spec.ts Outdated
@@ -0,0 +1,9 @@
export const cy = {

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.

Move all the files with in confirmation folder to "success" because it is a success page,

@@ -0,0 +1,9 @@
export const en = {

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.

Move all the page within "delete" to "confirmation" because it is a confirmation screen.

@@ -0,0 +1,7 @@
export const en = {

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.

same here. this is success page for subscription. move this to success folder.

@@ -0,0 +1,22 @@
export const en = {

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.

This is manage subscription page where it shows all the lists, not "confirmation"

@@ -0,0 +1,13 @@
export const en = {

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.

This is manage user screen page, move this to manage user folder.

@@ -0,0 +1,12 @@
export const en = {
pageTitle: "Manage third party users",

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.

move all these files to "manage"

CREATE TABLE "third_party_subscription" (
"id" TEXT NOT NULL,
"third_party_user_id" TEXT NOT NULL,
"list_type" VARCHAR(100) NOT NULL,

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.

This will be list_type id, we have list_type table, so this will be foreign key to list_type table.

@@ -0,0 +1,24 @@
-- CreateTable

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.

oauth confirmation table is missing completly.

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

This story completely missing Oauth configuration for the subscriber which we need to connect with third party.

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

It is also missing connection with newly created KV for third party. How CaTH AI will connect with KV (on local, it can use az login, but for lower environment, it needs to use managed identity)

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

🧹 Nitpick comments (2)
libs/system-admin-pages/src/pages/third-party-users/[id]/delete/success/index.ts (1)

8-17: 💤 Low value

Remove unnecessary async marker.

The getHandler function contains no await operations and performs only synchronous work. The async keyword is unnecessary and misleading.

♻️ Proposed fix
-export const getHandler = async (req: Request, res: Response) => {
+export const getHandler = (req: Request, res: Response) => {
   const language: Language = req.query.lng === "cy" ? "cy" : "en";
   const t = language === "cy" ? cy : en;
   const lngParam = language === "cy" ? "?lng=cy" : "";
libs/system-admin-pages/src/pages/third-party-users/[id]/delete/index.ts (1)

42-44: 💤 Low value

Consider extracting duplicate language logic.

The language-detection logic (lines 42-44) is identical to lines 28-30. Extracting to a helper function would reduce duplication.

♻️ Proposed refactor
+function getLanguageContext(req: Request) {
+  const language: Language = req.query.lng === "cy" ? "cy" : "en";
+  const t = language === "cy" ? cy : en;
+  const lngParam = language === "cy" ? "?lng=cy" : "";
+  return { language, t, lngParam };
+}
+
 export const getHandler = async (req: Request, res: Response) => {
-  const language: Language = req.query.lng === "cy" ? "cy" : "en";
-  const t = language === "cy" ? cy : en;
-  const lngParam = language === "cy" ? "?lng=cy" : "";
+  const { t, lngParam } = getLanguageContext(req);
   const { id } = req.params;

Apply similar changes to postHandler.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 44ab2031-b551-40af-af93-370a0f27f63c

📥 Commits

Reviewing files that changed from the base of the PR and between f630276 and a695cf2.

📒 Files selected for processing (9)
  • e2e-tests/tests/system-admin/third-party-user-management.spec.ts
  • libs/postgres-prisma/src/schema-discovery.test.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/index.test.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/index.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/success/cy.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/success/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/success/index.njk
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/success/index.test.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/success/index.ts
✅ Files skipped from review due to trivial changes (2)
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/success/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/success/cy.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/index.test.ts
  • e2e-tests/tests/system-admin/third-party-user-management.spec.ts

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

♻️ Duplicate comments (3)
libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/cy.ts (1)

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

Include the user name in the Welsh delete title for parity and clarity.

Line 2 ignores name, so the confirmation text is less specific than the English flow.

Proposed change
-  pageTitle: (_name: string) => "Ydych chi'n siŵr eich bod eisiau dileu defnyddiwr?",
+  pageTitle: (name: string) => `Ydych chi'n siŵr eich bod eisiau dileu ${name}?`,
libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/index.njk (1)

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

Switch the back link to govukBackLink.

The template imports the macro but bypasses it with a manual anchor.

As per coding guidelines, "Nunjucks templates must extend layouts/base-template.njk, use govuk macros from govuk/components, and include error handling with govukErrorSummary".

libs/system-admin-pages/src/pages/third-party-users/[id]/manage/index.njk (1)

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

Use govukBackLink for the back navigation.

Line 7 uses a hard-coded anchor despite importing the GOV.UK macro.

As per coding guidelines, "Nunjucks templates must extend layouts/base-template.njk, use govuk macros from govuk/components, and include error handling with govukErrorSummary".

🧹 Nitpick comments (3)
libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/index.ts (1)

62-70: ⚡ Quick win

Consider wrapping delete operation in try/catch.

If deleteThirdPartyUser throws an exception (e.g., database failure), the audit metadata won't be set and the user will see a generic error page. Explicit error handling would allow you to log the failed attempt and show a more helpful error message.

🛡️ Proposed error handling
+ try {
    await deleteThirdPartyUser(id);
-
+  } catch (error) {
+    req.auditMetadata = {
+      shouldLog: true,
+      action: "DELETE_THIRD_PARTY_USER_FAILED",
+      entityInfo: `Name: ${user.name}, ID: ${id}, Error: ${error.message}`
+    };
+    throw error;
+  }
+
  req.auditMetadata = {
    shouldLog: true,
    action: "DELETE_THIRD_PARTY_USER",
    entityInfo: `Name: ${user.name}, ID: ${id}`
  };

  res.redirect(`/third-party-users/${id}/delete/success${lngParam}`);
libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/manage/index.ts (2)

46-46: 💤 Low value

Unnecessary fallback for feature flag evaluation.

Since this route is protected by requireRole([USER_ROLES.SYSTEM_ADMIN]) (line 116), req.user will always be defined. The ?? "anonymous" fallback is defensive but unnecessary.

♻️ Simplification
- const useDropdown = !(await isFeatureEnabled(LD_FLAG_RADIO_BUTTONS, req.user?.id ?? "anonymous"));
+ const useDropdown = !(await isFeatureEnabled(LD_FLAG_RADIO_BUTTONS, req.user.id));

103-113: ⚡ Quick win

Add error handling for subscription update operation.

If updateThirdPartySubscriptions fails (e.g., database error), the audit metadata on line 107 would still record a successful update, which is misleading. Wrap the update in try/catch to handle errors appropriately and log failed attempts.

🛡️ Proposed error handling
+ try {
    await updateThirdPartySubscriptions(id, session.thirdPartySubscriptions.pending);
+  } catch (error) {
+    req.auditMetadata = {
+      shouldLog: true,
+      action: "UPDATE_THIRD_PARTY_SUBSCRIPTIONS_FAILED",
+      entityInfo: `User: ${user.name}, Error: ${error.message}`
+    };
+    throw error;
+  }

  delete session.thirdPartySubscriptions;

  req.auditMetadata = {
    shouldLog: true,
    action: "UPDATE_THIRD_PARTY_SUBSCRIPTIONS",
    entityInfo: `User: ${user.name}, Before: [${beforeSubscriptions}], After: [${afterSubscriptions}]`
  };

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 78eff35f-90b9-4637-90c0-fc0b8cf37294

📥 Commits

Reviewing files that changed from the base of the PR and between a695cf2 and a5b9e82.

📒 Files selected for processing (27)
  • apps/postgres/prisma/migrations/20260318000000_add_third_party_user/migration.sql
  • e2e-tests/tests/system-admin/third-party-user-management.spec.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/cy.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/index.njk
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/index.test.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/index.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/manage/cy.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/manage/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/manage/index.njk
  • libs/system-admin-pages/src/pages/third-party-users/[id]/manage/index.test.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/manage/index.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/manage/cy.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/manage/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/manage/index.njk
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/manage/index.test.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/manage/index.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/success/cy.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/success/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/success/index.njk
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/success/index.test.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/success/index.ts
  • libs/system-admin-pages/src/pages/third-party-users/index.njk
  • libs/third-party-user/package.json
  • libs/third-party-user/prisma/schema.prisma
  • libs/third-party-user/src/third-party-user-service.test.ts
  • libs/third-party-user/src/third-party-user-service.ts
✅ Files skipped from review due to trivial changes (9)
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/success/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/success/index.njk
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/manage/cy.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/manage/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/success/index.test.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/success/index.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/delete/confirmation/en.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/manage/cy.ts
  • libs/system-admin-pages/src/pages/third-party-users/[id]/subscriptions/success/cy.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • libs/system-admin-pages/src/pages/third-party-users/index.njk
  • libs/third-party-user/prisma/schema.prisma
  • libs/third-party-user/src/third-party-user-service.ts
  • e2e-tests/tests/system-admin/third-party-user-management.spec.ts
  • libs/third-party-user/src/third-party-user-service.test.ts


type Language = "en" | "cy";

export const getHandler = async (req: Request, res: Response) => {

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.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Avoid exporting getHandler if it is only used for tests.

Keep getHandler module-private and test behaviour via the exported GET chain (or a dedicated internal test helper) to avoid expanding the public module surface.

As per coding guidelines, "Only export functions intended for use outside the module - do not export functions solely to test them."

Comment on lines +6 to +8
{% block backLink %}
<a href="/third-party-users/{{ userId }}/manage{{ lngParam }}" class="govuk-back-link">{{ back }}</a>
{% endblock %}

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

Use the GOV.UK back-link macro instead of a hard-coded anchor.

This keeps the template consistent with component usage rules and the imported govukBackLink.

Proposed change
 {% block backLink %}
-  <a href="/third-party-users/{{ userId }}/manage{{ lngParam }}" class="govuk-back-link">{{ back }}</a>
+  {{ govukBackLink({
+    text: back,
+    href: "/third-party-users/" + userId + "/manage" + lngParam
+  }) }}
 {% endblock %}

As per coding guidelines, "Nunjucks templates must extend layouts/base-template.njk, use govuk macros from govuk/components, and include error handling with govukErrorSummary".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{% block backLink %}
<a href="/third-party-users/{{ userId }}/manage{{ lngParam }}" class="govuk-back-link">{{ back }}</a>
{% endblock %}
{% block backLink %}
{{ govukBackLink({
text: back,
href: "/third-party-users/" + userId + "/manage" + lngParam
}) }}
{% endblock %}

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

Adds ticket, plan, and tasks documentation for issue #301 covering
the full CRUD workflow for third-party users including LaunchDarkly
A/B testing of the subscriptions UI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
dotenv is not declared as a production dependency in apps/api or apps/web,
causing ERR_MODULE_NOT_FOUND crash in Docker containers on startup.
Production env vars are injected by Kubernetes — no dotenv needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@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.

junaidiqbalmoj and others added 2 commits June 18, 2026 13:20
Resolved conflicts by taking master's removal of channel/sensitivity
from legacy third-party subscriptions (PR #691) and adopting the `t`
variable naming convention and `{% block content %}` template pattern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove AuditLogAction override from mock so the real enum value
  "Update third party subscriptions" is used in the assertion
- Fix Biome formatting: inline the subscriptions array on one line

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@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.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 1, 2026

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.

…Key Vault env wiring

- Change ThirdPartyUser and ThirdPartySubscription primary keys from CUID text to UUID
- Add migration to convert existing columns to UUID type (truncates dev data)
- Remove redundant duplicate third_party_secret migration files
- Update all affected tests to use UUID-format mock IDs
- Fix THIRD_PARTY_KEY_VAULT env var not being loaded by web dev scripts by adding
  --env-file-if-exists=../../.env to tsx invocations (matching API app pattern)
- Add THIRD_PARTY_KEY_VAULT to Helm values (dev and pipeline) so deployed environments
  also have the vault name injected into process.env
- Remove stale docs/tickets/VIBE-169 directory

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 1, 2026

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.

junaidiqbalmoj and others added 4 commits July 3, 2026 16:33
Merged sscs-daily-hearing-list, utiac-jr, utiac-statutory-appeal, and
magistrates-standard-list modules from master into the feature branch.
Regenerated Prisma client to expose ThirdPartyUser, ThirdPartySecret,
and ThirdPartySubscription models added in this feature branch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Includes updates to shared list-type utilities, location data, publication
processing, notification service, audit log, test-support regions, and
package dependency changes brought in from master.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ject.properties

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 3, 2026

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.

@sonarqubecloud

sonarqubecloud Bot commented Jul 6, 2026

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Jul 6, 2026

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.

@junaidiqbalmoj
junaidiqbalmoj merged commit b5b6c81 into master Jul 8, 2026
26 checks passed
hmctsclaudecode Bot pushed a commit that referenced this pull request Jul 9, 2026
10 STATUS + IMPL changes (closed issue + merged closing PR → verified):
  REQ-0078 (#301): implemented → verified (PR #458)
  REQ-0105 (#428): in_progress  → verified (PR #749)
  REQ-0106 (#429): approved     → verified (PR #761)
  REQ-0107 (#431): implemented → verified (PR #701)
  REQ-0108 (#434): approved     → verified (PR #772)
  REQ-0109 (#436): implemented → verified (PR #727)
  REQ-0112 (#467): implemented → verified (PR #670)
  REQ-0124 (#563): approved     → verified (PR #782)
  REQ-0135 (#569): in_progress  → verified (PR #748)
  REQ-0137 (#729): approved     → verified (PR #766)

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.

[VIBE-313] Third Party User Management - Future

6 participants