Skip to content

feat: UT non-strategic publishing (UTCC, UTLC, UTAAC) #425 - #669

Merged
junaidiqbalmoj merged 55 commits into
masterfrom
feature/425-ut-non-strategic-publishing-clean
Jul 9, 2026
Merged

feat: UT non-strategic publishing (UTCC, UTLC, UTAAC) #425#669
junaidiqbalmoj merged 55 commits into
masterfrom
feature/425-ut-non-strategic-publishing-clean

Conversation

@alexbottenberg

@alexbottenberg alexbottenberg commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds non-strategic list type support for Upper Tribunal Tax and Chancery Chamber (UTCC), Upper Tribunal Lands Chamber (UTLC), and Upper Tribunal Administrative Appeals Chamber (UTAAC)
  • Each module follows the Care Standards Tribunal pattern with Excel converter config, JSON schema, TypeScript types, renderer, PDF generator, email summary builder, page controller, and Nunjucks templates
  • Integrates all three list types into the PDF generator registry, email builder registry, style guide page routing, and location/list-type seed data

What's included

  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/ — UTCC module (list type ID 28, National region)
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/ — UTLC module (list type ID 29, National region)
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/ — UTAAC module (list type ID 30, London region, landscape PDF)
  • Location data: new National region (ID 7), 3 sub-jurisdictions (IDs 10–12), 3 virtual locations (IDs 13–15)
  • Non-strategic upload form updated to register all three converter configs on load
  • Welsh translations for all three list type pages
  • JSON schemas aligned with converter configs: only time, caseReference/caseReferenceNumber, and caseName are required; all other fields optional

Test plan

  • Upload a valid UTCC/UTLC/UTAAC Excel file via the non-strategic upload form and verify the style guide page renders correctly
  • Upload an Excel file missing optional columns (judges, members, venue) and verify it is accepted
  • Upload an Excel file missing a required column (time, caseReference, caseName) and verify a validation error is shown
  • View style guide page with ?lng=cy and verify Welsh translations display
  • Verify PDF download works for all three list types
  • Verify UTAAC PDF renders in landscape orientation
  • Run unit tests: yarn test

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added support for three new Upper Tribunal daily hearing lists, including new pages, PDFs, email summaries, and downloadable files.
    • Added Welsh and English user-facing content for the new list pages and upload flows.
  • Bug Fixes
    • Improved list data handling so hearing lists and related lookups are populated more reliably.
    • Updated file download handling to return clearer responses for invalid, missing, or expired PDFs.

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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 three new Upper Tribunal daily hearing list modules (Tax and Chancery Chamber, Lands Chamber, Administrative Appeals Chamber), each with converters, JSON schemas, validators, renderers, email summaries, PDF generators, locales, and web pages. It adds shared PDF generator infrastructure, updates reference/seed data, wires the modules into publication, notification, and web app registries, and adds a public PDF download route.

Changes

Upper Tribunal daily hearing list publishing

