@se-studio/skills 1.9.11 → 1.9.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @se-studio/skills
2
2
 
3
+ ## 1.9.16
4
+
5
+ ### Patch Changes
6
+
7
+ - 049abbb: Document how to place a designed HTML page: site chrome stays in the template, editor-owned or repeated sections become registered components, and HtmlComponent is only for a developer-owned island. Specimens drop embedded fonts, a second colour palette, raw forms, and hand-rolled analytics.
8
+
9
+ ## 1.9.15
10
+
11
+ ### Patch Changes
12
+
13
+ - f03f1f1: Document the weekly production Screaming Frog fleet audit.
14
+
15
+ ## 1.9.14
16
+
17
+ ### Patch Changes
18
+
19
+ - 3d4f180: State the marketing-route and layout rules in the customer architecture block, the session skill, and the page and styling skills. A new URL is a Contentful slug. Frame width is not a max-width, and a missing text style stops the plan instead of becoming `leading-[…]`.
20
+
21
+ ## 1.9.13
22
+
23
+ ### Patch Changes
24
+
25
+ - b47c1c2: Implement se-core #252 anti-Webflow-port BLOCKERs plus Nick simplicity rules (no RTF flatten, links as-is, no hardcoded visitor copy, Tailwind over CSS islands, fail closed). Add skill `se-marketing-sites-customer-simplicity`, wire from agent-session, and soften globals.css / customCss escape hatches.
26
+
27
+ ## 1.9.12
28
+
29
+ ### Patch Changes
30
+
31
+ - fbb6952: Document Option C editor-pack publish via customer CI (reusable GitHub Actions workflow). Agents regenerate and commit packs only; they do not run `gh release create` unless Nick asks.
32
+
3
33
  ## 1.9.11
4
34
 
5
35
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@se-studio/skills",
3
- "version": "1.9.11",
3
+ "version": "1.9.16",
4
4
  "description": "SE Studio agent skills for marketing site development with Contentful CMS",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,7 +28,7 @@ Before non-trivial code, run the placement checklist (in the skill). Summary:
28
28
 
29
29
  | Belongs in… | Examples |
30
30
  |-------------|----------|
31
- | **This repo** (`src/project/*`, `cms-edit/**`) | Brand components, styling, site routing, editor-pack |
31
+ | **This repo** (`src/project/*`, `cms-edit/**`) | Brand components, styling, editor-pack, and `src/lib/marketing-routes.json` (which article-type and person-type folders exist). A new URL is a Contentful slug, not a new `page.tsx`. |
32
32
  | **Customer shared package** (if monorepo) | Consent/analytics shared across sites in this customer |
33
33
  | **`se-core-product`** (`@se-studio/*`) | Fixes/features needed by 2+ sites, CMS infrastructure |
34
34
 
