2026-07-05 03:37:35 +04:00
export interface LocalizedHtmlContent {
[ locale : string ] : string ;
}
export interface LocalizedTextContent {
[ locale : string ] : string ;
}
2026-07-10 13:52:01 +04:00
export interface StaticPageSeoConfig {
title? : string | LocalizedTextContent ;
description? : string | LocalizedTextContent ;
keywords? : string ;
canonical? : string ;
ogTitle? : string | LocalizedTextContent ;
ogDescription? : string | LocalizedTextContent ;
ogImage? : string ;
robots? : string ;
}
export interface StaticPageTranslationConfig {
title? : string ;
html? : string ;
2026-07-05 03:37:35 +04:00
seo ? : {
2026-07-10 13:52:01 +04:00
title? : string ;
description? : string ;
keywords? : string ;
canonical? : string ;
ogTitle? : string ;
ogDescription? : string ;
ogImage? : string ;
feat(static-pages): extend data model with route/enabled/status/media/SEO
Milestone 1 of the Static Pages Module sprint.
- StaticPageConfig / ContentPage / ContentPageBootstrapInput gain: explicit
editable route (defaults from slug, independently overridable), enabled
(master on/off), status: 'draft'|'published' (per-page publish lifecycle,
independent of the whole-bootstrap draft/publish cycle), customTemplate,
heroImage/thumbnail/gallery, and seo.robots.
- ContentPageService: normalizePage/normalizePages default missing
enabled/status to enabled+published so existing bootstrap data never gets
silently un-published; only the editor's createPage() opts a brand-new page
into 'draft'. Legacy array-format pages get the same treatment.
- resolvePage now returns null (storefront 404) for a disabled or draft page,
regardless of whether the surrounding bootstrap itself is published -
affects the storefront static-page route AND the auto-generated footer nav
group (both go through this same resolver), which is the correct behavior.
- validatePages extended: duplicateRoutes (route can now diverge from slug),
invalidHtml, invalidSeo (canonical/ogImage URL shape, known robots tokens).
- New schema/validators/primitives.validateHtml: stack-based tag-balance
check (void/self-closing elements skipped, comments stripped). Caught and
fixed a real bug during its own spec run: the initial implementation popped
the stack back to the nearest matching ancestor on a mismatched closing
tag, which silently swallowed a genuinely unclosed inner tag instead of
flagging it - now a closing tag must match the top of the stack exactly.
- toBootstrapRecord serializes the new fields; visible mirrors enabled so any
reader of the older field name stays truthful.
- Specs: content-page.service.spec.ts (new), primitives.spec.ts (validateHtml).
Gate: tsc --noEmit, npm test (57/57), arch:check, build all green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 09:43:00 +04:00
robots? : string ;
2026-07-05 03:37:35 +04:00
} ;
2026-07-10 13:52:01 +04:00
}
export interface StaticPageConfig {
id : string ;
slug : string ;
title : string | LocalizedTextContent ;
showInFooter? : boolean ;
showInHeader? : boolean ;
showInSitemap? : boolean ;
icon? : string ;
order? : number ;
visibility ? : {
desktop? : boolean ;
tablet? : boolean ;
mobile? : boolean ;
} ;
requiresAuthentication? : boolean ;
footerGroup? : string ;
translations? : Record < string , StaticPageTranslationConfig > ;
html? : string | LocalizedHtmlContent ;
seo? : StaticPageSeoConfig ;
2026-07-05 03:37:35 +04:00
visible? : boolean ;
2026-07-10 13:52:01 +04:00
route? : string ;
content? : LocalizedHtmlContent ;
feat(static-pages): extend data model with route/enabled/status/media/SEO
Milestone 1 of the Static Pages Module sprint.
- StaticPageConfig / ContentPage / ContentPageBootstrapInput gain: explicit
editable route (defaults from slug, independently overridable), enabled
(master on/off), status: 'draft'|'published' (per-page publish lifecycle,
independent of the whole-bootstrap draft/publish cycle), customTemplate,
heroImage/thumbnail/gallery, and seo.robots.
- ContentPageService: normalizePage/normalizePages default missing
enabled/status to enabled+published so existing bootstrap data never gets
silently un-published; only the editor's createPage() opts a brand-new page
into 'draft'. Legacy array-format pages get the same treatment.
- resolvePage now returns null (storefront 404) for a disabled or draft page,
regardless of whether the surrounding bootstrap itself is published -
affects the storefront static-page route AND the auto-generated footer nav
group (both go through this same resolver), which is the correct behavior.
- validatePages extended: duplicateRoutes (route can now diverge from slug),
invalidHtml, invalidSeo (canonical/ogImage URL shape, known robots tokens).
- New schema/validators/primitives.validateHtml: stack-based tag-balance
check (void/self-closing elements skipped, comments stripped). Caught and
fixed a real bug during its own spec run: the initial implementation popped
the stack back to the nearest matching ancestor on a mismatched closing
tag, which silently swallowed a genuinely unclosed inner tag instead of
flagging it - now a closing tag must match the top of the stack exactly.
- toBootstrapRecord serializes the new fields; visible mirrors enabled so any
reader of the older field name stays truthful.
- Specs: content-page.service.spec.ts (new), primitives.spec.ts (validateHtml).
Gate: tsc --noEmit, npm test (57/57), arch:check, build all green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 09:43:00 +04:00
/** Master on/off switch. Kept in sync with `visible` on serialize; a disabled page never resolves on the storefront regardless of `status`. */
enabled? : boolean ;
/** Per-page publish lifecycle, independent of the whole-bootstrap draft/publish cycle. A `draft` page never resolves on the storefront even when the surrounding bootstrap is published. */
status ? : 'draft' | 'published' ;
customTemplate? : string ;
heroImage? : string ;
thumbnail? : string ;
gallery? : string [ ] ;
2026-07-05 03:37:35 +04:00
}
export interface LegacyStaticPageConfig {
key : string ;
route : string | { path : string ; exact? : boolean } ;
title? : string | LocalizedTextContent ;
content? : string | LocalizedHtmlContent | { value? : string ; contentType? : string ; source? : string } ;
visible? : boolean ;
}
export type StaticPagesConfig = Record < string , StaticPageConfig > | LegacyStaticPageConfig [ ] ;
export interface ResolvedStaticPage {
key : string ;
2026-07-10 13:52:01 +04:00
id : string ;
slug : string ;
2026-07-05 03:37:35 +04:00
route : string ;
title : string ;
html : string ;
2026-07-10 13:52:01 +04:00
icon? : string ;
requiresAuthentication? : boolean ;
seo ? : {
title? : string ;
description? : string ;
keywords? : string ;
canonical? : string ;
ogTitle? : string ;
ogDescription? : string ;
ogImage? : string ;
robots? : string ;
} ;
feat(static-pages): extend data model with route/enabled/status/media/SEO
Milestone 1 of the Static Pages Module sprint.
- StaticPageConfig / ContentPage / ContentPageBootstrapInput gain: explicit
editable route (defaults from slug, independently overridable), enabled
(master on/off), status: 'draft'|'published' (per-page publish lifecycle,
independent of the whole-bootstrap draft/publish cycle), customTemplate,
heroImage/thumbnail/gallery, and seo.robots.
- ContentPageService: normalizePage/normalizePages default missing
enabled/status to enabled+published so existing bootstrap data never gets
silently un-published; only the editor's createPage() opts a brand-new page
into 'draft'. Legacy array-format pages get the same treatment.
- resolvePage now returns null (storefront 404) for a disabled or draft page,
regardless of whether the surrounding bootstrap itself is published -
affects the storefront static-page route AND the auto-generated footer nav
group (both go through this same resolver), which is the correct behavior.
- validatePages extended: duplicateRoutes (route can now diverge from slug),
invalidHtml, invalidSeo (canonical/ogImage URL shape, known robots tokens).
- New schema/validators/primitives.validateHtml: stack-based tag-balance
check (void/self-closing elements skipped, comments stripped). Caught and
fixed a real bug during its own spec run: the initial implementation popped
the stack back to the nearest matching ancestor on a mismatched closing
tag, which silently swallowed a genuinely unclosed inner tag instead of
flagging it - now a closing tag must match the top of the stack exactly.
- toBootstrapRecord serializes the new fields; visible mirrors enabled so any
reader of the older field name stays truthful.
- Specs: content-page.service.spec.ts (new), primitives.spec.ts (validateHtml).
Gate: tsc --noEmit, npm test (57/57), arch:check, build all green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 09:43:00 +04:00
customTemplate? : string ;
heroImage? : string ;
thumbnail? : string ;
gallery? : string [ ] ;
2026-07-05 03:37:35 +04:00
}