Layer / File(s) Summary
Issue specification and task checklist
docs/tickets/425/*
Adds ticket, plan, and task documentation for the UTCC/UTLC/UTAAC implementation.
Shared Excel conversion and PDF utilities
libs/list-types/common/src/conversion/excel-to-json.ts, libs/list-types/common/src/index.ts, libs/list-types/common/src/pdf/pdf-utilities.ts, libs/list-types/upper-tribunal-common/*
Fixes optional/required field handling in Excel-to-JSON conversion, exports PdfFromHtmlResult, and introduces a shared createUtDailyHearingListPdfGenerator factory with tests.
Reference data, seeding, and startup
libs/location/src/list-type-data.ts, libs/location/src/seed-data.ts, apps/postgres/prisma/seed.ts, apps/postgres/prisma.config.ts, apps/postgres/start.sh, .yarnrc.yml
Adds three list-type entries and sub-jurisdictions, always upserts location reference rows, seeds ListSearchConfig rows, adjusts DB connect timeout and migration startup handling.
Non-strategic upload sensitivity map and Welsh copy
apps/web/src/pages/(admin)/non-strategic-upload*
Adds a listTypeSensitivityMap to the upload form/controller and replaces Welsh placeholder text with finalized translations.
UTCC list module
libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/*
Adds the full Tax and Chancery Chamber module: config, converter, schema, models, validator, renderer, email summary, PDF generator/template, locales, and tests.
UTLC list module
libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/*
Adds the full Lands Chamber module mirroring the UTCC structure with mode-of-hearing field support.
UTAAC list module
libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/*
Adds the full Administrative Appeals Chamber module with appellant/case-reference fields and landscape PDF layout.
Web page controllers, templates, and app wiring
apps/web/src/pages/(list-types)/upper-tribunal-*, apps/web/src/app.ts, apps/web/src/app.test.ts, apps/web/package.json
Adds GET handlers via createSimpleListTypeHandler, Nunjucks page templates, registers module roots in configureGovuk, and adds workspace dependencies.
Publication, notification, and PDF download integration
libs/publication/src/processing/service.ts, libs/notifications/src/notification/notification-service.ts, libs/public-pages/src/routes/pdf/[artefactId]/download.ts, libs/publication/package.json, libs/notifications/package.json, tsconfig.json
Registers new list types in the PDF generator and email builder registries, adds a public PDF download route with UUID/display-window validation, and adds path aliases/dependencies.

Sequence Diagram(s)

sequenceDiagram
    participant Browser
    participant WebController as "UT Page GET Handler"
    participant Validator as "JSON Validator"
    participant Publication as "Publication Store"
    participant Renderer as "renderUt*DailyHearingListData"
    participant Template as "Nunjucks Template"

    Browser->>WebController: GET /upper-tribunal-*-daily-hearing-list?artefactId
    WebController->>Publication: getArtefactById(artefactId)
    Publication-->>WebController: artefact
    WebController->>Publication: getPublicationJson(artefactId)
    Publication-->>WebController: jsonData
    WebController->>Validator: validate(jsonData)
    Validator-->>WebController: isValid
    WebController->>Renderer: render(jsonData, options)
    Renderer-->>WebController: header, hearings
    WebController->>Template: res.render(view, header, hearings, dataSource, pdfDownloadUrl)
    Template-->>Browser: Rendered HTML page
Loading
sequenceDiagram
    participant Publisher as "Publication Processor"
    participant PdfRegistry as "PDF_GENERATOR_REGISTRY"
    participant Generator as "generateUt*DailyHearingListPdf"
    participant Renderer as "renderUt*DailyHearingListData"
    participant PdfEngine as "generatePdfFromHtml"
    participant Storage as "Azure Blob Storage"

    Publisher->>PdfRegistry: lookup(listTypeName)
    PdfRegistry-->>Publisher: generateUt*DailyHearingListPdf
    Publisher->>Generator: generatePdf(jsonData, options)
    Generator->>Renderer: render(hearingList, options)
    Renderer-->>Generator: header, hearings
    Generator->>PdfEngine: generatePdfFromHtml(html)
    PdfEngine-->>Generator: pdfBuffer, sizeBytes
    Generator->>Storage: uploadBlob(artefactId, pdfBuffer)
    Storage-->>Generator: success
    Generator-->>Publisher: pdfPath, sizeBytes, exceedsMaxSize
Loading

Possibly related issues

  • hmcts/cath-service#610: Implements the same UT AAC/Lands/Tax & Chancery daily hearing list modules described in this issue, including configs, schemas, renderers, pages, and registration wiring.
  • Style Guide: Tribunal non-strategic publishing - UTCC, UTLC & UTAAC #425: Implements the exact UTCC/UTLC/UTAAC non-strategic publishing scope described in this ticket, including schemas, PDF/email summaries, and web/list wiring.

Possibly related PRs

  • hmcts/cath-service#772: Both PRs extend PDF_GENERATOR_REGISTRY and EMAIL_BUILDER_REGISTRY to route new tribunal list types to their PDF/email generator functions.
  • hmcts/cath-service#320: Both PRs extend libs/publication/src/processing/service.ts to register new PDF generators into the same publication processing machinery.
  • hmcts/cath-service#749: Both PRs extend libs/list-types/common/src/pdf/pdf-utilities.ts and wire new non-strategic hearing-list modules into the web app.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarises the main change: non-strategic publishing support for the three UT list types.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/425-ut-non-strategic-publishing-clean

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 Jun 2, 2026

Copy link
Copy Markdown
Contributor

🎭 Playwright E2E Test Results

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

Results for commit 08d5738.

♻️ This comment has been updated with latest results.

abottenberg and others added 11 commits June 16, 2026 12:01
Creates three new list type modules for the Upper Tribunal (Tax and
Chancery Chamber), Upper Tribunal (Lands Chamber) and Upper Tribunal
(Administrative Appeals Chamber) daily hearing lists, enabling
publication through the non-strategic upload route.

Each module includes a JSON validation schema, Excel converter, renderer,
PDF generator, email summary builder, page controller, Nunjucks template
and English/Welsh content. Integration points updated in list-type-data,
location-data, PDF_GENERATOR_REGISTRY, EMAIL_BUILDER_REGISTRY, app.ts
and the seed script.

Fixes seed-data.ts to upsert sub-jurisdictions on existing databases
before seeding list types, so new sub-jurisdictions are propagated
without requiring a full database reset.

Closes #425

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

- Relax required constraints on UTAAC/UTLC/UTCC Excel config fields so rows with empty optional columns don't fail validation
- Fix excel-to-json header detection to use parsed headers rather than derived object keys
- Fix getField to return empty string for missing optional columns rather than throwing
- Add PDF download route for public artefact serving
- Add json-validator exports for UT list types
- Register UT list type converters in non-strategic-upload page
- Add devcontainer port forwarding and cross-platform yarn architecture support

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

When a UTCC, UTLC, or UTAAC list type is selected in the non-strategic
upload form, the sensitivity field now automatically defaults to Public
via the existing list-type-sensitivity JS mechanism.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces [Welsh] placeholders with proper Welsh translations sourced
from the existing manual-upload Welsh translations, which cover the
same fields and error messages.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Align JSON schemas with converter configs: only time, caseReference/caseReferenceNumber, and caseName are required fields for UTCC, UTLC, and UTAAC (judges, members, hearingType, venue etc are optional)
- Mark optional fields as optional (?) in UtccHearing, UtlcHearing, and UtaacHearing TypeScript interfaces
- Add Welsh translations for all three UT list type pages (replace [TRANSLATE: ...] placeholders)
- Remove inline <style> blocks from all three Nunjucks templates; use govuk-!-margin-top-7 utility class instead
- Replace any types in non-strategic-upload/index.ts with proper types (unknown, Record<string, string>, Session, typed option array)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds json-validator tests, converter config tests, and additional
page controller and pdf-generator cases to bring all three modules
above 80% coverage on all metrics (~98% statements, ~85% branches).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The three UT pdf-generator files were identical except for courtName,
listTitle, renderer function, and hearing list type. Introduces
createDailyHearingListPdfGenerator in @hmcts/list-types-common and
replaces each file with a single-call wrapper, eliminating the
duplication flagged by the quality gate.

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

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

Replaces all [TRANSLATE: ...] placeholders with Welsh text across:
- UTCC, UTLC and UTAAC cy.ts page translation files
- location-data.ts: location names, sub-jurisdiction names and National region
- list-type-data.ts: welshFriendlyName for all three list types

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The always-run seed path only upserted sub-jurisdictions and list types,
so Welsh names on locations (e.g. locationIds 13–15) were never applied
to an existing database. Adds locations to the always-upsert block so
Welsh name changes take effect without a full re-seed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@junaidiqbalmoj
junaidiqbalmoj force-pushed the feature/425-ut-non-strategic-publishing-clean branch from f7f3d8c to 41cb3d4 Compare June 16, 2026 11:11

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

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (4)
libs/location/src/list-type-data.ts-323-323 (1)

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

Normalise user-facing title casing in englishFriendlyName.

These new labels use Daily Hearing list (lowercase list), which is inconsistent with existing naming and likely to surface in UI/admin content. Use Daily Hearing List for consistency.

Also applies to: 335-335, 347-347

apps/postgres/prisma/seed.ts-234-238 (1)

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

upsert currently cannot correct stale listSearchConfig rows.

Line 237 uses update: {}, so reruns do not repair existing records if field mappings ever change. Populate update with caseNumberFieldName and caseNameFieldName to keep seeds idempotent and self-healing.

libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/pdf/pdf-template.njk-2-2 (1)

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

Template language is fixed to English.

The root lang attribute is always en; Welsh-rendered documents should expose the active locale in markup for accessibility tooling and correct language metadata.

libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/pages/index.ts-62-63 (1)

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

Treat malformed JSON as invalid list data (400), not server failure (500).

A JSON.parse failure currently falls to the outer catch and returns 500. That is a client/data validation outcome and should map to the same invalid-data path as schema failures.

Also applies to: 95-103

🧹 Nitpick comments (12)
libs/list-types/common/src/conversion/excel-to-json.test.ts (1)

83-98: ⚡ Quick win

Add a regression test for a missing optional header column.

Current coverage still misses the key contract: a sheet should pass when a non-required column is absent from the header row. Please add this case to lock in optional-header behaviour.

libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/rendering/renderer.ts (1)

4-20: ⚡ Quick win

Reorder exports to match the TypeScript module ordering convention.

RenderOptions and RenderedData are declared before exported function declarations. Move interfaces/types to the bottom, after exported functions, to keep module structure consistent.

As per coding guidelines, "**/*.ts: Order module exports: top-level constants first, then exported functions, then other functions ordered by usage, with interfaces and types at the bottom".