@@ -24,8 +24,18 @@ Source of truth: `se-core-product` `docs/PHILOSOPHY.md`. Code review: `CODE_REVI
24
24
 
25
25
  - Keep T0/T1 skeleton files thin; document deviations in the site README.
26
26
  - Use core route handlers (`generatePage`, robots, sitemaps, etc.). Do not reimplement.
27
+ - A new marketing URL is a Contentful page slug (use `indexed: false` for an experiment). Do not add `src/app/**/page.tsx` for it. App Router pages are the CMS catch-all, a folder named in `src/lib/marketing-routes.json` for an article type or a person type, and the fixed misc files (page-test, preview, sitemap, robots, markdown, download, og, api, cms-dev).
28
+ - Every marketing block is `<Section>` with `content-cols-grid`. Width is `col-span-*`, `max-w-cols-N`, or `max-w-cols-gap-N`. Type is a `fontTable` class (`h1`, `p2`, `sizingInformation.*`). Vertical space is `section-spacing` on `Section`.
29
+ - Figma stays the source for layout, copy, colour, and type when a text style is set. Implement with the grid and the font table. Do not paste MCP arbitrary classes.
30
+ - Plan-time stops: the frame width (1440, 1920, whatever the artboard is) is not `max-w-[…]`. Type with no text style (`leading-[1.2]`, raw `text-[32px]`) means the designer did not specify the font — name the node and wait. Do not pick a class and continue.
27
31
  - Mobile-first Tailwind. Preserve heading hierarchy. Size visuals with core helpers. Avoid duplicate mobile/desktop markup for the same content.
28
32
  - UI changes: early Vercel preview (mobile + laptop) → Nick visual → full breakpoints including oversize (~1920+) before deep polish/code review.
33
+ - **Remakes are not Webflow reconstruction** (PHILOSOPHY §5a / `se-marketing-sites-customer-simplicity`):
34
+ - CMS entry → registered component/collection only; **fail closed** when a field is empty (omit UI / fix CMS — never invent from the live site).
35
+ - Body/`additionalCopy` via `RtfOrString` — no RTF→plain flatten for layout.
36
+ - CMS `links` as-is with standard link helpers — no invented roles unless Nick asks.
37
+ - No hardcoded visitor copy, live URLs, or brand media fallbacks in TS.
38
+ - Tailwind + design tokens over CSS islands; do not grow Webflow-ported page CSS. `globals.css` / HtmlComponent `customCss` for true one-offs or shared primitives only.
29
39
 
30
40
  ## Caching / performance / images
31
41
 
@@ -52,14 +52,28 @@ Run all five lenses. Skip a lens only when the diff clearly cannot touch it (say
52
52
  - Consent granted by default where a CMP decides, or bypassing site consent gating.
53
53
  - Forms: preview posting to production CRM/forms destinations or GTM, or bypassing server-side submit.
54
54
  - Hard-coded heading skips, `Visual` without size helpers, or needless duplicate mobile/desktop content.
55
+ - A new `src/app/**/page.tsx` for a marketing URL. That URL is a Contentful slug (often `indexed: false` for an experiment). Allowed app pages: the CMS catch-all, an article type or person type named in `src/lib/marketing-routes.json`, and the fixed misc set (page-test, preview, sitemap, robots, markdown, download, og, api, cms-dev).
56
+ - Arbitrary layout standing in for the grid or an unspecified text style: `max-w-[1440px]` or `max-w-[1920px]` (that number is the Figma frame, not a max-width), `leading-[…]` / `text-[32px]` with no `fontTable` class, section padding via `py-[…]` instead of `<Section>`, `content-cols-grid`, and `max-w-cols-N`. Name the Figma node in the plan and wait. Do not guess a style and do not paste MCP classes.
55
57
  - Failing typecheck, lint, or tests; new behaviour with no test where the site already tests that layer.
56
58
  - Smoke/discovery/`server-config` hacks to unblock deploy smoke (belongs in `@se-studio/site-check`).
59
+ - **Remake / port simplicity** (PHILOSOPHY §5a / skill `se-marketing-sites-customer-simplicity`):
60
+ - Stub or heading-match fallback as the live renderer; unfinished types must stay unregistered or preview-only.
61
+ - Catalogue fetch (`getAllArticleLinks` / `getAllPersonLinks` / walking another page) inside a component or layout.
62
+ - Layout/behaviour multiplex on `cmsLabel` / heading / `anchor` (type ≠ label).
63
+ - Flattening body/`additionalCopy` RTF → plain strings or paragraph heuristics to drive layout (use `RtfOrString`).
64
+ - Inventing or filtering CMS `links` into roles / special chrome unless Nick explicitly asked.
65
+ - Hardcoded visitor copy, live URLs, CDN paths, or brand media fallbacks in TS — fix CMS instead.
66
+ - New Webflow/FlowKit CSS dumps or growing page CSS islands (`etf.css`-style, `fk-*`, minified sheets) for layout; prefer Tailwind + tokens. `globals.css` / `customCss` only for true one-offs or shared primitives.
67
+ - Filling missing CMS by inventing from the live site (must **fail closed**: omit UI or fix CMS).
68
+ - Second public URL system or custom App Router page for a type `generatePage` already covers.
69
+ - Mixed `@se-studio/*` majors on one site without an aligned bump plan.
57
70
 
58
71
  **NIT**
59
72
 
60
73
  - Prefer existing core components over one-offs.
61
74
  - Don’t rename existing tracking events only to match other sites.
62
75
  - Clearer names, smaller functions, docs polish.
76
+ - Pixel-perfect vs Figma before the early visual gate (not a merge blocker early). Webflow remakes follow CMS→component + tokens, not pixel CSS dumps.
63
77
 
64
78
  ---
65
79
 
@@ -70,7 +84,7 @@ If the PR changes UI, confirm the session followed agent-session visual phases:
70
84
  1. **Early:** Vercel preview, mobile (~390) + laptop (~1280), stopped for Nick’s visual review.
71
85
  2. **Full (after Nick is happy):** tablet (~768), laptop (~1280), **oversize (~1920+)**, plus mobile — flag overflow, stretched heroes, broken grids.
72
86
 
73
- Do not treat “pixel-perfect vs Figma” as a merge blocker before the early visual gate completes.
87
+ Do not treat “pixel-perfect vs Figma” as a merge blocker before the early visual gate completes. Remakes from live Webflow/HTML are **not** a fidelity chase against the old site — implement CMS fields with tokens; flag invented structure as **BLOCKER** above.
74
88
 
75
89
  ---
76
90
 
@@ -9,7 +9,32 @@ metadata:
9
9
 
10
10
  # HtmlComponent Authoring Guide
11
11
 
12
- `HtmlComponent` is a CMS content type that renders developer-authored HTML directly into the page. It bypasses the standard component registration system and is intended for one-off or highly custom layouts that the structured component library cannot produce.
12
+ `HtmlComponent` is a CMS content type that renders developer-authored HTML directly into the page. It bypasses the standard component registration system.
13
+
14
+ Author it only after the recorded call is **keep**. That call is in `packages/contentful-cms/docs/editor-tasks/create-html-component.md`. A layout the library cannot produce does not keep the section. A registered type that could render it does not promote the section. Do not use HtmlComponent + `customCss` to reconstruct a Webflow page. See `se-marketing-sites-customer-simplicity` and PHILOSOPHY §5a.
15
+
16
+ ---
17
+
18
+ ## From a designed page file
19
+
20
+ A self-contained HTML file (nav, page, footer, embedded font) is a specimen. Do not paste it into `rawHtml`. The shelf decision is in `packages/contentful-cms/docs/editor-tasks/create-html-component.md` (`cms-edit://customer/task-create-html-component`):
21
+
22
+ | Shelf | When |
23
+ |-----|------|
24
+ | Site layout | Nav, footer, menu, contact panel. Leave them in the file. |
25
+ | Registered component | An editor will change the words, media, or links, or the section repeats (on this page or another). Build or reuse a component. Do not author it here. |
26
+ | `HtmlComponent` | The recorded call is **keep**: a developer will own it, editors will not change the words, media, or links, and it does not repeat. A layout match does not decide this. A first version gets the same keep-or-promote call. Continue below only after **keep**. |
27
+
28
+ When the shelf is `HtmlComponent`:
29
+
30
+ - Drop `@font-face` and embedded font files. The site already loads the brand font.
31
+ - Drop a second `:root` palette. Use the named colour and type classes in the project style guide. Motion that those classes cannot express goes in `customCss`, using the site’s existing tokens.
32
+ - Do not paste a `<form>`. Forms use the site’s registered form.
33
+ - Do not push to `dataLayer` from `customJs`. `HtmlComponent` does not emit analytics. Clicks that must be measured are registered links.
34
+ - One page has one `h1`. Set `isHero` only when this block is that heading.
35
+ - Fill `markdownContent` with the visible sentences.
36
+
37
+ Regenerate `html-component-style-guide.md` only when that site’s tokens have changed.
13
38
 
14
39
  ---
15
40
 
@@ -299,7 +299,7 @@ export const HeroRenderer: ComponentRenderer<ProjectConfig> = ({ information })
299
299
 
300
300
  ## Code Style Requirements
301
301
 
302
- - **Styling**: Tailwind only. Do not use CSS modules (`*.module.css`). Use Tailwind classes or `src/app/globals.css` for shared styles.
302
+ - **Styling**: Tailwind utilities + design tokens first. Do not use CSS modules (`*.module.css`). Prefer classes in TSX over new CSS. `src/app/globals.css` is for **shared primitives only** (keyframes, RTF element maps, true design-system utilities) — not per-page Webflow/layout reconstruction. Growing page CSS islands is review debt (see `se-marketing-sites-customer-simplicity`).
303
303
  - **Biome** for linting/formatting (not ESLint/Prettier)
304
304
  - Single quotes, semicolons, trailing commas
305
305
  - `import type` for type-only imports
@@ -91,10 +91,14 @@ git add cms-edit/editor-pack # or cms-edit/<site>/editor-pack
91
91
  git commit -m "chore(cms-edit): regenerate editor pack"
92
92
  ```
93
93
 
94
- ## Step 6 — Publish (commit + push only)
94
+ ## Step 6 — Publish (commit + push; CI owns GitHub Releases)
95
95
 
96
96
  **Absolute rule for agents:** hosted MCP is **never** published via `vercel deploy`, `pnpm cms-edit:deploy*`, or `deploy-cms-edit-host.sh`. Commit and push is the only deploy path for customer repos with `cms-edit/host/`.
97
97
 
98
+ **Option C (shared multi-tenant host):** Customer CI publishes the committed pack as a GitHub Release (`editor-pack.tar.gz`) via the reusable workflow `Something-Else-Studio/se-core-product/.github/workflows/cms-edit-pack-publish.yml`. Agents do **not** run `gh release create` (or treat the printed command from `cms-edit host pack-publish` as something to execute) unless Nick explicitly asks. Do **not** regenerate the pack in CI — publish the committed `editor-pack/` only. Tags are immutable (`cms-edit-pack-<projectKey>-v<version>`); bump version for a new Release, then update the host registry `packTag` when intentional.
99
+
100
+ See `packages/contentful-cms/HOSTED.md` (Option C section) for the caller workflow sketch.
101
+
98
102
  ### Customer repo with `cms-edit/host/` (SE Studio, Pedestal, Headwater, Brightline, …)
99
103
 
100
104
  Commit `editor-pack/` (and any other `cms-edit/**` changes) and push **`develop`**. Hosted MCP Production is the marketing production branch (`main`, HSD `production`). Merge there only after ask + confirm (`production-merge.md`). `ignoreCommand` skips `develop` and feature refs.
@@ -108,7 +112,7 @@ Do **not** run `pnpm cms-edit:deploy` or `vercel deploy` after this step.
108
112
 
109
113
  ### Customers without `cms-edit/host/` in their repo
110
114
 
111
- Rare layout — coordinate with the repo owner. Agents still must not run deploy scripts unless explicitly asked.
115
+ Rare layout — coordinate with the repo owner. Agents still must not run deploy scripts unless explicitly asked. For Option C tenants, pack publish still goes through customer CI → GitHub Release (same reusable workflow), not a local `gh release create`.
112
116
 
113
117
  ## Homepage slug reminder
114
118
 
@@ -59,6 +59,20 @@ Prioritized P0–P3 report from a single crawl export.
59
59
 
60
60
  ---
61
61
 
62
+ ## Fleet production audit
63
+
64
+ From se-core-product, crawl every marketing production site and write P0–P3 reports. One site at a time. Quit the Screaming Frog GUI first.
65
+
66
+ ```bash
67
+ pnpm seo:screaming-frog:fleet # crawl + audit
68
+ pnpm seo:screaming-frog:fleet -- --list
69
+ node scripts/screaming-frog-fleet.mjs --install-agent
70
+ ```
71
+
72
+ Reports land in `~/spider/fleet-audits/<YYYY-MM-DD>/`. The command does not pass `--tag`, so it does not replace a deployment `content` baseline. `--install-agent` loads a user LaunchAgent (`studio.se.screaming-frog-fleet`) for Sunday 22:00 local time.
73
+
74
+ Start URL: the manifest `production` profile. When that profile is a `*.vercel.app` alias and cms-edit `productionSiteUrl` is a public host, the public host is crawled. Eagle stays on its configured Vercel production URL. Preview-only issue downgrades (noindex, preview robots) are not applied.
75
+
62
76
  ## Other commands
63
77
 
64
78
  ```bash
@@ -7,6 +7,8 @@ description: "Guide for the (cms-routes) route group and appShared pattern. Use
7
7
 
8
8
  Reference app: **example-empty** (this monorepo). Customer sites with fuller route sets: see `docs/RELATED_PROJECTS.md` (e.g. OM1 uses `resources/`, `team/`, `topics/` instead of `articles/`, `people/`, `tags/`).
9
9
 
10
+ Do not add a `page.tsx` for a marketing URL. That URL is a Contentful slug on the catch-all. Extra folders are only article types and person types listed in `src/lib/marketing-routes.json`.
11
+
10
12
  ## Route Group: (cms-routes)
11
13
 
12
14
  All CMS-driven pages live under `src/app/(cms-routes)/`. The layout enables dynamic params:
@@ -29,9 +31,9 @@ export default function CmsRoutesLayout({ children }: { children: React.ReactNod
29
31
  | `/{slug1}/{slug2}/...` | `[level1]/[...slugs]/page.ts` | Multi-level pages |
30
32
  | `/articles/` | `articles/page.ts` | Articles index (uses ARTICLES_BASE) |
31
33
  | `/articles/{type}/` | `articles/[articleType]/page.ts` | Article type index |
32
- | `/articles/{type}/{tag}/` | `articles/[articleType]/[tag]/page.ts` | Article type + tag index |
33
- | `/articles/{type}/{tag}/{article}/` | `articles/[articleType]/[tag]/[...slugs]/page.ts` | Individual article |
34
- | `/tags/`, `/tags/{tag}/` | `tags/` | Tag index (if enabled) |
34
+ | `/articles/{type}/{tag}/` | `articles/[articleType]/[tag]/page.ts` | Article type + tag index. Only when that base sets `tagInPath: true`. Hand-written `generateArticleTypeTag*` page. |
35
+ | `/articles/{type}/{tag}/{article}/` | `articles/[articleType]/[tag]/[...slugs]/page.ts` | Individual article with a tag segment. Same `tagInPath` rule. |
36
+ | `/tags/`, `/tags/{tag}/` | `tags/` | Tag index when `tags: true` |
35
37
  | `/people/`, `/people/{person}/` | `people/` | People (if enabled) |
36
38
 
37
39
  Base paths come from `@/lib/constants` (e.g. ARTICLES_BASE = `/learning-hub` or `/articles`).
@@ -97,7 +99,7 @@ export default async function (props: PageProps<'/[level1]'>) {
97
99
  }
98
100
  ```
99
101
 
100
- For article routes, use `converterContext.urlCalculators.article`, `articleType`, `articleTypeTag` to compute the path. Import `converterContext` from `@/lib/converter-context` when that module exists (so route files don't pull in cms-server); otherwise from `@/lib/cms-server`.
102
+ A dynamic `articles` route uses `converterContext.urlCalculators` (`article`, `articleType`, `articleTypeTag`). Import `converterContext` from `@/lib/converter-context` when that module exists (so route files don't pull in cms-server); otherwise from `@/lib/cms-server`. A fixed article folder, and a dynamic base whose path is not `articles`, passes the path of that file (`/work/`, `/work/${articleSlug}/`). `article()` prefixes `ARTICLES_BASE` and, when primary tags are on, inserts `other`. That is a different URL from the file that was written. The generator does this. Hand-written `[tag]` pages still use `articleTypeTag`.
101
103
 
102
104
  ## See Also
103
105
 
@@ -293,3 +293,8 @@ export const MyCollectionRegistration = defineCollection({
293
293
  * New UI or behaviour → new Contentful `collectionType` enum value + registration. Never `if (cmsLabel)` / parse labels for layout or renderer choice.
294
294
  * `cmsLabel` is for authors (and may pass to `trackingLocation`); it is not a runtime discriminator.
295
295
  * Position/variant-only differences may share one Core under multiple `defineCollection` registrations; drive layout from `collectionType`.
296
+ 9. **Simplicity (remakes / ports)**:
297
+ * Do **not** flatten item body fields for layout; use `<RtfOrString>`.
298
+ * Do **not** invent link roles from CMS `links` unless Nick asks.
299
+ * Prefer Tailwind tokens over CSS islands; empty fields → omit (**fail closed**).
300
+ * Load `se-marketing-sites-customer-simplicity` on remake tasks.
@@ -1,12 +1,20 @@
1
1
  ---
2
2
  name: se-marketing-sites-create-component
3
- description: "Guide for creating new CMS-driven components in the SE Core Product monorepo. Use this skill when asked to create a new component, ensuring adherence to the 4-layer architecture."
3
+ description: "Guide for creating new CMS-driven components in the SE Core Product monorepo. Use this skill when asked to create a new component, or when a designed HTML page needs a registered section. Ensures adherence to the 4-layer architecture."
4
4
  ---
5
5
 
6
6
  # Creating CMS Components
7
7
 
8
8
  This guide explains how to build new CMS-driven components following the established architecture patterns in this codebase.
9
9
 
10
+ ## When the brief is a designed HTML page
11
+
12
+ Read `packages/contentful-cms/docs/editor-tasks/create-html-component.md` and record **keep** or **promote** for each section before writing code. A first version with no designed file gets the same call. Do not start the four layers until the call is **promote**. Do not open the HTML playbook until the call is **keep**.
13
+
14
+ **Promote** is required when an editor will change the words, media, or links, or the section repeats (on this page or another). Then follow the four layers below. Do not paste the HTML document in as the component. Leave nav, footer, menu, and the contact panel to the page template.
15
+
16
+ **Keep** is allowed only when a developer will own it, an editor will not change the words, media, or links, and it does not repeat. Motion, a tool demo, or vendor JS can be that island. A layout match does not promote it, and a new layout does not keep it. The keep path is the playbook above, including the project HTML style guide.
17
+
10
18
  ## Architecture Overview
11
19
 
12
20
  All components follow a **four-layer architecture** and must remain **Server Components** by default.
@@ -231,9 +239,10 @@ export const MyNewRegistration = defineComponent({
231
239
  * Add `'use client'` to that file only.
232
240
  * Import and use in Core component.
233
241
  5. **Build Wrapper Component**:
234
- * Wrap Core with `<Section>`.
242
+ * Wrap Core with `<Section>` (`content-cols-grid`, `section-spacing`). Do not replace Section with `max-w-[1440px]` or `py-16`.
235
243
  * Pass `componentName={componentType}` and `information`.
236
- * Set layout (e.g., `positionClassName="col-span-full"`).
244
+ * Set layout with `col-span-*`, `max-w-cols-N`, or `max-w-cols-gap-N`.
245
+ * Type is a `fontTable` class or `sizingInformation.*`. A Figma frame width is not a max-width. A node with no text style (`leading-[1.2]`, raw `text-[32px]`) stops the plan — do not guess a class.
237
246
  6. **Build Renderer**:
238
247
  * Default export (short name).
239
248
  * Wrap with `<UnusedChecker>`.
@@ -248,3 +257,9 @@ export const MyNewRegistration = defineComponent({
248
257
  * New UI or behaviour → new Contentful `componentType` enum value + registration. Never `if (cmsLabel)` / parse labels for layout or renderer choice.
249
258
  * `cmsLabel` is for authors (and may pass to `trackingLocation`); it is not a runtime discriminator.
250
259
  * Position/variant-only differences may share one Core under multiple `defineComponent` registrations; drive layout from `componentType`.
260
+ 10. **Simplicity (remakes / ports)**:
261
+ * Layers are the registration pattern — not an invitation to bespoke parsers.
262
+ * Do **not** flatten body/`additionalCopy` for layout; use `<RtfOrString>`.
263
+ * Do **not** invent or filter CMS `links` into roles unless Nick asks.
264
+ * Prefer Tailwind tokens over new `globals.css` layout rules; CSS islands are debt.
265
+ * Empty field → omit UI (**fail closed**). Load `se-marketing-sites-customer-simplicity` on remake tasks. Its HtmlComponent escape hatch does not move a section onto or off HtmlComponent after **keep** or **promote** is recorded.
@@ -9,6 +9,18 @@ This guide explains how to create new pages and handle routing in the SE Core Pr
9
9
 
10
10
  Reference app: **example-empty** (this monorepo). Customer implementations: see `docs/RELATED_PROJECTS.md`.
11
11
 
12
+ ## Do not add a route for a marketing URL
13
+
14
+ A new URL is a Contentful page slug, served by the catch-all (`[level1]` and `[...slugs]`). An experiment is a CMS page with `indexed: false`, not a new folder under `src/app`.
15
+
16
+ App Router `page` files are only:
17
+
18
+ - the CMS catch-all
19
+ - a folder named in `src/lib/marketing-routes.json` for an article type or a person type (`node scripts/generate-marketing-routes.mjs <app> --write` writes the thin article index and detail wrappers; `[tag]` segments are hand-written when that base sets `tagInPath: true`)
20
+ - the fixed misc files (page-test, preview, sitemap, robots, markdown, download, og, api, cms-dev)
21
+
22
+ `pnpm skeleton:check` fails an extra `page.ts` once `marketing-routes.json` is present. Search and other non-page tools stay misc routes. They are not a second copy of a CMS page.
23
+
12
24
  ## Page Architecture
13
25
 
14
26
  ### 1. (cms-routes) Route Group
@@ -33,9 +45,9 @@ export default function CmsRoutesLayout({ children }: { children: React.ReactNod
33
45
  | `/{slug1}/{slug2}/...` | `[level1]/[...slugs]/page.ts` | Multi-level pages |
34
46
  | `/articles/` | `articles/page.ts` | Articles index (uses ARTICLES_BASE from constants) |
35
47
  | `/articles/{type}/` | `articles/[articleType]/page.ts` | Article type index |
36
- | `/articles/{type}/{tag}/` | `articles/[articleType]/[tag]/page.ts` | Article type + tag index |
37
- | `/articles/{type}/{tag}/{article}/` | `articles/[articleType]/[tag]/[...slugs]/page.ts` | Individual article |
38
- | `/tags/`, `/tags/{tag}/` | `tags/` | Tag index (if enabled) |
48
+ | `/articles/{type}/{tag}/` | `articles/[articleType]/[tag]/page.ts` | Article type + tag index. Only when that base sets `tagInPath: true`. Hand-written `generateArticleTypeTag*` page. `--write` does not emit it. |
49
+ | `/articles/{type}/{tag}/{article}/` | `articles/[articleType]/[tag]/[...slugs]/page.ts` | Individual article with a tag segment. Same `tagInPath` rule. |
50
+ | `/tags/`, `/tags/{tag}/` | `tags/` | Tag index when `tags: true` |
39
51
  | `/people/`, `/people/{person}/` | `people/` | People (if enabled) |
40
52
 
41
53
  Base paths (e.g. `/articles` vs `/learning-hub`) come from `@/lib/constants`.
@@ -104,19 +116,9 @@ The appShared modules render content with:
104
116
 
105
117
  For route files that only need `converterContext` or `buildInformation` (e.g. `generateStaticParams`, sitemap, path computation), import from `@/lib/converter-context` when that module exists, so you don't pull in cms-server.
106
118
 
107
- ## Creating a Specialized Route
108
-
109
- For a route that behaves differently from standard CMS pages (e.g. search, dashboard):
110
-
111
- 1. Create the route under `(cms-routes)` or a separate route group.
112
- 2. Either create a new appShared module (if the pattern is reusable) or implement inline.
113
- 3. Use `getPageWithErrors`, `getArticleWithErrors`, etc. from `@/lib/cms-server`.
114
- 4. Use `projectRendererConfig` from `@/lib/cms-server`.
115
- 5. Render with `CmsContent` using `contents`, `rendererConfig`, and `pageContext`.
116
-
117
119
  ## Custom Layouts
118
120
 
119
- If a route needs a different layout (e.g. no header/footer), create `layout.tsx` in that route directory.
121
+ A different chrome (for example no header) is a `layout.tsx` on a route that already exists. It is not a new URL. A new marketing URL is still a Contentful slug.
120
122
 
121
123
  ## Troubleshooting
122
124
 
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: se-marketing-sites-customer-simplicity
3
+ description: "Guardrail for customer marketing remakes and ports. Load on Webflow/HTML remake, match-live-site, or parity tasks: CMS to component only, fail closed, no RTF flatten, link inventing, CSS islands, or hardcoded copy."
4
+ ---
5
+
6
+ # Customer site simplicity (remakes / ports)
7
+
8
+ CMS field in → registered UI out. Do not reconstruct the live site.
9
+
10
+ Canonical: `docs/PHILOSOPHY.md` §5a. Review: `customer-code-review.md`. Session: `site-workflows-agent-session` (**Do not port Webflow / HTML pages**). Subtract first: `principle-subtract-before-you-add`. How to build a type: `se-marketing-sites-create-component` / `create-collection`.
11
+
12
+ ## Do
13
+
14
+ - CMS entry → `componentType` / `collectionType` → Registration → Core on core route handlers
15
+ - Empty field → **omit** that UI (or fix CMS). Never invent from the live site
16
+ - Body / `additionalCopy` via `RtfOrString`
17
+ - CMS `links` as-is with `SectionLinks` / `TrackedLink` (or site equivalents)
18
+ - Tailwind + design tokens; `Visual` + `calculateVisualSizes`; `getSizingInformation`
19
+
20
+ ## Do not (BLOCKER)
21
+
22
+ | Antipattern | Instead |
23
+ |-------------|---------|
24
+ | Stub / heading-match as live renderer | Full layers, or stay unregistered |
25
+ | Catalogue fetch inside a component | Collection `contents` / related fields |
26
+ | Multiplex on `cmsLabel` / heading / `anchor` | One type = one layout (R4.2a) |
27
+ | RTF → plain / paragraph heuristics for layout | `RtfOrString` only |
28
+ | Invent / filter `links` into roles | Render links as given (unless Nick asks) |
29
+ | Hardcoded visitor copy, live URLs, CDN/media fallbacks | Fix CMS / import |
30
+ | Webflow/FlowKit CSS dumps / page CSS islands | Tokens + Tailwind utilities |
31
+ | Second public URL system / custom page for `generatePage` types | One IA; type owns the prefix |
32
+ | Mixed `@se-studio/*` majors | Aligned bump |
33
+
34
+ ## Escape hatches (narrow)
35
+
36
+ - `globals.css`: shared primitives only (keyframes, RTF element maps, true design-system utilities) — **not** per-page layout ports
37
+ - HtmlComponent + `customCss`: only when the recorded call is **keep** (`create-html-component.md`). A layout a registered type cannot express does not make that call. Do not move a section onto or off HtmlComponent after **keep** or **promote** is recorded. **Not** the default Webflow remake path.
38
+
39
+ ## Related
40
+
41
+ - `site-workflows-agent-session`, `se-marketing-sites-styling-system`, `coding-discipline`
42
+ - Do not load Cursor Webflow DevLink / FlowKit skills on `@se-studio` customer sites
@@ -93,6 +93,16 @@ While configurable, most projects use:
93
93
  * `laptop`: ~1024px+
94
94
  * `desktop`: ~1440px+
95
95
 
96
+ Desktop at 1440 is the artboard the grid is built from. It is not a `max-w-[1440px]`. The grid (`container-cols-grid` outside, `content-cols-grid` inside) is what changes at other widths.
97
+
98
+ ### Sections
99
+
100
+ A marketing block is `<Section>` from `@/framework/Section`. That sets `container-cols-grid` and `section-spacing`. Do not replace it with `mx-auto max-w-[…] px-… py-16`.
101
+
102
+ Width inside the section is a column span, `max-w-cols-N`, or `max-w-cols-gap-N` (spacing tokens from `--spacing-cols-*`). Type is a `fontTable` class (`h1`, `p1`) or `sizingInformation.h1` from `getSizingInformation`. Do not write `text-[32px]`, `leading-[1.2]`, or `tracking-[…]`.
103
+
104
+ If Figma has no text style on a node, stop and name that node. Do not guess a class. If the only width in the file is the frame, use the grid.
105
+
96
106
  ### Layout Helpers
97
107
 
98
108
  Common layout patterns using Tailwind grid utilities:
@@ -124,9 +134,13 @@ Wrap the `RtfOrString` component with the appropriate class:
124
134
 
125
135
  ## Global Styles
126
136
 
127
- Project-specific global styles, animations, and custom utility classes are located in `src/app/globals.css`. This file imports the generated Tailwind CSS and defines:
137
+ Project-specific global styles live in `src/app/globals.css`. Prefer **Tailwind utilities and design tokens in TSX** for layout. Treat new layout selectors in `globals.css` or extra `*.css` files as **review debt** unless they are shared design-system primitives.
138
+
139
+ `globals.css` is appropriate for:
128
140
 
129
141
  * Root variables (if any)
130
- * Animation keyframes
131
- * Custom component classes (e.g., `.btn-primary`)
132
- * Rich Text Formatting classes
142
+ * Animation keyframes / `--animate-*` tokens
143
+ * Rich Text Formatting element maps (`.rtf-*`)
144
+ * True shared design-system utilities (rare; prefer tokens)
145
+
146
+ Do **not** grow per-page Webflow ports or CSS islands for layout (see `se-marketing-sites-customer-simplicity`). HtmlComponent `customCss` is a last-resort escape hatch for one-offs, not the default remake path.
@@ -231,9 +231,26 @@ When editing Contentful in parallel on the same space, use distinct cms-edit ses
231
231
  - **Do not** edit `se-core-product` unless placement is `core` and user approves mode switch
232
232
  - Consume `@se-studio/*` from npm — not monorepo workspace links
233
233
 
234
+ ### Do not port Webflow / HTML pages
235
+
236
+ Rebuild remakes as **CMS components and collections** on core handlers (`generatePage`, registrations, `RtfOrString`, Tailwind tokens). Never “match this Webflow section in one file,” dump FlowKit/`fk-*` CSS, multiplex on `cmsLabel`/heading, flatten RTF for layout, invent link roles, or hardcode live copy/URLs. **Fail closed** when CMS is empty — omit UI or fix CMS; do not invent from the live site.
237
+
238
+ Load skill **`se-marketing-sites-customer-simplicity`** on any Webflow/HTML remake, “match the live site,” or parity task. Also: `principle-subtract-before-you-add`. Canonical rules: `docs/PHILOSOPHY.md` §5a; review BLOCKERs in [`customer-code-review.md`](../../references/agent-session/customer-code-review.md).
239
+
240
+ Do **not** use Cursor Webflow DevLink / FlowKit skills on `@se-studio` customer sites (wrong stack: CSS modules / `_webflow-style.css`).
241
+
234
242
  ### Figma direction (new designs) + phased visual gates
235
243
 
236
- **Until the user explicitly says otherwise**, when implementing UI from a Figma file or node, treat Figma as the **direction / source of truth** for structure, spacing, type, colour, radii, alignment, and control patterns. Do not “improve” or normalize away from the comps to match older site patterns. Prefer Figma MCP design context over CMS drafts or live-site memory.
244
+ **Until the user explicitly says otherwise**, when implementing UI from a **new** Figma file or node, treat Figma as the **direction / source of truth** for structure, spacing, type, colour, radii, alignment, and control patterns. Do not “improve” or normalize away from the comps to match older site patterns. Prefer Figma MCP design context over CMS drafts or live-site memory.
245
+
246
+ Two things in that file are not decisions. Raise them in the plan and do not write the code until there is a concrete answer:
247
+
248
+ - The frame width (1440, 1920, whatever the artboard is) is one canvas size. The grid is how that frame adapts at other widths. It is not `max-w-[1440px]`. If the comp really seems to need a hard cap at the frame width, say so and wait.
249
+ - Type with no text style (`leading-[1.2]`, raw `text-[32px]`) means the designer did not specify the font. Name the node. Do not copy the leading and do not guess a `fontTable` class (`h1`, `p1`, `sizingInformation.*`).
250
+
251
+ Implement what Figma did specify with `<Section>`, `content-cols-grid`, column spans or `max-w-cols-N` / `max-w-cols-gap-N`, and a font-table class. Do not paste arbitrary classes from Figma MCP.
252
+
253
+ **Remakes from live Webflow/HTML are different:** Figma SoT does **not** apply. Use CMS structure + design tokens; do not chase pixel CSS dumps from the old site. See **Do not port Webflow / HTML pages** above.
237
254
 
238
255
  **Do not** chase pixel-perfect polish before the **early visual gate**. Iterate with Nick on a Vercel preview first.
239
256
 
@@ -259,7 +276,7 @@ Flag layout blowouts, overflow, sparse/stretched heroes, broken grids, and type
259
276
 
260
277
  Non-UI changes skip visual phases and go to code review.
261
278
 
262
- **Related skills:** `site-workflows-figma-design-snapshot` / `site-workflows-apply-design-snapshot`; Figma MCP `get_design_context`.
279
+ **Related skills:** `se-marketing-sites-customer-simplicity` (remakes / ports); `principle-subtract-before-you-add`; `site-workflows-figma-design-snapshot` / `site-workflows-apply-design-snapshot`; Figma MCP `get_design_context`.
263
280
 
264
281
  ### Cross-project handoffs
265
282
 
@@ -247,13 +247,15 @@ Use `getSizingInformation(index)` from `@/lib/SizingInformation` for dynamic sem
247
247
  | laptop | 1024px | 12 |
248
248
  | desktop | 1440px | 12 |
249
249
 
250
- Gap: 16px at all breakpoints. Margin: 16px at all breakpoints.
250
+ 1440 is the desktop artboard. It is not `max-w-[1440px]`. The grid is what adapts at other widths.
251
251
 
252
- Use `content-cols-grid` for standard content layout.
252
+ Gap and margin come from `tailwind.config.json`.
253
+
254
+ A marketing block is `<Section>` (`container-cols-grid` + `section-spacing`) with an inner `content-cols-grid`. Width is `col-span-*`, `max-w-cols-N`, or `max-w-cols-gap-N`. Type is a `fontTable` class. Do not use `py-16` as section padding, or `leading-[…]` / `text-[32px]` when the file has no text style — stop and ask which style.
253
255
 
254
256
  ## Section Spacing
255
257
 
256
- Standard vertical padding: `py-16 laptop:py-24`
258
+ Vertical rhythm is `section-spacing` on `<Section>`, not a hand-written `py-*`.
257
259
 
258
260
  ## RTF Classes
259
261