Skip to content

feat(#428): Add non-strategic hearing list types for SIAC, POAC, PAAC, FTT Tax Chamber, FTT LRT and FTT RPT - #749

Merged
junaidiqbalmoj merged 26 commits into
masterfrom
feature/428-tribunal-non-strategic-publishing
Jul 3, 2026
Merged

feat(#428): Add non-strategic hearing list types for SIAC, POAC, PAAC, FTT Tax Chamber, FTT LRT and FTT RPT#749
junaidiqbalmoj merged 26 commits into
masterfrom
feature/428-tribunal-non-strategic-publishing

Conversation

@junaidiqbalmoj

@junaidiqbalmoj junaidiqbalmoj commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds 10 new non-strategic list types (IDs 28–37) to the list type registry: SIAC, POAC, PAAC, FTT Tax Chamber, FTT Lands Registration Tribunal, and 5 FTT RPT regional variants (Eastern, London, Midlands, Northern, Southern)
  • Creates 4 new lib packages grouping related list types: siac-poac-paac-weekly-hearing-list, ftt-tax-chamber-weekly-hearing-list, ftt-lands-registration-tribunal-weekly-hearing-list, ftt-rpt-weekly-hearing-list
  • Creates 10 page controllers and Nunjucks templates in apps/web/src/pages/(list-types)/ following the existing non-strategic publishing pattern
  • Each list type has validation JSON schema, Excel converter config, email summary builder (Date, Time/Hearing Time, Case Reference Number), PDF generator and template, English/Welsh locales, and unit tests

Implementation Notes

  • SIAC, POAC and PAAC share identical field sets (Date, Time, Appellant, Case Reference Number, Hearing Type, Courtroom, Additional Information) and the same important information accordion text pointing to Field House, EC4A 1DZ
  • FTT Tax Chamber includes optional Members field and important information with the taxappeals@justice.gov.uk contact
  • FTT LRT and FTT RPT use [insert office email] placeholder pending confirmation from the tribunal — see TODO comments in the relevant en.ts files
  • Welsh translations for new list types use English as placeholder text pending translation

Test plan

  • Unit tests pass for all 10 new page controllers (yarn test)
  • Lint checks pass (yarn lint)
  • Each list type URL path resolves correctly with a test artefact
  • Important information accordion renders correctly with structured text + link (no raw markdown)
  • Optional fields (members, additionalInformation) render blank when absent, populated when present
  • Welsh locale (?lng=cy) loads without errors on all new pages

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added new weekly hearing list pages for SIAC/POAC/PAAC, FTT Tax Chamber, FTT Lands Registration Tribunal, and FTT Residential Property Tribunal regional lists.
    • Added searchable hearings tables, “important information” sections, data source labels, and back-to-top links.
    • Added Welsh and English wording across the new list pages.
  • Bug Fixes

    • Improved handling for missing or invalid hearing list data with clearer error responses.
    • Updated tribunal naming to “Land Registration Tribunal” in relevant places.

…, FTT Tax Chamber, FTT LRT and FTT RPT

Adds 10 new list types (IDs 28–37) to the non-strategic publishing route,
each with a validation schema, Excel converter, email summary, PDF template,
Nunjucks page template, and English/Welsh locales.

List types added:
- SIAC Weekly Hearing List (ID 28, London)
- POAC Weekly Hearing List (ID 29, London)
- PAAC Weekly Hearing List (ID 30, London)
- FTT Tax Chamber Weekly Hearing List (ID 31, National)
- FTT Lands Registration Tribunal Weekly Hearing List (ID 32, National)
- FTT RPT Eastern Region Weekly Hearing List (ID 33)
- FTT RPT London Region Weekly Hearing List (ID 34)
- FTT RPT Midlands Region Weekly Hearing List (ID 35)
- FTT RPT Northern Region Weekly Hearing List (ID 36)
- FTT RPT Southern Region Weekly Hearing List (ID 37)

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

coderabbitai Bot commented Jun 18, 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 adds ten new tribunal weekly hearing list types (SIAC, POAC, PAAC, FTT Tax Chamber, FTT LRT, and five FTT RPT regions) as new lib packages with schemas, converters, renderers, PDF generators, locales, and templates, plus corresponding web page controllers, list-type registry entries, and notification/publication wiring.

Changes

Tribunal weekly hearing list rollout

Layer / File(s) Summary
Application module wiring
apps/web/src/app.ts
Registers the new module roots for FTT LRT, RPT, Tax Chamber, and SIAC/POAC/PAAC into modulePaths.
Planning docs and registry
docs/tickets/428/*, libs/location/src/list-type-data.ts, libs/location/src/location-data.ts, templates/tech-spec-references/welsh-translations-catalogue.json, tsconfig.json, biome.json
Adds implementation plan/tasks/ticket/review docs, appends list-type registry entries (IDs 28–37, shifting CIC/AST IDs), fixes LRT tribunal naming, adds tsconfig path mappings, and ignores .claude in biome.
SIAC/POAC/PAAC library
libs/list-types/siac-poac-paac-weekly-hearing-list/*
New package with config, model types, schema, Excel converter (IDs 28–30), EN/CY locales, renderer, email summary builder, PDF generator/template, and view template.
FTT Tax Chamber library and page
libs/list-types/ftt-tax-chamber-weekly-hearing-list/*, apps/web/src/pages/(list-types)/ftt-tax-chamber-weekly-hearing-list/*
New package (ID 31) mirroring the SIAC pattern, plus a page controller/template/tests.
FTT LRT library and page
libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/*, apps/web/src/pages/(list-types)/ftt-lands-registration-tribunal-weekly-hearing-list/*
New package (ID 32) mirroring the SIAC pattern, plus a page controller/template/tests.
FTT RPT library and page
libs/list-types/ftt-rpt-weekly-hearing-list/*, apps/web/src/pages/(list-types)/ftt-rpt-weekly-hearing-list/ftt-rpt-weekly-hearing-list.njk
New package for five regions (IDs 33–37) mirroring the SIAC pattern, plus the page template.
Shared PDF utilities
libs/list-types/common/src/pdf/pdf-utilities.ts, libs/list-types/common/src/index.ts
Introduces generateFttSiacWeeklyHearingListPdf orchestration reused by all new packages' PDF generators.
Publication and notification wiring
libs/publication/src/processing/service.ts, libs/notifications/src/notification/notification-service.ts, libs/publication/package.json, libs/notifications/package.json
Registers PDF generators and email builders for the new list types, and adds workspace dependencies.

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant Publication
  participant renderSiacPoacPaacData
  Browser->>Publication: getArtefactById(artefactId)
  Publication-->>Browser: artefact
  Browser->>Publication: getPublicationJson(artefactId)
  Publication-->>Browser: hearing list JSON
  Browser->>renderSiacPoacPaacData: jsonData + options
  renderSiacPoacPaacData-->>Browser: header + hearings
Loading

Possibly related issues

Possibly related PRs

  • hmcts/cath-service#204: Also wires additional module roots into the same apps/web/src/app.ts modulePaths configuration.
  • hmcts/cath-service#325: Builds on the shared libs/list-types/common/src/pdf/pdf-utilities.ts infrastructure extended in this PR.
  • hmcts/cath-service#663: Also registers new list-type module roots and routes via the same configureGovuk/createSimpleRouter pattern in apps/web/src/app.ts.
🚥 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 matches the main change: adding the new non-strategic hearing list types for SIAC, POAC, PAAC and FTT variants.
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/428-tribunal-non-strategic-publishing

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 18, 2026

Copy link
Copy Markdown
Contributor

🎭 Playwright E2E Test Results

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

Results for commit f1b27ab.

♻️ This comment has been updated with latest results.

- Add no-op migration file for 20260605141023_add_jurisdiction_soft_delete_and_audit_log
- Fix summary-of-publications "for week commencing" text for all WEEKLY_HEARING_LIST types
- Register all 10 new list types in PDF_GENERATOR_REGISTRY and EMAIL_BUILDER_REGISTRY
- Add workspace dependencies for 4 new list type libs to publication and notifications
- Split FTT Tax Chamber important information from single paragraph into 4 paragraphs
- Fix FTT RPT short names: "RPT X" -> "FTT (RPT) X Weekly Hearing List"
- Fix FTT RPT full names: remove "and", add colon, lowercase "region" across all files
- Exclude .claude analytics files from Biome linting

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.

@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

Note

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

🟠 Major comments (36)
libs/location/src/list-type-data.ts-383-390 (1)

383-390: ⚠️ Potential issue | 🟠 Major

FTT RPT friendly names deviate from ticket specification.

Lines 383, 395, 407, 419, and 431 show englishFriendlyName as "First-tier Tribunal (Residential Property Tribunal): Eastern region Weekly Hearing List" (missing "and", added colon, lowercase "region"), but ticket 428 specifies "First-tier Tribunal (Residential and Property Tribunal) Eastern Region Weekly Hearing List".

Additionally, shortenedFriendlyName is "FTT (RPT) Eastern Weekly Hearing List", but the ticket specifies "RPT Eastern Weekly Hearing List" for the upload form label.

These deviations affect user-visible text in the upload form. Align with the approved specification or update the ticket if these changes were intentional.

libs/list-types/siac-poac-paac-weekly-hearing-list/src/schemas/siac-poac-paac-weekly-hearing-list.json-13-13 (1)

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

Strengthen date validation to reject impossible calendar dates.

Line 13 only validates shape, so invalid dates can pass validation and render as wrong dates downstream.

Suggested change
-        "pattern": "^\\d{2}/\\d{2}/\\d{4}$",
+        "pattern": "^(0[1-9]|[12][0-9]|3[01])\\/(0[1-9]|1[0-2])\\/\\d{4}$",
apps/web/src/pages/(list-types)/poac-weekly-hearing-list/index.ts-26-27 (1)

26-27: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate and constrain artefactId before building the JSON path.

At Line 26 and Line 49, user input is interpolated into a filesystem path without explicit format validation or path containment checks. Add an allow-list check (e.g. UUID) and verify the resolved path remains under TEMP_UPLOAD_DIR before reading.

Also applies to: 49-49

apps/web/src/pages/(list-types)/poac-weekly-hearing-list/index.ts-32-34 (1)

32-34: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Localise error title/message content for Welsh requests.

These user-facing error strings are hard-coded in English, so Welsh journeys still receive English copy on error branches. Route-level error text should be locale-driven like the rest of the page content.

As per coding guidelines, "Implement Welsh language support on all user-facing text with separate en.ts and cy.ts content files".

Also applies to: 44-46, 72-74, 103-105

Source: Coding guidelines

libs/list-types/siac-poac-paac-weekly-hearing-list/src/locales/cy.ts-4-35 (1)

4-35: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Replace English placeholders with Welsh copy for the cy locale.

Line 4 through Line 35 are still English, so Welsh journeys render untranslated content when ?lng=cy is used.

As per coding guidelines, "Implement Welsh language support on all user-facing text with separate en.ts and cy.ts content files" and "Test pages with ?lng=cy query parameter to verify Welsh content during development."

Source: Coding guidelines

libs/list-types/siac-poac-paac-weekly-hearing-list/src/pdf/pdf-generator.ts-62-62 (1)

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

Avoid non-null assertion on sizeBytes from external PDF generation.

Line 62 uses pdfResult.sizeBytes!; if sizeBytes is absent on a successful response, this can propagate invalid data into storage logic.

Suggested fix
-    return await savePdfToStorage(options.artefactId, pdfResult.pdfBuffer, pdfResult.sizeBytes!);
+    const sizeBytes = pdfResult.sizeBytes ?? pdfResult.pdfBuffer.length;
+    return await savePdfToStorage(options.artefactId, pdfResult.pdfBuffer, sizeBytes);
libs/list-types/siac-poac-paac-weekly-hearing-list/src/pdf/pdf-generator.ts-32-33 (1)

32-33: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use artefact last-received time, not generation time, for PDF header metadata.

Line 32 currently uses new Date().toISOString(), which makes “last updated” reflect PDF generation time rather than publication data time.

Suggested fix
 interface PdfGenerationOptions extends BasePdfGenerationOptions<SiacPoacPaacHearingList> {
   contentDate: Date;
+  lastReceivedDate: string;
   courtName: string;
   listTitle: string;
 }

 // ...
-      lastReceivedDate: new Date().toISOString(),
+      lastReceivedDate: options.lastReceivedDate,
apps/web/src/pages/(list-types)/siac-weekly-hearing-list/index.ts-26-50 (1)

26-50: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate artefactId before file-path construction to block traversal.

Line 49 builds a filesystem path directly from user-controlled artefactId. Without strict format validation, crafted values can escape TEMP_UPLOAD_DIR.

Suggested change
+const ARTEFACT_ID_PATTERN = /^[a-zA-Z0-9-]+$/;
+
 export const GET = async (req: Request, res: Response) => {
@@
   const artefactId = req.query.artefactId as string;
@@
   if (!artefactId) {
@@
   }
+
+  if (!ARTEFACT_ID_PATTERN.test(artefactId)) {
+    return res.status(400).render("errors/common", {
+      en,
+      cy,
+      errorTitle: "Bad Request",
+      errorMessage: "Invalid artefactId parameter"
+    });
+  }
@@
-    const jsonFilePath = path.join(TEMP_UPLOAD_DIR, `${artefactId}.json`);
+    const jsonFilePath = path.resolve(TEMP_UPLOAD_DIR, `${artefactId}.json`);
+    if (!jsonFilePath.startsWith(`${TEMP_UPLOAD_DIR}${path.sep}`)) {
+      return res.status(400).render("errors/common", {
+        en,
+        cy,
+        errorTitle: "Bad Request",
+        errorMessage: "Invalid artefactId parameter"
+      });
+    }
libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/models/types.ts-1-11 (1)

1-11: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make members optional in the domain model.

members is currently mandatory, but this list type is described as having an optional Members field. Keeping it required creates a contract mismatch and pushes callers to inject placeholder empty strings.

Suggested change
 export interface FttTaxChamberHearing {
   date: string;
   hearingTime: string;
   caseName: string;
   caseReferenceNumber: string;
   judges: string;
-  members: string;
+  members?: string;
   venuePlatform: string;
 }
libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/schemas/ftt-tax-chamber-weekly-hearing-list.json-8-8 (1)

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

members should not be in required for this schema.

Line 8 currently makes members mandatory, which conflicts with the stated optional Members behaviour and will reject otherwise valid records at ingest time.

Suggested change
-    "required": ["date", "hearingTime", "caseName", "caseReferenceNumber", "judges", "members", "venuePlatform"],
+    "required": ["date", "hearingTime", "caseName", "caseReferenceNumber", "judges", "venuePlatform"],
libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/pdf/pdf-template.njk-2-2 (1)

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

Remove hard-coded English in the Welsh-capable PDF template.

Line [2] fixes document language to en, and Line [51] hard-codes “No hearings scheduled.”. This will produce mixed-language output when Welsh content is selected.

Suggested patch
-<html lang="en">
+<html lang="{{ t.languageCode or 'en' }}">
@@
-    <p>No hearings scheduled.</p>
+    <p>{{ t.noHearingsScheduled }}</p>

Also applies to: 51-51

apps/web/src/pages/(list-types)/ftt-tax-chamber-weekly-hearing-list/index.ts-18-19 (1)

18-19: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace hard-coded repository traversal with configuration.

This path derivation is deployment-fragile and can break as soon as runtime layout changes. Read the upload root from an environment variable instead.

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

Source: Coding guidelines

apps/web/src/pages/(list-types)/ftt-tax-chamber-weekly-hearing-list/index.ts-26-26 (1)

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

Sanitise artefactId before using it in a filesystem path.

Line [26] trusts query input via cast, and Line [49] interpolates it into a file path. Add strict type/format validation (and path containment checks) before file access.

Suggested patch
-  const artefactId = req.query.artefactId as string;
+  const artefactIdRaw = req.query.artefactId;
+  if (typeof artefactIdRaw !== "string" || !/^[a-f0-9-]{36}$/i.test(artefactIdRaw)) {
+    return res.status(400).render("errors/common", {
+      en,
+      cy,
+      errorTitle: "Bad Request",
+      errorMessage: "Invalid artefactId parameter"
+    });
+  }
+  const artefactId = artefactIdRaw;
@@
-    const jsonFilePath = path.join(TEMP_UPLOAD_DIR, `${artefactId}.json`);
+    const jsonFilePath = path.resolve(TEMP_UPLOAD_DIR, `${artefactId}.json`);
+    if (!jsonFilePath.startsWith(`${path.resolve(TEMP_UPLOAD_DIR)}${path.sep}`)) {
+      return res.status(400).render("errors/common", {
+        en,
+        cy,
+        errorTitle: "Bad Request",
+        errorMessage: "Invalid artefactId parameter"
+      });
+    }

Also applies to: 49-49

apps/web/src/pages/(list-types)/ftt-tax-chamber-weekly-hearing-list/index.ts-52-62 (1)

52-62: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not collapse all file-read failures into 404.

This catch treats permission/I/O faults as “Not Found”, which obscures operational failures. Return 404 only for missing files (ENOENT); return 500 for other read errors.

apps/web/src/pages/(list-types)/ftt-tax-chamber-weekly-hearing-list/index.ts-55-55 (1)

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

Avoid logging raw errors and validation payload details.

These logs may expose sensitive case data or internal paths. Log sanitised, structured messages instead.

As per coding guidelines: “Never include sensitive data in application logs”.

Also applies to: 68-68, 99-99

Source: Coding guidelines

libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/locales/cy.ts-4-36 (1)

4-36: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Welsh locale is still English placeholder content.

For Welsh journeys, users on ?lng=cy will see English copy across headings, body content, and table labels. Please replace these placeholders with actual Welsh strings before release.

libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/locales/en.ts-12-13 (1)

12-13: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

User-facing contact email is unresolved placeholder text.

Line 13 still contains [insert office email], so users cannot follow the published contact instruction. Please replace with the confirmed tribunal mailbox before shipping.

libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/locales/cy.ts-4-13 (1)

4-13: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Welsh locale remains placeholder content, including unresolved office email token.

This file is still English and includes [insert office email], so the Welsh path is incomplete and not actionable for users.

apps/web/src/pages/(list-types)/ftt-lands-registration-tribunal-weekly-hearing-list/index.ts-26-26 (1)

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

artefactId needs strict validation before file-path usage.

Line 49 interpolates unvalidated query input into a filesystem path. A crafted value (for example containing path segments) can escape the intended upload directory. Validate artefactId against a strict allowlist (e.g., UUID) and reject anything else before path construction.

Suggested hardening
+const ARTEFACT_ID_PATTERN = /^[0-9a-fA-F-]{36}$/;
+
 export const GET = async (req: Request, res: Response) => {
@@
-  const artefactId = req.query.artefactId as string;
+  const artefactId = req.query.artefactId as string;
@@
-  if (!artefactId) {
+  if (!artefactId || !ARTEFACT_ID_PATTERN.test(artefactId)) {
     return res.status(400).render("errors/common", {
       en,
       cy,
       errorTitle: "Bad Request",
-      errorMessage: "Missing artefactId parameter"
+      errorMessage: "Invalid artefactId parameter"
     });
   }

Also applies to: 49-49

apps/web/src/pages/(list-types)/ftt-lands-registration-tribunal-weekly-hearing-list/index.ts-55-55 (1)

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

Avoid logging raw errors and validation details from this request flow.

These logs can expose operational paths and data-bearing validation details. Log a sanitised error code/context only.

As per coding guidelines, "Never include sensitive data in application logs".

Also applies to: 68-68, 99-99

Source: Coding guidelines

libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/conversion/ftt-tax-config.ts-45-48 (1)

45-48: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Member(s) is incorrectly mandatory in the Tax converter.

Line 47 sets required: true, but this list type is defined with an optional Members field. This will fail otherwise valid uploads.

Suggested fix
     {
       header: "Member(s)",
       fieldName: "members",
-      required: true,
+      required: false,
       validators: [(value, rowNumber) => validateNoHtmlTags(value, "Member(s)", rowNumber)]
     },
libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/pdf/pdf-template.njk-2-2 (1)

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

Remove hardcoded English from language metadata and empty-state content.

lang="en" and No hearings scheduled. are fixed English strings, so Welsh/localised PDF output is incomplete.

Also applies to: 55-55

libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/pdf/pdf-generator.ts-60-60 (1)

60-60: ⚠️ Potential issue | 🟠 Major

Remove non-null assertion and handle optional sizeBytes defensively.

Line 60 uses a non-null assertion on pdfResult.sizeBytes! despite the type signature marking it optional. While the implementation always provides sizeBytes when generation succeeds, the code should treat the type as authoritative. Use a fallback to the buffer length if needed:

Suggested fix
-    return await savePdfToStorage(options.artefactId, pdfResult.pdfBuffer, pdfResult.sizeBytes!);
+    const sizeBytes = pdfResult.sizeBytes ?? pdfResult.pdfBuffer.length;
+    return await savePdfToStorage(options.artefactId, pdfResult.pdfBuffer, sizeBytes);
libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/pdf/pdf-generator.ts-30-31 (1)

30-31: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use artefact/event lastReceivedDate instead of generation-time now().

lastUpdatedDate/Time in the PDF header is currently derived from new Date() at generation time, so it can drift from the actual received timestamp used elsewhere and produce inconsistent publication metadata.

Suggested fix
 interface PdfGenerationOptions extends BasePdfGenerationOptions<FttLrtHearingList> {
   contentDate: Date;
+  lastReceivedDate?: string;
 }
@@
-      lastReceivedDate: new Date().toISOString(),
+      lastReceivedDate: options.lastReceivedDate ?? new Date().toISOString(),
libs/list-types/ftt-rpt-weekly-hearing-list/src/locales/en.ts-11-13 (1)

11-13: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace unresolved contact placeholder before release.

Line 12 still contains [insert office email] in user-facing guidance. That leaves no actionable contact route for observers/media and breaks the core instruction flow.

apps/web/src/pages/(list-types)/ftt-rpt-eastern-weekly-hearing-list/index.ts-59-70 (1)

59-70: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle JSON parse failures as 400 Invalid Data, not 500.

Line 59 can throw on malformed JSON and currently falls into the Line 94 catch, returning a server error. Parse failures should be mapped to the same 400 invalid-data path as schema failures.

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

Also applies to: 94-101

libs/list-types/ftt-rpt-weekly-hearing-list/src/pdf/pdf-template.njk-57-57 (1)

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

Localise the empty-state message instead of hardcoding English text.

No hearings scheduled. is hardcoded and will stay English in Welsh output. Use a translation key from locale files (for example t.noHearingsScheduled) to keep bilingual rendering consistent.

libs/list-types/ftt-rpt-weekly-hearing-list/src/pdf/pdf-template.njk-2-2 (1)

2-2: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Do not hardcode document language to English.

<html lang="en"> is incorrect for Welsh PDFs. Pass the active locale into the template and set lang dynamically.

libs/list-types/ftt-rpt-weekly-hearing-list/src/locales/cy.ts-4-39 (1)

4-39: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

cy locale is not Welsh content.

Lines 4–39 are English strings, so ?lng=cy users won’t receive Welsh content. This is a localisation defect for a user-facing route.

As per coding guidelines, "Implement Welsh language support on all user-facing text with separate en.ts and cy.ts content files".

Source: Coding guidelines

apps/web/src/pages/(list-types)/ftt-rpt-midlands-weekly-hearing-list/index.ts-21-24 (1)

21-24: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add runtime validation for artefactId input shape.

Line 21 relies on a type assertion. Non-string query values (e.g. repeated params) can still reach downstream calls and cause a 500 path instead of a 400.

apps/web/src/pages/(list-types)/ftt-rpt-midlands-weekly-hearing-list/index.ts-59-64 (1)

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

Handle invalid JSON as client error (400).

Line 59 parse failures currently escape to the outer catch and return 500. Malformed list payload should return the same 400 Invalid Data response used for schema failures.

apps/web/src/pages/(list-types)/ftt-rpt-london-weekly-hearing-list/index.ts-59-64 (1)

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

Malformed JSON currently returns 500 instead of 400.

Line 59 can throw on JSON.parse, and that is caught by the outer handler (Line 94), returning Server Error. This should return Invalid Data (400), same as schema failures.

Suggested fix
-    const jsonData: FttRptHearingList = JSON.parse(jsonContent);
+    let jsonData: FttRptHearingList;
+    try {
+      jsonData = JSON.parse(jsonContent) as FttRptHearingList;
+    } catch {
+      return res.status(400).render("errors/common", {
+        en,
+        cy,
+        errorTitle: "Invalid Data",
+        errorMessage: "The list data is invalid"
+      });
+    }
apps/web/src/pages/(list-types)/ftt-rpt-london-weekly-hearing-list/index.ts-21-24 (1)

21-24: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate artefactId runtime type, not just TS assertion.

Line 21 uses as string without runtime checks. Repeated query params (array value) can flow through and end up as a 500 instead of a 400.

Suggested fix
-  const artefactId = req.query.artefactId as string;
-
-  if (!artefactId) {
+  const artefactIdParam = req.query.artefactId;
+  if (typeof artefactIdParam !== "string" || artefactIdParam.trim().length === 0) {
     return res.status(400).render("errors/common", {
       en,
       cy,
       errorTitle: "Bad Request",
       errorMessage: "Missing artefactId parameter"
     });
   }
+  const artefactId = artefactIdParam;
libs/list-types/ftt-rpt-weekly-hearing-list/src/locales/cy.ts-11-13 (1)

11-13: ⚠️ Potential issue | 🟠 Major

Replace [insert office email] with the actual tribunal contact address.

Line 12 contains an unresolved placeholder that leaves the instructions unusable for observers and media requesting hearing access. The same issue appears in the English version and other tribunal configuration files.

libs/list-types/ftt-rpt-weekly-hearing-list/src/pdf/pdf-generator.ts-28-33 (1)

28-33: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use artefact update time for renderer metadata, not generation time.

Line 32 hardcodes new Date().toISOString(), which can misstate the list’s actual update timestamp in the rendered output. Please pass through the artefact’s lastReceivedDate from options so PDF and page views stay consistent for the same artefact.

Suggested fix
     const renderedData = renderFttRptData(options.jsonData, {
       locale: options.locale,
       courtName: options.courtName,
       contentDate: options.contentDate,
-      lastReceivedDate: new Date().toISOString(),
+      lastReceivedDate: options.lastReceivedDate.toISOString(),
       listTitle: options.listTitle
     });
libs/list-types/ftt-rpt-weekly-hearing-list/src/pdf/pdf-generator.ts-55-63 (1)

55-63: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate sizeBytes before persisting the PDF.

Line 62 uses a non-null assertion for sizeBytes. If the PDF service returns a buffer without size metadata, this can pass invalid data into storage handling.

Suggested fix
-    if (!pdfResult.success || !pdfResult.pdfBuffer) {
+    if (!pdfResult.success || !pdfResult.pdfBuffer || typeof pdfResult.sizeBytes !== "number") {
       return {
         success: false,
         error: pdfResult.error || "PDF generation failed"
       };
     }

-    return await savePdfToStorage(options.artefactId, pdfResult.pdfBuffer, pdfResult.sizeBytes!);
+    return await savePdfToStorage(options.artefactId, pdfResult.pdfBuffer, pdfResult.sizeBytes);
🟡 Minor comments (6)
libs/list-types/siac-poac-paac-weekly-hearing-list/src/pdf/pdf-template.njk-53-53 (1)

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

Localise the empty-state message instead of hardcoding English.

Line 53 uses "No hearings scheduled." directly, so Welsh output will still contain English text for empty lists.

Suggested change
-    <p>No hearings scheduled.</p>
+    <p>{{ t.noHearingsScheduled }}</p>
libs/list-types/siac-poac-paac-weekly-hearing-list/src/config.test.ts-40-42 (1)

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

Make the trailing-separator assertion cross-platform.

At Line 41, /\/$/ only matches POSIX separators. This can fail on Windows-style paths.
Use a platform-agnostic check instead.

Suggested diff
-    it("should end with trailing slash", () => {
-      expect(assets).toMatch(/\/$/);
-    });
+    it("should end with a trailing path separator", () => {
+      expect(/[\\/]$/.test(assets)).toBe(true);
+    });
apps/web/src/pages/(list-types)/siac-weekly-hearing-list/index.ts-64-75 (1)

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

Treat malformed JSON as client data error, not server error.

Line 64 can throw on invalid JSON, but that currently maps to the generic 500 path (Lines 98-105). This should return the same 400 “Invalid Data” response as schema failures.

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

Also applies to: 98-105

apps/web/src/pages/(list-types)/ftt-tax-chamber-weekly-hearing-list/ftt-tax-chamber-weekly-hearing-list.njk-72-72 (1)

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

Render dataSource conditionally to avoid empty label output.

If dataSource is missing, the page will still display a blank value (Data source:). Guard this block with a conditional.

apps/web/src/pages/(list-types)/ftt-lands-registration-tribunal-weekly-hearing-list/ftt-lands-registration-tribunal-weekly-hearing-list.njk-68-68 (1)

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

Guard the data source paragraph when no provenance label is available.

Without a conditional, users can see an empty data source value.

libs/list-types/ftt-rpt-weekly-hearing-list/src/rendering/renderer.ts-4-22 (1)

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

Move exported interfaces below exported functions to match repo export-order rules.

RenderOptions/RenderedData are currently declared before renderFttRptData; this breaks the project’s required export ordering for *.ts files.

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

🧹 Nitpick comments (21)
libs/list-types/siac-poac-paac-weekly-hearing-list/src/rendering/renderer.ts (1)

4-22: ⚡ Quick win

Reorder exports to match repository TypeScript ordering convention.

Lines 4–21 export interfaces before the exported function on Line 22. Please move interfaces/types to the bottom of the module.

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/siac-poac-paac-weekly-hearing-list/src/conversion/siac-poac-paac-config.ts (1)

62-62: ⚡ Quick win

Rename converter constant to SCREAMING_SNAKE_CASE.

Line 62 uses siacPoacPaacConverter, which breaks the constant naming rule used in this repo.

Suggested change
-const siacPoacPaacConverter = createConverter(SIAC_POAC_PAAC_EXCEL_CONFIG);
+const SIAC_POAC_PAAC_CONVERTER = createConverter(SIAC_POAC_PAAC_EXCEL_CONFIG);

-registerConverter(28, siacPoacPaacConverter);
-registerConverterByName("SIAC_WEEKLY_HEARING_LIST", siacPoacPaacConverter);
+registerConverter(28, SIAC_POAC_PAAC_CONVERTER);
+registerConverterByName("SIAC_WEEKLY_HEARING_LIST", SIAC_POAC_PAAC_CONVERTER);

-registerConverter(29, siacPoacPaacConverter);
-registerConverterByName("POAC_WEEKLY_HEARING_LIST", siacPoacPaacConverter);
+registerConverter(29, SIAC_POAC_PAAC_CONVERTER);
+registerConverterByName("POAC_WEEKLY_HEARING_LIST", SIAC_POAC_PAAC_CONVERTER);

-registerConverter(30, siacPoacPaacConverter);
-registerConverterByName("PAAC_WEEKLY_HEARING_LIST", siacPoacPaacConverter);
+registerConverter(30, SIAC_POAC_PAAC_CONVERTER);
+registerConverterByName("PAAC_WEEKLY_HEARING_LIST", SIAC_POAC_PAAC_CONVERTER);

As per coding guidelines, "Use SCREAMING_SNAKE_CASE for constant declarations (e.g., MAX_FILE_SIZE, DEFAULT_TIMEOUT)."

Source: Coding guidelines

apps/web/src/pages/(list-types)/siac-weekly-hearing-list/index.test.ts (1)

187-217: ⚡ Quick win

Add a malformed-JSON test case for the GET handler.

Current tests cover schema-invalid JSON, but not syntactically invalid JSON (e.g. truncated payload). A dedicated case will lock in the expected error response for parse failures.

apps/web/src/pages/(list-types)/poac-weekly-hearing-list/index.test.ts (1)

55-142: ⚡ Quick win

Align POAC negative-path coverage with the SIAC suite.

This suite currently misses JSON-file read failure and schema-validation failure scenarios, which are already covered in the SIAC equivalent tests.

apps/web/src/pages/(list-types)/paac-weekly-hearing-list/index.test.ts (1)

45-109: ⚡ Quick win

Expand PAAC error-path tests for parity with sibling controllers.

Please add cases for JSON file read failure and schema-validation failure so PAAC coverage matches SIAC behaviour checks.

libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/config.test.ts (1)

4-4: ⚡ Quick win

Add schemaPath assertions to cover the runtime validation contract.

Current tests only cover moduleRoot and assets. schemaPath is consumed by page validation, so a missing/misplaced schema would fail at runtime without test coverage.

Suggested patch
-import { assets, moduleRoot } from "./config.js";
+import { assets, moduleRoot, schemaPath } from "./config.js";
@@
   describe("assets", () => {
@@
   });
+
+  describe("schemaPath", () => {
+    it("should be an absolute path", () => {
+      expect(path.isAbsolute(schemaPath)).toBe(true);
+    });
+
+    it("should point to an existing schema file", () => {
+      expect(existsSync(schemaPath)).toBe(true);
+    });
+  });
 });

Also applies to: 13-47

libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/config.test.ts (1)

4-4: ⚡ Quick win

Cover schemaPath in config tests to protect validator wiring.

This suite does not assert schemaPath, even though downstream handlers depend on it for JSON validation initialisation.

Suggested patch
-import { assets, moduleRoot } from "./config.js";
+import { assets, moduleRoot, schemaPath } from "./config.js";
@@
   describe("assets", () => {
@@
   });
+
+  describe("schemaPath", () => {
+    it("should be an absolute path", () => {
+      expect(path.isAbsolute(schemaPath)).toBe(true);
+    });
+
+    it("should point to an existing schema file", () => {
+      expect(existsSync(schemaPath)).toBe(true);
+    });
+  });
 });

Also applies to: 13-47

libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/index.ts (1)

4-11: ⚡ Quick win

Reorder barrel exports to match the repo export-order convention.

ValidationResult (type export) is currently above value exports. Move type/interface exports to the bottom to keep module surfaces consistent.

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

Source: Coding guidelines

libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/rendering/renderer.ts (1)

4-22: ⚡ Quick win

Move interfaces/types to the bottom to match repository export ordering.

RenderOptions and RenderedData are declared before the exported function; the repo rule requires constants first, then exported functions, with interfaces/types at the bottom.

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/ftt-tax-chamber-weekly-hearing-list/src/pdf/pdf-generator.ts (1)

20-24: ⚡ Quick win

Reorder declarations to keep interfaces/types at the bottom.

PdfGenerationOptions is declared before the exported function; this breaks the repository 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

apps/web/src/pages/(list-types)/ftt-tax-chamber-weekly-hearing-list/index.test.ts (1)

76-76: ⚡ Quick win

Avoid as any in test fixtures; use typed mock artefacts.

The as any casts weaken type-safety and can mask contract drift in controller tests.

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

Also applies to: 111-111

Source: Coding guidelines

apps/web/src/pages/(list-types)/ftt-lands-registration-tribunal-weekly-hearing-list/index.test.ts (1)

75-75: ⚡ Quick win

Replace as any casts with typed test doubles.

Using as any here reduces confidence that mocked artefacts still match the real controller contract.

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

Also applies to: 110-110

Source: Coding guidelines

libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/rendering/renderer.ts (1)

4-22: ⚡ Quick win

Reorder exports to match the module ordering convention.

This file currently exports interfaces before the exported function; your project rule requires exported functions before interfaces/types.

Suggested reordering
-export interface RenderOptions {
-  locale: string;
-  courtName: string;
-  contentDate: Date;
-  lastReceivedDate: string;
-  listTitle: string;
-}
-
-export interface RenderedData {
-  header: {
-    listTitle: string;
-    weekCommencingDate: string;
-    lastUpdatedDate: string;
-    lastUpdatedTime: string;
-  };
-  hearings: FttLrtHearing[];
-}
-
 export function renderFttLrtData(hearingList: FttLrtHearingList, options: RenderOptions): RenderedData {
   const weekCommencingDate = formatDisplayDate(options.contentDate, options.locale);
   const { date: lastUpdatedDate, time: lastUpdatedTime } = formatLastUpdatedDateTime(options.lastReceivedDate, options.locale);
@@
   };
 }
+
+export interface RenderOptions {
+  locale: string;
+  courtName: string;
+  contentDate: Date;
+  lastReceivedDate: string;
+  listTitle: string;
+}
+
+export interface RenderedData {
+  header: {
+    listTitle: string;
+    weekCommencingDate: string;
+    lastUpdatedDate: string;
+    lastUpdatedTime: string;
+  };
+  hearings: FttLrtHearing[];
+}

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

apps/web/src/pages/(list-types)/ftt-rpt-london-weekly-hearing-list/index.ts (1)

17-103: 🏗️ Heavy lift

Extract a shared regional handler factory to prevent logic drift.

This controller is structurally duplicated across regional pages; defects like the JSON/type handling are likely to recur. A shared createFttRptRegionalHandler({ template, pageTitleKey, courtName }) would reduce repeat bugs.

libs/list-types/ftt-rpt-weekly-hearing-list/src/pdf/pdf-generator.test.ts (1)

83-160: ⚡ Quick win

Add a regression test for successful PDF generation with missing sizeBytes.

The suite currently does not cover the case where generatePdfFromHtml returns { success: true, pdfBuffer } without sizeBytes. Adding this test will lock in expected error handling for a real edge case.

apps/web/src/pages/(list-types)/ftt-rpt-eastern-weekly-hearing-list/index.test.ts (2)

78-78: ⚡ Quick win

Replace any artefact casts with a typed fixture.

Line 78 and Line 116 use as any, which weakens strict test guarantees and can hide shape mismatches against controller expectations.
As per coding guidelines, "Enable TypeScript strict mode and avoid any type without justification".

Also applies to: 111-116

Source: Coding guidelines


45-128: ⚡ Quick win

Add coverage for invalid JSON validation path.

The controller has a dedicated 400 branch for schema validation failures, but this suite does not assert it. Please add a case with mockValidate returning { isValid: false } and verify the 400 response path.

apps/web/src/pages/(list-types)/ftt-rpt-london-weekly-hearing-list/index.test.ts (1)

78-78: ⚡ Quick win

Replace any artefact casts with a typed fixture.

Line 78 and Line 116 use as any, which reduces confidence in controller contract checks and can mask future type regressions.
As per coding guidelines, "Enable TypeScript strict mode and avoid any type without justification".

Also applies to: 111-116

Source: Coding guidelines

apps/web/src/pages/(list-types)/ftt-rpt-midlands-weekly-hearing-list/index.test.ts (1)

78-78: ⚡ Quick win

Replace any artefact casts with a typed fixture.

Line 78 and Line 116 use as any, which weakens strict typing in these controller tests.
As per coding guidelines, "Enable TypeScript strict mode and avoid any type without justification".

Also applies to: 111-116

Source: Coding guidelines

apps/web/src/pages/(list-types)/ftt-rpt-northern-weekly-hearing-list/index.test.ts (1)

78-78: ⚡ Quick win

Replace any artefact casts with a typed fixture.

Line 78 and Line 116 use as any, which weakens type safety and can hide contract drift in test setup.
As per coding guidelines, "Enable TypeScript strict mode and avoid any type without justification".

Also applies to: 111-116

Source: Coding guidelines

apps/web/src/pages/(list-types)/ftt-rpt-southern-weekly-hearing-list/index.test.ts (1)

78-78: ⚡ Quick win

Replace any artefact casts with a typed fixture.

Line 78 and Line 116 use as any, which undermines strict typing in this test suite.
As per coding guidelines, "Enable TypeScript strict mode and avoid any type without justification".

Also applies to: 111-116

Source: Coding guidelines


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 069a8d55-5181-4079-a4a1-9240284d4092

📥 Commits

Reviewing files that changed from the base of the PR and between 4b0aea1 and 1a0ae8e.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (112)
  • apps/postgres/prisma/migrations/20260605141023_add_jurisdiction_soft_delete_and_audit_log/migration.sql
  • apps/web/src/app.ts
  • apps/web/src/pages/(list-types)/ftt-lands-registration-tribunal-weekly-hearing-list/ftt-lands-registration-tribunal-weekly-hearing-list.njk
  • apps/web/src/pages/(list-types)/ftt-lands-registration-tribunal-weekly-hearing-list/index.test.ts
  • apps/web/src/pages/(list-types)/ftt-lands-registration-tribunal-weekly-hearing-list/index.ts
  • apps/web/src/pages/(list-types)/ftt-rpt-eastern-weekly-hearing-list/ftt-rpt-eastern-weekly-hearing-list.njk
  • apps/web/src/pages/(list-types)/ftt-rpt-eastern-weekly-hearing-list/index.test.ts
  • apps/web/src/pages/(list-types)/ftt-rpt-eastern-weekly-hearing-list/index.ts
  • apps/web/src/pages/(list-types)/ftt-rpt-london-weekly-hearing-list/ftt-rpt-london-weekly-hearing-list.njk
  • apps/web/src/pages/(list-types)/ftt-rpt-london-weekly-hearing-list/index.test.ts
  • apps/web/src/pages/(list-types)/ftt-rpt-london-weekly-hearing-list/index.ts
  • apps/web/src/pages/(list-types)/ftt-rpt-midlands-weekly-hearing-list/ftt-rpt-midlands-weekly-hearing-list.njk
  • apps/web/src/pages/(list-types)/ftt-rpt-midlands-weekly-hearing-list/index.test.ts
  • apps/web/src/pages/(list-types)/ftt-rpt-midlands-weekly-hearing-list/index.ts
  • apps/web/src/pages/(list-types)/ftt-rpt-northern-weekly-hearing-list/ftt-rpt-northern-weekly-hearing-list.njk
  • apps/web/src/pages/(list-types)/ftt-rpt-northern-weekly-hearing-list/index.test.ts
  • apps/web/src/pages/(list-types)/ftt-rpt-northern-weekly-hearing-list/index.ts
  • apps/web/src/pages/(list-types)/ftt-rpt-southern-weekly-hearing-list/ftt-rpt-southern-weekly-hearing-list.njk
  • apps/web/src/pages/(list-types)/ftt-rpt-southern-weekly-hearing-list/index.test.ts
  • apps/web/src/pages/(list-types)/ftt-rpt-southern-weekly-hearing-list/index.ts
  • apps/web/src/pages/(list-types)/ftt-tax-chamber-weekly-hearing-list/ftt-tax-chamber-weekly-hearing-list.njk
  • apps/web/src/pages/(list-types)/ftt-tax-chamber-weekly-hearing-list/index.test.ts
  • apps/web/src/pages/(list-types)/ftt-tax-chamber-weekly-hearing-list/index.ts
  • apps/web/src/pages/(list-types)/paac-weekly-hearing-list/index.test.ts
  • apps/web/src/pages/(list-types)/paac-weekly-hearing-list/index.ts
  • apps/web/src/pages/(list-types)/paac-weekly-hearing-list/paac-weekly-hearing-list.njk
  • apps/web/src/pages/(list-types)/poac-weekly-hearing-list/index.test.ts
  • apps/web/src/pages/(list-types)/poac-weekly-hearing-list/index.ts
  • apps/web/src/pages/(list-types)/poac-weekly-hearing-list/poac-weekly-hearing-list.njk
  • apps/web/src/pages/(list-types)/siac-weekly-hearing-list/index.test.ts
  • apps/web/src/pages/(list-types)/siac-weekly-hearing-list/index.ts
  • apps/web/src/pages/(list-types)/siac-weekly-hearing-list/siac-weekly-hearing-list.njk
  • apps/web/src/pages/(public)/summary-of-publications/index.ts
  • biome.json
  • docs/tickets/428/plan.md
  • docs/tickets/428/review.md
  • docs/tickets/428/tasks.md
  • docs/tickets/428/ticket.md
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/package.json
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/config.test.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/config.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/conversion/ftt-lrt-config.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/email-summary/summary-builder.test.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/email-summary/summary-builder.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/index.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/locales/cy.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/locales/en.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/models/types.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/pdf/pdf-generator.test.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/pdf/pdf-generator.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/pdf/pdf-template.njk
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/rendering/renderer.test.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/rendering/renderer.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/schemas/ftt-lands-registration-tribunal-weekly-hearing-list.json
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/tsconfig.json
  • libs/list-types/ftt-rpt-weekly-hearing-list/package.json
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/config.test.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/config.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/conversion/ftt-rpt-config.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/email-summary/summary-builder.test.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/email-summary/summary-builder.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/index.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/locales/cy.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/locales/en.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/models/types.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/pdf/pdf-generator.test.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/pdf/pdf-generator.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/pdf/pdf-template.njk
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/rendering/renderer.test.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/rendering/renderer.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/schemas/ftt-rpt-weekly-hearing-list.json
  • libs/list-types/ftt-rpt-weekly-hearing-list/tsconfig.json
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/package.json
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/config.test.ts
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/config.ts
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/conversion/ftt-tax-config.ts
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/email-summary/summary-builder.test.ts
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/email-summary/summary-builder.ts
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/index.ts
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/locales/cy.ts
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/locales/en.ts
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/models/types.ts
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/pdf/pdf-generator.test.ts
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/pdf/pdf-generator.ts
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/pdf/pdf-template.njk
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/rendering/renderer.test.ts
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/rendering/renderer.ts
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/schemas/ftt-tax-chamber-weekly-hearing-list.json
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/tsconfig.json
  • libs/list-types/siac-poac-paac-weekly-hearing-list/package.json
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/config.test.ts
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/config.ts
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/conversion/siac-poac-paac-config.ts
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/email-summary/summary-builder.test.ts
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/email-summary/summary-builder.ts
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/index.ts
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/locales/cy.ts
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/locales/en.ts
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/models/types.ts
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/pdf/pdf-generator.test.ts
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/pdf/pdf-generator.ts
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/pdf/pdf-template.njk
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/rendering/renderer.test.ts
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/rendering/renderer.ts
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/schemas/siac-poac-paac-weekly-hearing-list.json
  • libs/list-types/siac-poac-paac-weekly-hearing-list/tsconfig.json
  • libs/location/src/list-type-data.ts
  • libs/notifications/package.json
  • libs/notifications/src/notification/notification-service.ts
  • libs/publication/package.json
  • libs/publication/src/processing/service.ts
  • tsconfig.json

Comment on lines +321 to +355
id: 28,
name: "SIAC_WEEKLY_HEARING_LIST",
englishFriendlyName: "Special Immigration Appeals Commission Weekly Hearing List",
welshFriendlyName: "Special Immigration Appeals Commission Weekly Hearing List",
provenance: "MANUAL_UPLOAD",
urlPath: "siac-weekly-hearing-list",
isNonStrategic: true,
defaultSensitivity: "Public",
shortenedFriendlyName: "SIAC Weekly Hearing List",
subJurisdictionIds: [25]
},
{
id: 29,
name: "POAC_WEEKLY_HEARING_LIST",
englishFriendlyName: "Proscribed Organisations Appeal Commission Weekly Hearing List",
welshFriendlyName: "Proscribed Organisations Appeal Commission Weekly Hearing List",
provenance: "MANUAL_UPLOAD",
urlPath: "poac-weekly-hearing-list",
isNonStrategic: true,
defaultSensitivity: "Public",
shortenedFriendlyName: "POAC Weekly Hearing List",
subJurisdictionIds: [23]
},
{
id: 30,
name: "PAAC_WEEKLY_HEARING_LIST",
englishFriendlyName: "Pathogens Access Appeal Commission Weekly Hearing List",
welshFriendlyName: "Pathogens Access Appeal Commission Weekly Hearing List",
provenance: "MANUAL_UPLOAD",
urlPath: "paac-weekly-hearing-list",
isNonStrategic: true,
defaultSensitivity: "Public",
shortenedFriendlyName: "PACC Weekly Hearing List",
subJurisdictionIds: [21]
},

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

🧩 Analysis chain

🏁 Script executed:

# First, locate the file and check its structure
find . -name "list-type-data.ts" -type f

Repository: hmcts/cath-service

Length of output: 100


🏁 Script executed:

# Also look for plan.md and any ticket files
find . -name "plan.md" -type f
find . -name "*.md" -type f | head -20

Repository: hmcts/cath-service

Length of output: 1702


🏁 Script executed:

# Search for references to SIAC, POAC, PAAC in the codebase to understand context
rg -i "SIAC|POAC|PAAC" --type ts --type md -A 2 -B 2

Repository: hmcts/cath-service

Length of output: 50374


🏁 Script executed:

# Read the plan.md file to find the specific lines 111-113 mentioned in the review comment
head -120 ./docs/tickets/428/plan.md | tail -20

Repository: hmcts/cath-service

Length of output: 3449


🏁 Script executed:

# Also check the ticket.md file to find line 23 and the requirement mentioned
head -30 ./docs/tickets/428/ticket.md | tail -15

Repository: hmcts/cath-service

Length of output: 1681


🏁 Script executed:

# Check if there's any documented approval or resolution of the sensitivity level question
rg "defaultSensitivity|sensitivity.*level|Public.*SIAC|SIAC.*Public" ./docs/tickets/428/ -A 2 -B 2

Repository: hmcts/cath-service

Length of output: 6838


🏁 Script executed:

# Check the actual current state of list-type-data.ts to see the exact sensitivity values
sed -n '320,360p' ./libs/location/src/list-type-data.ts

Repository: hmcts/cath-service

Length of output: 1636


🏁 Script executed:

# Check if there's any resolution or product owner decision documented in any follow-up files
rg "SIAC.*sensitivity|sensitivity.*SIAC|product owner.*SIAC|SIAC.*approval" ./docs --type md

Repository: hmcts/cath-service

Length of output: 1497


🏁 Script executed:

# Check the review.md file to see what the final recommendation was
grep -A 5 "Solution:" ./docs/tickets/428/review.md | grep -A 5 "defaultSensitivity"

Repository: hmcts/cath-service

Length of output: 388


🏁 Script executed:

# Check the git history to see if this was addressed in follow-up commits
git log --oneline --all -- "libs/location/src/list-type-data.ts" | head -20

Repository: hmcts/cath-service

Length of output: 750


🏁 Script executed:

# Check if there are any comments in the review.md or ticket.md about resolution after the review was written
tail -50 ./docs/tickets/428/review.md

Repository: hmcts/cath-service

Length of output: 5079


Obtain explicit written product owner approval before these entries are deployed to production.

Lines 328, 340, 352 set defaultSensitivity: "Public" for SIAC, POAC, and PAAC weekly hearing lists. However, the tribunal locales explicitly state: "The tribunal sometimes uses reference numbers or initials to protect the anonymity of those involved in the appeal", suggesting these lists contain protected personal information.

The ticket acceptance criterion requires that "List types are classified and user groups are decided based on authorised access", but no product owner confirmation is documented. The codebase review identified this as a critical issue requiring explicit written approval before go-live. If Public is the intended classification, document the decision in the ticket; otherwise, adjust the sensitivity level in consultation with the product owner.

junaidiqbalmoj and others added 3 commits June 19, 2026 11:04
…ngle shared template

The 5 regional FTT RPT weekly hearing list templates were byte-for-byte
identical. Move the single template into the lib's views directory and
point all regional controllers at it, removing 410 lines of duplication.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace hardcoded courtName strings in the 5 regional FTT RPT controllers
with locale file keys, consistent with how listTitle is already handled.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The build:nunjucks script used cd src/pdf before copying views, causing
the src/views glob to resolve from the wrong directory and fail with
"No matches found" on CI. Split into a separate build:views step using
find instead of a glob.

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.

@@ -0,0 +1 @@
-- No-op: changes in this migration are applied by other in-progress tickets

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.

Not sure why this change is needed. If not required we should remove it

@@ -0,0 +1,103 @@
import { readFile } from "node:fs/promises";

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.

There are 5 separate pages for the 5 RPT list types. For RCJ standard types, those list types are grouped together under the page rcj-standard-daily-cause-list. For SJP main list and SJP delta list, they are in separate pages.

I think we need to discuss and agree on a consistent approaches for this type of list types.

@@ -0,0 +1,107 @@
import { readFile } from "node:fs/promises";

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 for SIAC, POAC and PAAC, they are in separate pages here but the PDF and summary stuffs in /libs/list-types/siac-poac-paac-weekly-hearing-list are shared.

junaidiqbalmoj and others added 10 commits June 25, 2026 14:32
…publishing

Resolves conflicts from remote refactoring commits that:
- Moved NJK template into libs/ftt-rpt-weekly-hearing-list/src/views/
- Moved court names into locale files
- Fixed build:views script in package.json

Local consolidation of regional pages into single handler is preserved.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…to a single shared handler

Three identical NJK templates for siac, poac, and paac weekly hearing lists
are replaced by a single siac-poac-paac-weekly-hearing-list template in the lib.
The three individual page controllers are replaced by one handler that routes
by listTypeId (28=SIAC, 29=POAC, 30=PAAC), following the same pattern used
for FTT RPT.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All three list types now resolve to siac-poac-paac-weekly-hearing-list
instead of the deleted individual routes.

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: 6

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)/ftt-lands-registration-tribunal-weekly-hearing-list/index.test.ts (1)

63-145: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add the invalid-data branch to this suite.

The changed controller now relies on the shared validator path, but none of these tests drive mockValidate to { isValid: false }. A regression in that branch would still slip through here. Please add one case that asserts the 400 error render when validation fails.

🧹 Nitpick comments (2)
apps/web/src/pages/(list-types)/ftt-lands-registration-tribunal-weekly-hearing-list/index.test.ts (1)

77-80: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Drop the as any casts in these fixtures.

These casts sidestep the strict-mode safety the test should provide, so contract drift in the artefact or rendered payload can still compile unnoticed. Prefer typed fixtures or satisfies here. As per coding guidelines, "Enable TypeScript strict mode and avoid any type without justification".

Also applies to: 130-133

Source: Coding guidelines

apps/web/src/pages/(list-types)/ftt-rpt-weekly-hearing-list/index.test.ts (1)

111-117: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a typed Artefact fixture instead of as any in these mocks. The casts in this file suppress interface drift across all five getArtefactById stubs, so a small shared helper or Partial<Artefact> would keep the test data strict without much extra noise.

Source: Coding guidelines


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 14efb396-3f0f-4c6a-8357-059a54992c08

📥 Commits

Reviewing files that changed from the base of the PR and between 1a0ae8e and 3ffed41.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (29)
  • apps/web/src/pages/(list-types)/ftt-lands-registration-tribunal-weekly-hearing-list/index.test.ts
  • apps/web/src/pages/(list-types)/ftt-lands-registration-tribunal-weekly-hearing-list/index.ts
  • apps/web/src/pages/(list-types)/ftt-rpt-weekly-hearing-list/ftt-rpt-weekly-hearing-list.njk
  • apps/web/src/pages/(list-types)/ftt-rpt-weekly-hearing-list/index.test.ts
  • apps/web/src/pages/(list-types)/ftt-rpt-weekly-hearing-list/index.ts
  • apps/web/src/pages/(list-types)/ftt-tax-chamber-weekly-hearing-list/index.test.ts
  • apps/web/src/pages/(list-types)/ftt-tax-chamber-weekly-hearing-list/index.ts
  • apps/web/src/pages/(list-types)/siac-poac-paac-weekly-hearing-list/index.test.ts
  • apps/web/src/pages/(list-types)/siac-poac-paac-weekly-hearing-list/index.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/conversion/ftt-lrt-config.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/locales/cy.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/locales/en.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/pdf/pdf-generator.test.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/pdf/pdf-generator.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/rendering/renderer.test.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/schemas/ftt-lands-registration-tribunal-weekly-hearing-list.json
  • libs/list-types/ftt-rpt-weekly-hearing-list/package.json
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/locales/cy.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/locales/en.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/views/ftt-rpt-weekly-hearing-list.njk
  • libs/list-types/siac-poac-paac-weekly-hearing-list/package.json
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/views/siac-poac-paac-weekly-hearing-list.njk
  • libs/location/src/list-type-data.ts
  • libs/location/src/location-data.ts
  • libs/notifications/package.json
  • libs/notifications/src/notification/notification-service.ts
  • libs/publication/package.json
  • templates/tech-spec-references/welsh-translations-catalogue.json
  • tsconfig.json
💤 Files with no reviewable changes (3)
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/views/siac-poac-paac-weekly-hearing-list.njk
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/views/ftt-rpt-weekly-hearing-list.njk
  • apps/web/src/pages/(list-types)/ftt-rpt-weekly-hearing-list/ftt-rpt-weekly-hearing-list.njk
✅ Files skipped from review due to trivial changes (3)
  • libs/location/src/location-data.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/locales/en.ts
  • tsconfig.json
🚧 Files skipped from review as they are similar to previous changes (14)
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/schemas/ftt-lands-registration-tribunal-weekly-hearing-list.json
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/locales/cy.ts
  • libs/list-types/siac-poac-paac-weekly-hearing-list/package.json
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/rendering/renderer.test.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/package.json
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/conversion/ftt-lrt-config.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/locales/en.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/locales/cy.ts
  • libs/publication/package.json
  • libs/location/src/list-type-data.ts
  • libs/notifications/package.json
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/pdf/pdf-generator.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/pdf/pdf-generator.test.ts
  • libs/notifications/src/notification/notification-service.ts

Comment on lines +18 to +26
vi.mock("@hmcts/ftt-lands-registration-tribunal-weekly-hearing-list", () => ({
fttLrtWeeklyHearingListEn: {
pageTitle: "First-tier Tribunal (Land Registration Tribunal) Weekly Hearing List",
provenanceLabels: { MANUAL_UPLOAD: "Manual Upload", SNL: "ListAssist" }
},
fttLrtWeeklyHearingListCy: {
pageTitle: "First-tier Tribunal (Land Registration Tribunal) Weekly Hearing List",
provenanceLabels: { MANUAL_UPLOAD: "Lanlwytho â Llaw", SNL: "ListAssist" }
},

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use a distinct Welsh title in the locale mock.

pageTitle is identical in both locale fixtures, so the Welsh test only proves the provenance label changed. If the controller stopped forwarding the Welsh title into renderFttLrtData, this test would still pass. Give the Welsh mock a different title and assert that listTitle matches it. As per coding guidelines, "Implement Welsh language support on all user-facing text with separate en.ts and cy.ts content files".

Also applies to: 121-143

Source: Coding guidelines

Comment on lines +27 to +33
fttRptWeeklyHearingListCy: {
provenanceLabels: { MANUAL_UPLOAD: "Lanlwytho â Llaw", SNL: "ListAssist" },
rptEasternPageTitle: "First-tier Tribunal (Residential Property Tribunal): Eastern region Weekly Hearing List",
rptLondonPageTitle: "First-tier Tribunal (Residential Property Tribunal): London region Weekly Hearing List",
rptMidlandsPageTitle: "First-tier Tribunal (Residential Property Tribunal): Midlands region Weekly Hearing List",
rptNorthernPageTitle: "First-tier Tribunal (Residential Property Tribunal): Northern region Weekly Hearing List",
rptSouthernPageTitle: "First-tier Tribunal (Residential Property Tribunal): Southern region Weekly Hearing List"

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the Welsh title path observable.

The mocked cy titles on Lines 27-33 are the same as en, so the Welsh test on Lines 160-185 would still pass if the controller accidentally used enTitle. Give the Welsh mock distinct values and assert the listTitle passed to renderFttRptData.

Suggested change
   fttRptWeeklyHearingListCy: {
     provenanceLabels: { MANUAL_UPLOAD: "Lanlwytho â Llaw", SNL: "ListAssist" },
-    rptEasternPageTitle: "First-tier Tribunal (Residential Property Tribunal): Eastern region Weekly Hearing List",
-    rptLondonPageTitle: "First-tier Tribunal (Residential Property Tribunal): London region Weekly Hearing List",
-    rptMidlandsPageTitle: "First-tier Tribunal (Residential Property Tribunal): Midlands region Weekly Hearing List",
-    rptNorthernPageTitle: "First-tier Tribunal (Residential Property Tribunal): Northern region Weekly Hearing List",
-    rptSouthernPageTitle: "First-tier Tribunal (Residential Property Tribunal): Southern region Weekly Hearing List"
+    rptEasternPageTitle: "CY Eastern Weekly Hearing List",
+    rptLondonPageTitle: "CY London Weekly Hearing List",
+    rptMidlandsPageTitle: "CY Midlands Weekly Hearing List",
+    rptNorthernPageTitle: "CY Northern Weekly Hearing List",
+    rptSouthernPageTitle: "CY Southern Weekly Hearing List"
   },
-      expect(renderFttRptData).toHaveBeenCalledWith(MOCK_JSON_DATA, expect.objectContaining({ locale: "cy" }));
+      expect(renderFttRptData).toHaveBeenCalledWith(
+        MOCK_JSON_DATA,
+        expect.objectContaining({ locale: "cy", listTitle: "CY Eastern Weekly Hearing List" })
+      );

As per coding guidelines, "Implement Welsh language support on all user-facing text with separate en.ts and cy.ts content files" and "Test pages with ?lng=cy query parameter to verify Welsh content during development".

Also applies to: 160-185

Source: Coding guidelines

import type { Request, Response } from "express";
import { beforeEach, describe, expect, it, vi } from "vitest";

const mockValidate = vi.hoisted(() => vi.fn());

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Rename the test constants to match the repo rule.

mockValidate and both mockRenderedData fixtures are const declarations but are not SCREAMING_SNAKE_CASE. As per coding guidelines, "Use SCREAMING_SNAKE_CASE for constant declarations (e.g., MAX_FILE_SIZE, DEFAULT_TIMEOUT)".

Also applies to: 67-76, 134-143

Source: Coding guidelines

import { createJsonValidator } from "@hmcts/list-types-common";
import { createSimpleListTypeHandler, resolveDataSource } from "../list-type-handler.js";

const validate = createJsonValidator(schemaPath);

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Rename these constants to match the repo rule.

validate, t, and dataSource are const declarations but are not SCREAMING_SNAKE_CASE. As per coding guidelines, "Use SCREAMING_SNAKE_CASE for constant declarations (e.g., MAX_FILE_SIZE, DEFAULT_TIMEOUT)".

Also applies to: 20-20, 30-30

Source: Coding guidelines

cy,
validate,
logPrefix: "ftt-tax-chamber-weekly-hearing-list",
serverError: { errorTitle: "Server Error", errorMessage: "An error occurred while loading the list" },

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Localise the custom 500 copy.

These strings are hard-coded in English, so the Welsh route will still show English text on the server-error path. Either remove the override or make the shared handler accept locale-specific error content from en/cy. As per coding guidelines, "Provide both en and cy content objects in page controllers and render both language versions in templates" and "Implement Welsh language support on all user-facing text with separate en.ts and cy.ts content files".

Source: Coding guidelines

Comment on lines +35 to +39
res.status(400).render("errors/common", {
en,
cy,
errorTitle: "Invalid List Type",
errorMessage: "This list type is not supported by this module"

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Localise the custom error copy.

These branches hard-code English strings, so ?lng=cy will still show English text for the invalid-list-type and custom 500 paths. Move this copy into the locale content, or make the error payload locale-aware before rendering errors/common. As per coding guidelines, apps/web/src/pages/**/index.ts must “Provide both en and cy content objects in page controllers” and “Implement Welsh language support on all user-facing text with separate en.ts and cy.ts content files”.

Also applies to: 51-51

Source: Coding guidelines

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

…iacWeeklyHearingListPdf to eliminate duplication

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.

@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 (5)
libs/list-types/common/src/index.ts (1)

36-41: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep the new type re-exports at the end of this barrel block.

generateFttSiacWeeklyHearingListPdf is a value export, so FttSiacWeeklyHearingListPdfOptions and RenderedPdfData should sit after the value exports here to keep the public API ordering consistent. 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".

Source: Coding guidelines

libs/list-types/siac-poac-paac-weekly-hearing-list/src/pdf/pdf-generator.test.ts (1)

3-43: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rename the shared test fixtures to SCREAMING_SNAKE_CASE.

mockUploadBlob, mockRenderedData, and mockHearingList are module-level constants, so they should follow the repo naming rule to keep these tests aligned with linting. As per coding guidelines, "Use SCREAMING_SNAKE_CASE for constant declarations (e.g., MAX_FILE_SIZE, DEFAULT_TIMEOUT)".

Source: Coding guidelines

libs/list-types/ftt-rpt-weekly-hearing-list/src/pdf/pdf-generator.test.ts (1)

3-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rename the shared test fixtures to SCREAMING_SNAKE_CASE.

mockUploadBlob, mockRenderedData, and mockHearingList are module-level constants, so they should follow the repo naming rule to keep these tests aligned with linting. As per coding guidelines, "Use SCREAMING_SNAKE_CASE for constant declarations (e.g., MAX_FILE_SIZE, DEFAULT_TIMEOUT)".

Source: Coding guidelines

libs/list-types/common/src/pdf/pdf-utilities.ts (2)

65-82: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move the exported interfaces to the bottom of the module.

RenderedPdfData and FttSiacWeeklyHearingListPdfOptions now sit above an exported function, which breaks the repo’s export ordering rule. 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".

Source: Coding guidelines


78-79: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Require sizeBytes in the success shape.
savePdfToStorage needs sizeBytes, so a successful generatePdf result should not allow it to be omitted. Make the success branch carry both pdfBuffer and sizeBytes, or split success/failure into a discriminated union.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5de4a6a1-7559-41bf-ac97-e7d8c146fe90

📥 Commits

Reviewing files that changed from the base of the PR and between 3ffed41 and 2202932.

📒 Files selected for processing (11)
  • 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/ftt-lands-registration-tribunal-weekly-hearing-list/src/pdf/pdf-generator.test.ts
  • libs/list-types/ftt-lands-registration-tribunal-weekly-hearing-list/src/pdf/pdf-generator.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/pdf/pdf-generator.test.ts
  • libs/list-types/ftt-rpt-weekly-hearing-list/src/pdf/pdf-generator.ts
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/pdf/pdf-generator.test.ts
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/pdf/pdf-generator.ts
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/pdf/pdf-generator.test.ts
  • libs/list-types/siac-poac-paac-weekly-hearing-list/src/pdf/pdf-generator.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • libs/list-types/ftt-tax-chamber-weekly-hearing-list/src/pdf/pdf-generator.test.ts

Comment on lines +17 to +24
return generateFttSiacWeeklyHearingListPdf({
...options,
courtName: "First-tier Tribunal (Land Registration Tribunal)",
listTitle: "First-tier Tribunal (Land Registration Tribunal) Weekly Hearing List",
moduleDir: __dirname,
provenanceLabel: options.provenance ? PROVENANCE_LABELS[options.provenance as keyof typeof PROVENANCE_LABELS] || options.provenance : "",
importEn: () => import("../locales/en.js"),
importCy: () => import("../locales/cy.js"),

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Do not hard-code the Welsh-facing title in the wrapper.

Line 20 always passes the English list title, so a locale: "cy" request can never render a Welsh header from this path. Please source listTitle (and ideally courtName) from locale data or caller input instead of fixing them here.

@github-actions

github-actions Bot commented Jul 2, 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 3 commits July 3, 2026 11:01
Merges SIAC/POAC/PAAC/FTT list types (HEAD) with SEND/CIC/AST list types
(master). Both PDF generation APIs kept: generateFttSiacWeeklyHearingListPdf
and generateListPdf/buildPdfFromRenderedList. List type IDs renumbered so
SEND=38, CIC=39, AST=40 to avoid collision with SIAC(28)-FTT_RPT_SOUTHERN(37).

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

date-formatting.ts was updated to use day: "2-digit" (producing "02 January 2025"
instead of "2 January 2025"). Align renderer tests for siac-poac-paac, ftt-rpt,
ftt-tax-chamber, and ftt-lands-registration-tribunal to match the new format.

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.

junaidiqbalmoj and others added 3 commits July 3, 2026 11:20
…directories

Restored migration.sql files from their original commits for migrations
that had empty directories in the working tree, and removed orphan
directories that were never committed.

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

sonarqubecloud Bot commented Jul 3, 2026

Copy link
Copy Markdown

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

@junaidiqbalmoj
junaidiqbalmoj merged commit 3b7d84b into master Jul 3, 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.

Style Guide: Tribunal non-strategic publishing - SIAC, POAC, PAAC, FFT TC, FFT LRT & FFT RPT

2 participants