Also applies to: 22-47

Source: Coding guidelines

libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/pages/index.test.ts (1)

98-98: ⚡ Quick win

Replace repeated as any casts with a typed artefact fixture.

The as any casts weaken compile-time contract checks in these tests and can hide shape regressions in controller dependencies.

As per coding guidelines, "**/*.{ts,tsx}: Enable TypeScript strict mode and avoid any type without justification".

Also applies to: 170-170, 201-201, 275-275, 325-325

Source: Coding guidelines

libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/index.ts (1)

4-9: ⚡ Quick win

Reorder barrel exports to keep types at the bottom.

Place function/module exports first and move export type { ValidationResult } to the end for consistent module layout.

As per coding guidelines, "**/*.ts: Order module exports: top-level constants first, then exported functions, then other functions ordered by usage, with interfaces and types at the bottom".

Source: Coding guidelines

libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/rendering/renderer.ts (1)

4-22: ⚡ Quick win

Reorder exports to match the repository TypeScript ordering rule.

RenderOptions and RenderedData are exported before the exported function. Move interfaces/types to the bottom of the module after exported/other functions.

As per coding guidelines, "**/*.ts: Order module exports: top-level constants first, then exported functions, then other functions ordered by usage, with interfaces and types at the bottom".

Source: Coding guidelines

libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/rendering/renderer.test.ts (1)

6-12: ⚡ Quick win

Use SCREAMING_SNAKE_CASE for module-level constants.

Rename baseOptions to a SCREAMING_SNAKE_CASE constant name to align with the repository’s TS/JS constant convention.

As per coding guidelines, "**/*.{ts,tsx,js}: Use SCREAMING_SNAKE_CASE for constant declarations (e.g., MAX_FILE_SIZE, DEFAULT_TIMEOUT)".

Source: Coding guidelines

libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/pages/index.test.ts (1)

96-96: ⚡ Quick win

Remove repeated as any casts from artefact mocks.

These casts suppress type checks on a critical contract in controller tests. Prefer a typed fixture (or NonNullable<Awaited<ReturnType<typeof getArtefactById>>>) so schema/controller changes break tests safely.

As per coding guidelines, "**/*.{ts,tsx}: Enable TypeScript strict mode and avoid any type without justification".

Also applies to: 168-168, 204-204, 277-277, 326-326, 376-376

Source: Coding guidelines

libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/validation/json-validator.test.ts (1)

21-22: ⚡ Quick win

Strengthen schema assertion to catch miswired validators.

The expect.any(Object) matcher is too broad; these tests would still pass if the wrong schema is imported. Assert against the concrete schema object to lock the wrapper contract.

