بنقرة واحدة
page-from-prototype
Create a new page and associated files by parsing a prototype page
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Create a new page and associated files by parsing a prototype page
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Fetch a Jira ticket's details (summary, description, acceptance criteria, testing notes) by ticket ID. Use whenever another skill or task needs to read a Jira ticket.
Test a page in the browser against accessibility standards.
Conventions and file structure for quote journey pages in nrf-frontend. Read before creating or modifying any page under frontend/src/server/quote/. Covers the standard file structure (routes, get-view-model, form-validation, get-next-page), quoteController / quotePostController wiring, PRG validation flow, Nunjucks template conventions, Joi rules per input type, session cache helpers, and page/accessibility test patterns.
Fetch a Confluence page's details (title, space, version, labels, body HTML) by page ID or URL. Use whenever another skill or task needs to read a Confluence page.
Reviews changed code against team coding standards. Use after writing code in a nrf-* repository
Audit and fix the @openapi JSDoc annotations across all API route and controller files in frontend/ and backend/ so the Swagger documentation matches the actual endpoint implementations. Run for one or both sub-repos.
| name | page-from-prototype |
| description | Create a new page and associated files by parsing a prototype page |
nrf-quote-4/start.htmlstart. This will be the last part of the page URL and also the folder name for the files../nrf-prototypes/prompts/implementation. This will only be used if the source page contains a form. If it's passed as a parameter, don't read the file immediately as it's large. Instructions on which section to focus on are in the form validation section below.../nrf-prototypes/app/views relative to this repository's root (i.e. the nrf-prototypes repository is a sibling directory of this one).frontend/src/server/quote that is named after the route ID, eg frontend/frontend/src/server/quote/start../nrf-prototypes/app/views/{prototype page sub-path} (relative to this repository's root). If the page can't be found, stop execution and inform the user<main> element content from the HTML page. Ignore everything outside <main> (header, footer, nav, phase banners, etc.) as these are handled by the layout template.{target folder}/index.njk following the rules below.Use frontend/src/server/quote/start/index.njk as an example of the target output format and conventions, for a simple content page not containing a form.
If the source page does contain a form, use frontend/src/server/quote/boundary-type/index.njk as an example.
The generated index.njk must:
layouts/page.njk{% block pageTitle %} containing only a {{pageTitle}} variable.beforeContent block in the source page, then create one in the generated page containing the backLink macro and set the href to the variable backLinkPath (which will be provided in the view model below)govuk-grid-column-two-thirds with govuk-grid-column-two-thirds-from-desktop<h1> tag (that will be used to set the pageTitle value in the view model later), and replace the <h1> contents with {{pageHeading}}{% block content %} containing the converted markuphref values in links with # (except mailto: links which should be kept as-is)layouts/page.njk and if not, add there rather than in the page index.njkIf the source file contains a form element, there are some extra steps:
novalidate attribute{% set legendHtml %} statement to set itdata object to formSubmitData (e.g. {{ data.nrfReference }} becomes {{ formSubmitData.nrfReference }}).data object, rename them to camelCase (e.g. formSubmitData['building-types'] becomes formSubmitData.buildingTypes). These new property names will be used in the form validation file.checked attribute of radio and checkbox elements will be set using a data property eg data['hasRedlineBoundaryFile']. For each radio or checkbox macro in the generated page: set name to the field name as a plain string (e.g. name: "boundaryEntryType"); for radios set value: formSubmitData.boundaryEntryType; for checkboxes set values: formSubmitData.hasRedlineBoundaryFile (the GOV.UK checkboxes macro expects an array, not a scalar). This ensures the previously submitted value is pre-selected when the form is re-rendered after a validation error.validationErrors.messagesByFormField to set each form group's errorMessage propertypageTitle block value with {% if validationErrors %}Error: {% endif %}validationErrors. Use titleText: "There is a problem" and errorList: validationErrors.summary.When the prototype HTML contains elements matching these patterns, convert them to the corresponding Nunjucks macro.
For each matched component, fetch the reference URL (without JavaScript) and locate the Nunjucks code example to determine the correct import statement and macro call syntax.
If it's a form field component, just pass the name attribute in, no need to pass id attribute as it will default to re-using the name for the id.
| CSS class pattern | Component | Macro reference |
|---|---|---|
govuk-button | Button | https://design-system.service.gov.uk/components/button/#button-example-nunjucks |
govuk-error-message | Error message | https://design-system.service.gov.uk/components/error-message/#error-message-example-nunjucks |
govuk-error-summary | Error summary | https://design-system.service.gov.uk/components/error-summary/#error-summary-example-nunjucks |
govuk-radios | Radios | https://design-system.service.gov.uk/components/radios/#radios-example-nunjucks |
govuk-checkboxes | Checkboxes | https://design-system.service.gov.uk/components/checkboxes/#checkboxes-example-nunjucks |
govuk-panel | Panel | https://design-system.service.gov.uk/components/panel/#panel-example-nunjucks |
This is a simple function that returns the data that will be used to render data placeholders eg {{pageTitle}} in the nunjucks view.
Create a file called get-view-model.js in the target folder with a named default export that returns an object including the following properties:
pageTitle, which should have the value of the page title that was read from the source page <h1>, plus ' - Gov.uk'pageHeading, which should have the value of the page title that was read from the source page <h1>backLinkPath - set this to '#'Create a file called form-validation.js in the target folder with a named default export function that returns a Joi schema to validate the request body from the form submission. See frontend/src/server/quote/boundary-type/form-validation.js for an example. The Joi schema should check for each form input group name that's present in the page form, using the following rules per input type:
joi.string().valid(...allowedValues).required() where allowedValues is the list of value strings from the radio/select items. Handle both 'any.required' (field absent) and 'any.only' (unrecognised value submitted) — use the same error message for both.joi.array().items(joi.string().valid(...allowedValues)).single().required() where allowedValues is the list of valid checkbox values. The .single() call is required because when only one checkbox is checked the browser submits a plain string rather than an array — .single() tells Joi to accept and wrap it. Handle 'any.required' (nothing checked) and 'any.only' (unrecognised value submitted) — use the same error message for both. Do not add 'array.min' — it is unreachable because an empty array is never submitted via a normal HTML form.'string.empty' and 'any.required' error keysjoi.string().allow('') — no error messages needed. Always include optional fields in the schema; omitting them causes Hapi to reject submissions that include them as unknown fields..email({ tlds: { allow: false } }) to validate the format. Handle 'string.empty', 'any.required', and 'string.email' (invalid format). Use tlds: { allow: false } to avoid Joi rejecting valid addresses due to unknown TLDs. The GOV.UK-standard format error message is 'Enter an email address in the correct format, like name@example.com'.convert: true by default, so use joi.number().integer().required(). Handle 'any.required' (field absent), 'number.base' (empty or non-numeric value), and 'number.integer' (fractional number submitted). Do not use joi.string() — Joi will attempt to coerce the submitted string to a number before applying further rules.If parameter 3 was not provided, use sensible placeholder error messages (e.g. 'Enter a value' for text inputs, 'Select an option' for radios/checkboxes) and at the end of the skill output display a clearly visible warning listing every field whose error message is a placeholder that needs replacing.
If parameter 3 was provided, look up the real error messages as follows:
.html extension, e.g. confirmation) within Path: rows in the content markdown file, to find the matching section and its line number. Match by checking that the slug appears as the final path segment (the part after the last /), since the prototype folder prefix in the parameter may differ from the one used in the markdown.#### Errors heading).#### Errors. For each validation error case there will be Description, Error summary and Error message rows. The Error message row contains the actual error message string to use in form-validation.js. Map each Description to the appropriate Joi error key based on the field type rules above (e.g. "without choosing an option" → 'any.required' for a radio; "without entering a value" → 'string.empty' and 'any.required' for a text input).Where the same error message string is used more than once in a field's .messages({}) call, extract it to a named const at the top of the file (outside the function) to avoid duplication. See frontend/src/server/quote/boundary-type/form-validation.js for an example.
Create a file called form-validation.test.js in the target folder. See frontend/src/server/quote/boundary-type/form-validation.test.js for the pattern to follow.
For each field in the schema, add tests that:
If the form has optional text fields, add an optional fields describe block with three tests: passes when all optional fields are absent, passes when all are empty strings, passes when all have values. Extract a validRequiredData const at the top of the file for use across tests.
Run the tests and confirm they pass.
Create a file called get-next-page.js in the target folder with a named default export that is a function that accepts the form payload as its argument and returns a path string, used by the controller to redirect to the next page after a successful form submit.
Create a file called routes.js in the target folder with a default export that is an array of route definitions.
Every page will have at least a GET route. The GET route should be passed the route ID and the view model function that was created above. See frontend/src/server/quote/start/routes.js for the pattern to follow, except for the routePath format - for new routes it should use the format /quote/{routeId}.
In addition, if the source page included a form, then also create a POST route. See frontend/src/server/quote/boundary-type/routes.js for the pattern to follow. The route should be passed the route ID, the formValidation function, the getViewModel function and the getNextPage function.
Then, import and spread the routes into frontend/src/server/quote/index.js (there is an example in there to follow for the start routes)
Create a test file in the target folder. See frontend/src/server/quote/start/page.test.js for the pattern to follow.
The first test should load the page and assert:
document.title matches the pageTitle value from the view modelhref (matching the backLinkPath value from the view model)See frontend/src/server/quote/boundary-type/page.test.js for an example of this pattern.
If the source page included a form, add the following tests. See frontend/src/server/quote/boundary-type/page.test.js for the pattern to follow:
frontend/src/test-utils/assertions.js:expectFieldsetError — for fields wrapped in a <fieldset> (radios and checkboxes). Pass document and errorMessage.expectInputError — for individual text/number inputs (not wrapped in a fieldset). Pass document, inputLabel (the visible label text), and errorMessage.location header.See the following examples -
frontend/src/server/quote/start/accessibility.test.jsfrontend/src/server/quote/boundary-type/accessibility.test.jsFor a page with a form, the test should mock validation error(s) then submit the form, so that a rendered page including validation errors is tested.