Suggested change
 import { validateJson } from "`@hmcts/publication`";
+import schema from "../schemas/upper-tribunal-administrative-appeals-chamber-daily-hearing-list.json" with { type: "json" };
 import { validateUtAdministrativeAppealsChamberDailyHearingList } from "./json-validator.js";
@@
-    expect(validateJson).toHaveBeenCalledWith(mockData, expect.any(Object), "1.0");
+    expect(validateJson).toHaveBeenCalledWith(mockData, schema, "1.0");
@@
-    expect(validateJson).toHaveBeenCalledWith(mockData, expect.any(Object), "1.0");
+    expect(validateJson).toHaveBeenCalledWith(mockData, schema, "1.0");

Also applies to: 35-36

libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/pages/upper-tribunal-lands-chamber-daily-hearing-list.njk (1)

3-10: ⚡ Quick win

Remove inline style and use GOV.UK spacing utilities for the back-to-top block.

This keeps templates style-free and avoids reintroducing per-template CSS for a single spacing rule.

Proposed fix
-{% block head %}
-  {{ super() }}
-  <style>
-    .back-to-top {
-      margin-top: 40px;
-    }
-  </style>
-{% endblock %}
@@
-    <div class="back-to-top">
+    <div class="govuk-!-margin-top-6">
       <a href="`#top`" class="govuk-link">{{ t.backToTop }}</a>
     </div>

Also applies to: 84-86

libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/index.ts (1)

4-9: ⚡ Quick win

Reorder exports so type exports are at the bottom.

Line 4 places a type export before runtime exports; move the ValidationResult export below Lines 5-9 to match the module export ordering rule.

As per coding guidelines, "**/*.ts: Order module exports: top-level constants first, then exported functions, then other functions ordered by usage, with interfaces and types at the bottom".

Source: Coding guidelines

libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/rendering/renderer.ts (1)

4-22: ⚡ Quick win

Reorder exports to match the project’s TypeScript module ordering rule.

Line 4 to Line 21 should appear after the exported function so this module follows the required export sequence.

As per coding guidelines, **/*.ts: "Order module exports: top-level constants first, then exported functions, then other functions ordered by usage, with interfaces and types at the bottom".

Source: Coding guidelines

libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/index.ts (1)

4-9: ⚡ Quick win

Move type exports to the bottom to match module export ordering.

Place the ValidationResult type export after value exports in this module.

As per coding guidelines, "Order module exports: top-level constants first, then exported functions, then other functions ordered by usage, with interfaces and types at the bottom".

Suggested change
-export type { ValidationResult } from "`@hmcts/publication`";
 export * from "./email-summary/summary-builder.js";
 export * from "./models/types.js";
 export * from "./pdf/pdf-generator.js";
 export * from "./rendering/renderer.js";
 export { validateUtTaxAndChanceryChamberDailyHearingList } from "./validation/json-validator.js";
+export type { ValidationResult } from "`@hmcts/publication`";

Source: Coding guidelines


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 04605b6f-0ff6-40c6-909b-4495343b346c

📥 Commits

Reviewing files that changed from the base of the PR and between 7a77ea2 and 41cb3d4.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (94)
  • .yarnrc.yml
  • apps/postgres/prisma/migrations/20260527140208/migration.sql
  • apps/postgres/prisma/seed.ts
  • apps/web/package.json
  • apps/web/src/app.test.ts
  • apps/web/src/app.ts
  • apps/web/src/pages/(admin)/non-strategic-upload-summary/cy.ts
  • apps/web/src/pages/(admin)/non-strategic-upload/cy.ts
  • apps/web/src/pages/(admin)/non-strategic-upload/index.njk
  • apps/web/src/pages/(admin)/non-strategic-upload/index.ts
  • docs/tickets/425/plan.md
  • docs/tickets/425/tasks.md
  • docs/tickets/425/ticket.md
  • libs/list-types/common/src/conversion/excel-to-json.test.ts
  • libs/list-types/common/src/conversion/excel-to-json.ts
  • libs/list-types/common/src/index.ts
  • libs/list-types/common/src/pdf/pdf-utilities.test.ts
  • libs/list-types/common/src/pdf/pdf-utilities.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/package.json
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/config.test.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/config.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/conversion/utaac-config.test.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/conversion/utaac-config.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/email-summary/summary-builder.test.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/email-summary/summary-builder.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/index.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/models/types.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/pages/cy.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/pages/en.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/pages/index.test.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/pages/index.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/pages/upper-tribunal-administrative-appeals-chamber-daily-hearing-list.njk
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/pdf/pdf-generator.test.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/pdf/pdf-generator.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/pdf/pdf-template.njk
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/rendering/renderer.test.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/rendering/renderer.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/schemas/upper-tribunal-administrative-appeals-chamber-daily-hearing-list.json
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/validation/json-validator.test.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/validation/json-validator.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/tsconfig.json
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/package.json
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/config.test.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/config.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/conversion/utlc-config.test.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/conversion/utlc-config.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/email-summary/summary-builder.test.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/email-summary/summary-builder.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/index.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/models/types.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/pages/cy.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/pages/en.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/pages/index.test.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/pages/index.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/pages/upper-tribunal-lands-chamber-daily-hearing-list.njk
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/pdf/pdf-generator.test.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/pdf/pdf-generator.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/pdf/pdf-template.njk
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/rendering/renderer.test.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/rendering/renderer.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/schemas/upper-tribunal-lands-chamber-daily-hearing-list.json
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/validation/json-validator.test.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/validation/json-validator.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/tsconfig.json
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/package.json
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/config.test.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/config.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/conversion/utcc-config.test.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/conversion/utcc-config.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/email-summary/summary-builder.test.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/email-summary/summary-builder.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/index.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/models/types.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/pages/cy.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/pages/en.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/pages/index.test.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/pages/index.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/pages/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list.njk
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/pdf/pdf-generator.test.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/pdf/pdf-generator.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/pdf/pdf-template.njk
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/rendering/renderer.test.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/rendering/renderer.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/schemas/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list.json
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/validation/json-validator.test.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/validation/json-validator.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/tsconfig.json
  • libs/location/src/list-type-data.ts
  • libs/location/src/location-data.ts
  • libs/location/src/seed-data.ts
  • libs/notifications/src/notification/notification-service.ts
  • libs/public-pages/src/routes/pdf/[artefactId]/download.ts
  • libs/publication/src/processing/service.ts
  • tsconfig.json

Comment on lines +24 to +25
const sensitivityMap = Object.fromEntries(nonStrategicListTypes.map((listType) => [listType.id.toString(), Sensitivity.PUBLIC]));
return { options, sensitivityMap };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Sensitivity defaults are now hardcoded to PUBLIC for all non-strategic list types.

Line 24 ignores defaultSensitivity from list type metadata and changes behaviour globally. This should preserve each list type’s configured default, with UT-specific handling only where required.

Suggested fix
-  const sensitivityMap = Object.fromEntries(nonStrategicListTypes.map((listType) => [listType.id.toString(), Sensitivity.PUBLIC]));
+  const sensitivityMap = Object.fromEntries(
+    nonStrategicListTypes.map((listType) => [
+      listType.id.toString(),
+      listType.defaultSensitivity ?? Sensitivity.PUBLIC
+    ])
+  );

Also applies to: 93-104

Comment on lines +91 to 92
const actualHeaders = headers.map((h) => h.toLowerCase().trim());
validateHeaders(actualHeaders, config.fields);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Header validation still enforces optional columns as mandatory.

validateHeaders(actualHeaders, config.fields) currently validates all configured headers, so uploads missing optional columns still fail before row parsing. This defeats the optional-field handling added in getField.

Proposed fix
 function validateHeaders(actualHeaders: string[], fields: FieldConfig[]): void {
-  const expectedHeaders = fields.map((f) => f.header.toLowerCase());
+  const requiredFields = fields.filter((f) => f.required ?? true);
+  const expectedHeaders = requiredFields.map((f) => f.header.toLowerCase());
   const missingHeaders = expectedHeaders.filter((expected) => !actualHeaders.includes(expected));

   if (missingHeaders.length > 0) {
-    const headerNames = fields.filter((f) => missingHeaders.includes(f.header.toLowerCase())).map((f) => f.header);
+    const headerNames = requiredFields
+      .filter((f) => missingHeaders.includes(f.header.toLowerCase()))
+      .map((f) => f.header);

-    throw new Error(`Excel file must contain columns: ${fields.map((f) => f.header).join(", ")}. Missing: ${headerNames.join(", ")}`);
+    throw new Error(
+      `Excel file must contain columns: ${requiredFields.map((f) => f.header).join(", ")}. Missing: ${headerNames.join(", ")}`
+    );
   }
 }

Comment thread libs/list-types/common/src/pdf/pdf-utilities.ts Outdated
Comment on lines +3 to +9
appellant: string;
caseReferenceNumber: string;
caseName: string;
judges: string;
members: string;
modeOfHearing: string;
venue: string;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Align optional hearing fields with the converter/schema contract.

Line 3 and Lines 6-9 currently require fields that are configured as optional in the converter flow. This creates a contract mismatch between parsed JSON and TypeScript models, and can leak undefined into rendering paths while the type system assumes string.

Proposed fix
 export interface UtaacHearing {
   time: string;
-  appellant: string;
+  appellant?: string;
   caseReferenceNumber: string;
   caseName: string;
-  judges: string;
-  members: string;
-  modeOfHearing: string;
-  venue: string;
+  judges?: string;
+  members?: string;
+  modeOfHearing?: string;
+  venue?: string;
   additionalInformation?: string;
 }
📝 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
appellant: string;
caseReferenceNumber: string;
caseName: string;
judges: string;
members: string;
modeOfHearing: string;
venue: string;
export interface UtaacHearing {
time: string;
appellant?: string;
caseReferenceNumber: string;
caseName: string;
judges?: string;
members?: string;
modeOfHearing?: string;
venue?: string;
additionalInformation?: string;
}

"minItems": 1,
"items": {
"type": "object",
"required": ["time", "caseReference", "caseName", "judges", "members", "hearingType", "venue"],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Required fields are stricter than the intended upload contract.

This schema currently requires judges, members, hearingType, and venue, which will reject valid records where those optional Excel fields are blank and trigger downstream “Invalid Data” responses.

Suggested fix
-    "required": ["time", "caseReference", "caseName", "judges", "members", "hearingType", "venue"],
+    "required": ["time", "caseReference", "caseName"],
📝 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
"required": ["time", "caseReference", "caseName", "judges", "members", "hearingType", "venue"],
"required": ["time", "caseReference", "caseName"],

Comment on lines 39 to 77
const needsSeeding = await shouldSeed();
if (!needsSeeding) {
// Seed list types even for existing DBs to pick up new entries added since initial seed
// Upsert sub-jurisdictions, locations, and list types even for existing DBs to pick up new entries added since initial seed
for (const subJurisdiction of locationData.subJurisdictions) {
await prisma.subJurisdiction.upsert({
where: { subJurisdictionId: subJurisdiction.subJurisdictionId },
create: {
subJurisdictionId: subJurisdiction.subJurisdictionId,
name: subJurisdiction.name,
welshName: subJurisdiction.welshName,
jurisdictionId: subJurisdiction.jurisdictionId
},
update: {
name: subJurisdiction.name,
welshName: subJurisdiction.welshName,
jurisdictionId: subJurisdiction.jurisdictionId
}
});
}

for (const location of locationData.locations) {
await prisma.location.upsert({
where: { locationId: location.locationId },
create: {
locationId: location.locationId,
name: location.name,
welshName: location.welshName,
email: null,
contactNo: null
},
update: {
name: location.name,
welshName: location.welshName
}
});
}

await seedListTypes();
return;

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 | 🔴 Critical | ⚡ Quick win

Prod/CI seed guard is bypassed in the new !needsSeeding branch.

Lines 39–41 route all shouldSeed() === false cases into write operations, including ENVIRONMENT=prod and CI=true. That contradicts the skip contract and can mutate protected environments.

Suggested fix
 export async function seedLocationData() {
   console.log("Checking if location data seeding is needed...");
 
+  if (process.env.ENVIRONMENT === "prod") {
+    console.log("Skipping seed: ENVIRONMENT is prod");
+    return;
+  }
+  if (process.env.CI === "true") {
+    console.log("Skipping seed: Running in CI environment");
+    return;
+  }
+
   const needsSeeding = await shouldSeed();
   if (!needsSeeding) {

Comment thread libs/location/src/seed-data.ts Outdated
Comment on lines +41 to +74
// Upsert sub-jurisdictions, locations, and list types even for existing DBs to pick up new entries added since initial seed
for (const subJurisdiction of locationData.subJurisdictions) {
await prisma.subJurisdiction.upsert({
where: { subJurisdictionId: subJurisdiction.subJurisdictionId },
create: {
subJurisdictionId: subJurisdiction.subJurisdictionId,
name: subJurisdiction.name,
welshName: subJurisdiction.welshName,
jurisdictionId: subJurisdiction.jurisdictionId
},
update: {
name: subJurisdiction.name,
welshName: subJurisdiction.welshName,
jurisdictionId: subJurisdiction.jurisdictionId
}
});
}

for (const location of locationData.locations) {
await prisma.location.upsert({
where: { locationId: location.locationId },
create: {
locationId: location.locationId,
name: location.name,
welshName: location.welshName,
email: null,
contactNo: null
},
update: {
name: location.name,
welshName: location.welshName
}
});
}

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 | 🏗️ Heavy lift

Existing-DB path upserts locations without rebuilding their relations.

Lines 59–74 update location rows, but the same branch skips locationRegion, locationSubJurisdiction, and locationReference writes. New entries can therefore exist without join-table links, causing incomplete location behaviour downstream.

Comment on lines +9 to +10
const MONOREPO_ROOT = path.join(__dirname, "..", "..", "..", "..", "..", "..");
const STORAGE_BASE = path.join(MONOREPO_ROOT, "storage", "temp", "uploads");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Storage path configuration is hardcoded in runtime code.

MONOREPO_ROOT/STORAGE_BASE are environment-specific configuration values and should be injected via environment variables rather than fixed relative traversal.

Suggested fix
-const MONOREPO_ROOT = path.join(__dirname, "..", "..", "..", "..", "..", "..");
-const STORAGE_BASE = path.join(MONOREPO_ROOT, "storage", "temp", "uploads");
+const STORAGE_BASE = process.env.PDF_STORAGE_PATH;
+if (!STORAGE_BASE) {
+  throw new Error("Missing PDF_STORAGE_PATH");
+}

As per coding guidelines, "Use environment variables for all configuration values and secrets, never hardcode them".

Source: Coding guidelines

Comment on lines +22 to +33
const artefact = await getArtefactById(artefactId);

if (!artefact) {
res.setHeader("Cache-Control", "private, max-age=0, no-cache, no-store, must-revalidate");
return res.status(404).json({ error: "Artefact not found" });
}

const now = new Date();
if (now < artefact.displayFrom || now > artefact.displayTo) {
res.setHeader("Cache-Control", "private, max-age=0, no-cache, no-store, must-revalidate");
return res.status(410).json({ error: "File has expired" });
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Public download flow does not enforce public sensitivity before serving files.

After artefact lookup and display-window checks, the handler serves the PDF without verifying that the artefact is actually public. Add an explicit sensitivity gate before file access to prevent unintended exposure of non-public artefacts.

Suggested fix
   if (!artefact) {
     res.setHeader("Cache-Control", "private, max-age=0, no-cache, no-store, must-revalidate");
     return res.status(404).json({ error: "Artefact not found" });
   }

+  if (artefact.sensitivity !== "PUBLIC") {
+    res.setHeader("Cache-Control", "private, max-age=0, no-cache, no-store, must-revalidate");
+    return res.status(404).json({ error: "Artefact not found" });
+  }
+
   const now = new Date();
📝 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
const artefact = await getArtefactById(artefactId);
if (!artefact) {
res.setHeader("Cache-Control", "private, max-age=0, no-cache, no-store, must-revalidate");
return res.status(404).json({ error: "Artefact not found" });
}
const now = new Date();
if (now < artefact.displayFrom || now > artefact.displayTo) {
res.setHeader("Cache-Control", "private, max-age=0, no-cache, no-store, must-revalidate");
return res.status(410).json({ error: "File has expired" });
}
const artefact = await getArtefactById(artefactId);
if (!artefact) {
res.setHeader("Cache-Control", "private, max-age=0, no-cache, no-store, must-revalidate");
return res.status(404).json({ error: "Artefact not found" });
}
if (artefact.sensitivity !== "PUBLIC") {
res.setHeader("Cache-Control", "private, max-age=0, no-cache, no-store, must-revalidate");
return res.status(404).json({ error: "Artefact not found" });
}
const now = new Date();
if (now < artefact.displayFrom || now > artefact.displayTo) {
res.setHeader("Cache-Control", "private, max-age=0, no-cache, no-store, must-revalidate");
return res.status(410).json({ error: "File has expired" });
}

junaidiqbalmoj and others added 5 commits June 16, 2026 12:43
…th new architecture

Move UTCC, UTLC, and UTAAC page controllers from libs/src/pages/ to
apps/web/src/pages/(list-types)/, relocate translations to src/locales/,
replace pageRoutes with schemaPath in configs, and export locale objects
with prefixed names from module index.ts — matching the pattern established
by the care-standards-tribunal-weekly-hearing-list reference implementation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After moving translations from src/pages/ to src/locales/, the
pdf-generator files in all three UT modules still referenced the
old paths, causing TS2307 build errors and test failures.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Bump typescript to 6.0.3 and vitest to 4.1.8 in all three UT modules
  to match monorepo — TS 5.9.3 does not accept ignoreDeprecations "6.0"
  in root tsconfig, causing Docker build failures
- Remove stale build:nunjucks src/pages/ reference (pages were moved to
  apps/web; only src/pdf/ njk files remain to copy)
- Fix list-type-validator test: replace CIVIL_DAILY_CAUSE_LIST (id=1)
  with LEGACY_UNSUPPORTED_LIST for the "no schema" test case, since
  @hmcts/civil-daily-cause-list now exists and has a validate function

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
importOriginal triggers real module resolution of civil-and-family-daily-cause-list
which chains through to postgres-prisma generated client, causing a 5000ms test
timeout in CI where the generated client does not exist.

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

@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

Caution

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

⚠️ Outside diff range comments (1)
apps/web/src/pages/(list-types)/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/index.ts (1)

64-65: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle malformed JSON as invalid input, not a server error.

At Line 64, JSON.parse failures fall into the outer catch and return HTTP 500 at Line 99. This should return the same 400 invalid-data path used for schema failures.

Suggested fix
-    const jsonData: UtccHearingList = JSON.parse(jsonContent);
+    let jsonData: UtccHearingList;
+    try {
+      jsonData = JSON.parse(jsonContent) as UtccHearingList;
+    } catch {
+      return res.status(400).render("errors/common", {
+        en,
+        cy,
+        errorTitle: "Invalid Data",
+        errorMessage: "The list data is invalid"
+      });
+    }

Also applies to: 97-104


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 828cec30-2ca7-4a1c-aa0f-eaf0df5c3211

📥 Commits

Reviewing files that changed from the base of the PR and between 41cb3d4 and c138f5a.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (32)
  • apps/web/src/app.test.ts
  • apps/web/src/pages/(list-types)/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/index.test.ts
  • apps/web/src/pages/(list-types)/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/index.ts
  • apps/web/src/pages/(list-types)/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/upper-tribunal-administrative-appeals-chamber-daily-hearing-list.njk
  • apps/web/src/pages/(list-types)/upper-tribunal-lands-chamber-daily-hearing-list/index.test.ts
  • apps/web/src/pages/(list-types)/upper-tribunal-lands-chamber-daily-hearing-list/index.ts
  • apps/web/src/pages/(list-types)/upper-tribunal-lands-chamber-daily-hearing-list/upper-tribunal-lands-chamber-daily-hearing-list.njk
  • apps/web/src/pages/(list-types)/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/index.test.ts
  • apps/web/src/pages/(list-types)/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/index.ts
  • apps/web/src/pages/(list-types)/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list.njk
  • libs/list-types/common/src/validation/list-type-validator.test.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/package.json
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/config.test.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/config.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/index.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/locales/cy.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/locales/en.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/pdf/pdf-generator.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/package.json
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/config.test.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/config.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/index.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/locales/cy.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/locales/en.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/pdf/pdf-generator.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/package.json
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/config.test.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/config.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/index.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/locales/cy.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/locales/en.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/pdf/pdf-generator.ts
💤 Files with no reviewable changes (9)
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/locales/cy.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/locales/cy.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/locales/cy.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/locales/en.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/locales/en.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/locales/en.ts
  • apps/web/src/pages/(list-types)/upper-tribunal-lands-chamber-daily-hearing-list/upper-tribunal-lands-chamber-daily-hearing-list.njk
  • apps/web/src/pages/(list-types)/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/upper-tribunal-administrative-appeals-chamber-daily-hearing-list.njk
  • apps/web/src/pages/(list-types)/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list.njk
✅ Files skipped from review due to trivial changes (1)
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/config.ts
🚧 Files skipped from review as they are similar to previous changes (10)
  • apps/web/src/app.test.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/index.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/index.ts
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/package.json
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/package.json
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/index.ts
  • libs/list-types/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/src/pdf/pdf-generator.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/package.json
  • libs/list-types/upper-tribunal-lands-chamber-daily-hearing-list/src/pdf/pdf-generator.ts
  • libs/list-types/upper-tribunal-tax-and-chancery-chamber-daily-hearing-list/src/pdf/pdf-generator.ts

junaidiqbalmoj and others added 2 commits June 16, 2026 14:06
The shared E2E database already has the artefact_list_type_id_fkey
constraint from a previous migration run. Re-applying the migration
fails with 42710 (constraint already exists). Wrap in a DO block so
the ADD CONSTRAINT is skipped if it already exists.

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

20260527140208 was a branch-only migration that added artefact_list_type_id_fkey,
duplicating the same constraint already added by the master migration
20260528115459_add_third_party_push_log. The duplicate left the shared E2E
database _prisma_migrations table in a failed state, blocking all subsequent
migrations.

Remove the duplicate migration and wrap the remaining ADD CONSTRAINT in a
DO block so it is skipped if the constraint already exists.

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.

@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


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fb73c798-cecd-48a0-b926-f4382fb67209

📥 Commits

Reviewing files that changed from the base of the PR and between dad6849 and 61b9087.

📒 Files selected for processing (8)
  • apps/postgres/prisma/migrations/20260707090002/migration.sql
  • apps/web/package.json
  • apps/web/src/app.test.ts
  • apps/web/src/app.ts
  • apps/web/src/pages/(admin)/non-strategic-upload/index.ts
  • apps/web/src/pages/(list-types)/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/upper-tribunal-administrative-appeals-chamber-daily-hearing-list.njk
  • libs/list-types/common/src/index.ts
  • libs/list-types/common/src/pdf/pdf-utilities.ts
💤 Files with no reviewable changes (1)
  • apps/web/src/pages/(list-types)/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/upper-tribunal-administrative-appeals-chamber-daily-hearing-list.njk
✅ Files skipped from review due to trivial changes (3)
  • libs/list-types/common/src/index.ts
  • apps/web/package.json
  • apps/web/src/app.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/web/src/app.ts
  • apps/web/src/pages/(admin)/non-strategic-upload/index.ts
  • libs/list-types/common/src/pdf/pdf-utilities.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.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fb73c798-cecd-48a0-b926-f4382fb67209

📥 Commits

Reviewing files that changed from the base of the PR and between dad6849 and 61b9087.

📒 Files selected for processing (8)
  • apps/postgres/prisma/migrations/20260707090002/migration.sql
  • apps/web/package.json
  • apps/web/src/app.test.ts
  • apps/web/src/app.ts
  • apps/web/src/pages/(admin)/non-strategic-upload/index.ts
  • apps/web/src/pages/(list-types)/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/upper-tribunal-administrative-appeals-chamber-daily-hearing-list.njk
  • libs/list-types/common/src/index.ts
  • libs/list-types/common/src/pdf/pdf-utilities.ts
💤 Files with no reviewable changes (1)
  • apps/web/src/pages/(list-types)/upper-tribunal-administrative-appeals-chamber-daily-hearing-list/upper-tribunal-administrative-appeals-chamber-daily-hearing-list.njk
✅ Files skipped from review due to trivial changes (3)
  • libs/list-types/common/src/index.ts
  • apps/web/package.json
  • apps/web/src/app.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/web/src/app.ts
  • apps/web/src/pages/(admin)/non-strategic-upload/index.ts
  • libs/list-types/common/src/pdf/pdf-utilities.ts
🛑 Comments failed to post (1)
apps/postgres/prisma/migrations/20260707090002/migration.sql (1)

2-2: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Avoid validating this foreign key inline.

This ALTER TABLE will scan artefact and can block writes while the constraint is added. If the table is non-trivial, this risks stalling deploys. Prefer NOT VALID here, then validate in a separate migration/window.

♻️ Suggested change
-ALTER TABLE "artefact" ADD CONSTRAINT "artefact_list_type_id_fkey" FOREIGN KEY ("list_type_id") REFERENCES "list_types"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
+ALTER TABLE "artefact" ADD CONSTRAINT "artefact_list_type_id_fkey" FOREIGN KEY ("list_type_id") REFERENCES "list_types"("id") ON DELETE RESTRICT ON UPDATE CASCADE NOT VALID;
+
+-- later, in a separate migration
+ALTER TABLE "artefact" VALIDATE CONSTRAINT "artefact_list_type_id_fkey";
🧰 Tools
🪛 Squawk (2.59.0)

[warning] 2-2: By default new constraints require a table scan and block writes to the table while that scan occurs. Use NOT VALID with a later VALIDATE CONSTRAINT call.

(constraint-missing-not-valid)


[warning] 2-2: Adding a foreign key constraint requires a table scan and a SHARE ROW EXCLUSIVE lock on both tables, which blocks writes to each table. Add NOT VALID to the constraint in one transaction and then VALIDATE the constraint in a separate transaction.

(adding-foreign-key-constraint)

Source: Linters/SAST tools

@sonarqubecloud

sonarqubecloud Bot commented Jul 8, 2026

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Jul 8, 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 0fcb3af into master Jul 9, 2026
26 checks passed
hmctsclaudecode Bot pushed a commit that referenced this pull request Jul 10, 2026
Migration 006: REQ-0104 (#425) implemented -> verified
PR #669 (feat: UT non-strategic publishing UTCC/UTLC/UTAAC) merged 2026-07-09.

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.

Style Guide: Tribunal non-strategic publishing - UTCC, UTLC & UTAAC

5 participants