From 00c74e4587a627510fb9bd9e8eace96c11b265bd Mon Sep 17 00:00:00 2001 From: Stephen Walsh <868017+stphnwlsh@users.noreply.github.com> Date: Sun, 8 Nov 2026 16:02:51 +0000 Subject: [PATCH 1/3] Review the docs before launch Fix the facts the three-pass review found, tighten the pages that said more than they needed to, and make the site hold up on a phone. Guides: the five "Add a" guides now match code that builds and passes on a fresh solution, including the operation count test, the Lambda Invoke wrapper, the MCP tool's XML docs and icon, and the GraphQL snapshot copy. Make it yours is split under three headings and its tables are lists. Set up CI leads with the pipeline a solution ships with, then lists every check the template runs on itself, what each one needs and which to leave out, so an engineer extending the minimal pipeline has the menu in one place. How it's built keeps the rules on main, the releases and the docs. Facts: one solution name throughout, migration namespace and BOM, HTTPS redirection behind a proxy, which Infrastructure classes are internal, the Scalar authentication section, the reviews_list arguments and the service name default. Design: a long inline code chip wraps like text and a short one stays whole, tables scroll on a phone, the header and sidebar take less room and the GitHub link shows on small screens. --- astro.config.mjs | 24 +++++++- package-lock.json | 1 + package.json | 1 + src/components/docs/Footer.astro | 4 +- src/components/docs/Header.astro | 13 ++-- src/components/docs/Hero.astro | 4 +- src/components/docs/Sidebar.astro | 14 +---- src/content/docs/brand/index.mdx | 4 +- .../docs/graphql/explanation/architecture.mdx | 2 +- .../docs/graphql/explanation/decisions.mdx | 2 +- .../graphql/explanation/how-its-built.mdx | 27 ++------- src/content/docs/graphql/getting-started.mdx | 2 +- .../docs/graphql/guides/add-a-field.mdx | 6 +- src/content/docs/graphql/guides/database.mdx | 16 +++-- .../docs/graphql/guides/make-it-yours.mdx | 49 ++++++++------- .../docs/graphql/guides/run-locally.mdx | 8 +-- src/content/docs/graphql/guides/set-up-ci.mdx | 40 +++++++++---- .../graphql/guides/ship-the-container.mdx | 6 +- .../docs/graphql/guides/test-your-changes.mdx | 3 +- .../guides/work-with-a-coding-agent.mdx | 4 +- src/content/docs/graphql/index.mdx | 2 + .../docs/graphql/reference/configuration.mdx | 2 +- .../graphql/reference/project-structure.mdx | 2 +- .../docs/lambda/explanation/architecture.mdx | 6 +- .../docs/lambda/explanation/decisions.mdx | 6 +- .../docs/lambda/explanation/how-its-built.mdx | 29 ++------- src/content/docs/lambda/getting-started.mdx | 16 ++--- .../docs/lambda/guides/add-a-function.mdx | 31 ++++++---- src/content/docs/lambda/guides/database.mdx | 18 ++++-- .../docs/lambda/guides/deploy-to-aws.mdx | 10 ++-- .../docs/lambda/guides/make-it-yours.mdx | 51 +++++++++------- .../docs/lambda/guides/run-locally.mdx | 18 +++--- .../lambda/guides/secure-the-function.mdx | 6 +- src/content/docs/lambda/guides/set-up-ci.mdx | 40 +++++++++---- .../docs/lambda/guides/test-your-changes.mdx | 3 +- .../guides/work-with-a-coding-agent.mdx | 2 +- src/content/docs/lambda/index.mdx | 17 +++--- .../docs/lambda/reference/configuration.mdx | 6 +- .../docs/lambda/reference/functions.mdx | 18 +++--- .../lambda/reference/project-structure.mdx | 8 +-- .../lambda/reference/template-options.mdx | 4 +- .../docs/mcp/explanation/architecture.mdx | 2 +- .../docs/mcp/explanation/decisions.mdx | 2 +- .../docs/mcp/explanation/how-its-built.mdx | 27 ++------- src/content/docs/mcp/getting-started.mdx | 6 +- src/content/docs/mcp/guides/add-a-tool.mdx | 15 +++-- .../docs/mcp/guides/connect-a-client.mdx | 6 +- src/content/docs/mcp/guides/database.mdx | 16 +++-- src/content/docs/mcp/guides/make-it-yours.mdx | 59 +++++++++++-------- src/content/docs/mcp/guides/run-locally.mdx | 8 +-- src/content/docs/mcp/guides/set-up-ci.mdx | 40 +++++++++---- .../docs/mcp/guides/ship-the-container.mdx | 6 +- .../docs/mcp/guides/test-your-changes.mdx | 3 +- .../mcp/guides/work-with-a-coding-agent.mdx | 2 +- src/content/docs/mcp/index.mdx | 2 + .../docs/mcp/reference/configuration.mdx | 2 +- .../docs/mcp/reference/project-structure.mdx | 2 +- src/content/docs/mcp/reference/tools.mdx | 4 +- .../docs/mcp/reference/troubleshooting.mdx | 2 +- .../minimalapi/explanation/architecture.mdx | 2 +- .../docs/minimalapi/explanation/decisions.mdx | 2 +- .../minimalapi/explanation/how-its-built.mdx | 27 ++------- .../docs/minimalapi/getting-started.mdx | 2 +- .../minimalapi/guides/add-an-endpoint.mdx | 8 ++- .../docs/minimalapi/guides/database.mdx | 16 +++-- .../docs/minimalapi/guides/make-it-yours.mdx | 51 +++++++++------- .../docs/minimalapi/guides/run-locally.mdx | 8 +-- .../docs/minimalapi/guides/secure-the-api.mdx | 2 +- .../docs/minimalapi/guides/set-up-ci.mdx | 40 +++++++++---- .../minimalapi/guides/ship-the-container.mdx | 6 +- .../minimalapi/guides/test-your-changes.mdx | 3 +- .../guides/work-with-a-coding-agent.mdx | 2 +- src/content/docs/minimalapi/index.mdx | 2 + .../minimalapi/reference/configuration.mdx | 2 +- .../reference/project-structure.mdx | 2 +- .../minimalapi/reference/troubleshooting.mdx | 2 +- .../docs/webapi/explanation/architecture.mdx | 2 +- .../docs/webapi/explanation/decisions.mdx | 2 +- .../docs/webapi/explanation/how-its-built.mdx | 27 ++------- src/content/docs/webapi/getting-started.mdx | 2 +- .../docs/webapi/guides/add-an-endpoint.mdx | 8 ++- src/content/docs/webapi/guides/database.mdx | 16 +++-- .../docs/webapi/guides/make-it-yours.mdx | 49 ++++++++------- .../docs/webapi/guides/run-locally.mdx | 8 +-- .../docs/webapi/guides/secure-the-api.mdx | 2 +- src/content/docs/webapi/guides/set-up-ci.mdx | 40 +++++++++---- .../docs/webapi/guides/ship-the-container.mdx | 6 +- .../docs/webapi/guides/test-your-changes.mdx | 3 +- .../guides/work-with-a-coding-agent.mdx | 2 +- src/content/docs/webapi/index.mdx | 2 + .../docs/webapi/reference/configuration.mdx | 2 +- .../webapi/reference/project-structure.mdx | 2 +- .../docs/webapi/reference/troubleshooting.mdx | 2 +- src/styles/docs/brand.css | 1 + src/styles/docs/theme.css | 52 ++++++++++++---- 95 files changed, 635 insertions(+), 499 deletions(-) diff --git a/astro.config.mjs b/astro.config.mjs index 38e68b9..25a27a3 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,6 +1,7 @@ // @ts-check import { defineConfig } from 'astro/config'; import starlight from '@astrojs/starlight'; +import { satteri } from '@astrojs/markdown-satteri'; import starlightLinksValidator from 'starlight-links-validator'; import starlightLlmsTxt from 'starlight-llms-txt'; import starlightSidebarTopics from 'starlight-sidebar-topics'; @@ -46,10 +47,10 @@ const sidebars = { }, ], mcp: [ - { label: 'Start here', items: ['mcp/getting-started', 'mcp/guides/run-locally'] }, + { label: 'Start here', items: ['mcp/getting-started', 'mcp/guides/run-locally', 'mcp/guides/connect-a-client'] }, { label: 'Guides', - items: ['mcp/guides/make-it-yours', 'mcp/guides/connect-a-client', 'mcp/guides/add-a-tool', 'mcp/guides/test-your-changes', 'mcp/guides/database', 'mcp/guides/secure-the-server', 'mcp/guides/ship-the-container', 'mcp/guides/set-up-ci', 'mcp/guides/work-with-a-coding-agent'], + items: ['mcp/guides/make-it-yours', 'mcp/guides/add-a-tool', 'mcp/guides/test-your-changes', 'mcp/guides/database', 'mcp/guides/secure-the-server', 'mcp/guides/ship-the-container', 'mcp/guides/set-up-ci', 'mcp/guides/work-with-a-coding-agent'], }, { label: 'Reference', items: [{ autogenerate: { directory: 'mcp/reference' } }] }, { @@ -61,7 +62,7 @@ const sidebars = { { label: 'Start here', items: ['lambda/getting-started', 'lambda/guides/run-locally'] }, { label: 'Guides', - items: ['lambda/guides/make-it-yours', 'lambda/guides/add-a-function', 'lambda/guides/test-your-changes', 'lambda/guides/database', 'lambda/guides/deploy-to-aws', 'lambda/guides/secure-the-function', 'lambda/guides/set-up-ci', 'lambda/guides/work-with-a-coding-agent'], + items: ['lambda/guides/make-it-yours', 'lambda/guides/add-a-function', 'lambda/guides/test-your-changes', 'lambda/guides/database', 'lambda/guides/secure-the-function', 'lambda/guides/deploy-to-aws', 'lambda/guides/set-up-ci', 'lambda/guides/work-with-a-coding-agent'], }, { label: 'Reference', items: [{ autogenerate: { directory: 'lambda/reference' } }] }, { @@ -77,9 +78,26 @@ const sidebars = { ], }; +/* Marks inline code longer than a short name, usually a file path, so the stylesheet can let it wrap + like text instead of sitting on a line of its own. */ +const LONG_CODE = 28; +const markLongCode = { + name: 'mark-long-code', + element: { + filter: ['code'], + visit(node, ctx) { + if (ctx.parent(node)?.tagName === 'pre') return; + if (ctx.textContent(node).length <= LONG_CODE) return; + const cls = node.properties?.className; + ctx.setProperty(node, 'className', Array.isArray(cls) ? [...cls, 'cl-long'] : ['cl-long']); + }, + }, +}; + export default defineConfig({ site: 'https://leanmeancleanapps.github.io', trailingSlash: 'always', + markdown: { processor: satteri({ hastPlugins: [markLongCode] }) }, integrations: [ starlight({ title: 'Lean Mean Clean Apps', diff --git a/package-lock.json b/package-lock.json index b4f7471..fe8015d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,6 +6,7 @@ "": { "name": "lean-mean-clean-apps-site", "dependencies": { + "@astrojs/markdown-satteri": "0.4.6", "@astrojs/starlight": "0.42.8", "@fontsource-variable/bricolage-grotesque": "5.3.0", "@fontsource-variable/inter": "5.3.0", diff --git a/package.json b/package.json index 4e217bf..5be10f9 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "sync-brand": "node scripts/sync-brand.mjs" }, "dependencies": { + "@astrojs/markdown-satteri": "0.4.6", "@astrojs/starlight": "0.42.8", "@fontsource-variable/bricolage-grotesque": "5.3.0", "@fontsource-variable/inter": "5.3.0", diff --git a/src/components/docs/Footer.astro b/src/components/docs/Footer.astro index dec5fb3..aff029b 100644 --- a/src/components/docs/Footer.astro +++ b/src/components/docs/Footer.astro @@ -18,8 +18,8 @@ const community = 'https://github.com/LeanMeanCleanApps/.github/blob/main'; Sponsor

- Made by the Lean Mean Clean Apps team with Clean Architecture, strong coffee and a healthy - disregard for pomp and ceremony. Not affiliated with Microsoft, AWS, Uncle Bob or anyone with a marketing budget. + Made by the Lean Mean Clean Apps team with strong coffee and a healthy disregard for pomp and + ceremony. Not affiliated with Uncle Bob, a certain billionaire's chest piece, or anyone with a marketing budget.

diff --git a/src/components/docs/Header.astro b/src/components/docs/Header.astro index 2609144..0a95ef4 100644 --- a/src/components/docs/Header.astro +++ b/src/components/docs/Header.astro @@ -39,7 +39,7 @@ const isBrand = key === brand.key; ) } - + @@ -126,10 +126,9 @@ const isBrand = key === brand.key; background: var(--sl-color-gray-6); } - /* On a phone the organisation keeps only its mark and GitHub waits in the menu. */ + /* On a phone the organisation keeps only its mark, and on the smallest screens it gives its space to the title. */ @media (max-width: 50rem) { - .cl-org span, - .cl-icon { + .cl-org span { display: none; } @@ -137,4 +136,10 @@ const isBrand = key === brand.key; margin-inline-end: 0.25rem; } } + + @media (max-width: 30rem) { + .cl-org { + display: none; + } + } diff --git a/src/components/docs/Hero.astro b/src/components/docs/Hero.astro index bd96bcb..78fb470 100644 --- a/src/components/docs/Hero.astro +++ b/src/components/docs/Hero.astro @@ -18,11 +18,11 @@ const isBrand = key === brand.key; const match = /^(.*?),?\s*(minus the ceremony\.?)$/i.exec(title); const [lead, accent] = match ? [match[1].trim() + ',', match[2].replace(/\.?$/, '.')] : [title, '']; -const solution = template?.key === 'lambda' ? 'WorksOnMyMachine.Reviews' : 'WorksOnMyMachine.Movies'; +const solution = 'WorksOnMyMachine.Movies'; const commands = template ? [ `dotnet new install ${template.package}`, - `dotnet new ${template.shortName} --name ${solution} --authorName "Your Name"`, + `dotnet new ${template.shortName} --name ${solution}`, `cd ${solution} && docker compose up -d`, ] : []; diff --git a/src/components/docs/Sidebar.astro b/src/components/docs/Sidebar.astro index 8cb162c..272c070 100644 --- a/src/components/docs/Sidebar.astro +++ b/src/components/docs/Sidebar.astro @@ -1,5 +1,5 @@ --- -// The five templates and the brand sit at the top of the sidebar, each with its ring logo, and the sidebar below belongs to the one you're in. +// The five templates and the brand sit at the top of the sidebar, one line each with its ring logo, and the sidebar below belongs to the one you're in. import Default from '@astrojs/starlight/components/Sidebar.astro'; import { brand, templates } from '../../data/templates'; @@ -12,7 +12,6 @@ const keyOf = (link: string) => link.split('/').filter(Boolean)[0]; { topics.map((topic) => { const key = keyOf(topic.link); - const t = key === brand.key ? brand : templates.find((x) => x.key === key); const logo = key === brand.key ? '/logos/org-spectrum-small-tile.svg' : `/logos/${key}-small.svg`; const hue = key === brand.key ? 'org' : key; return ( @@ -24,7 +23,6 @@ const keyOf = (link: string) => link.split('/').filter(Boolean)[0]; > {topic.label} - {t && {t.subject}} ); @@ -55,7 +53,7 @@ const keyOf = (link: string) => link.split('/').filter(Boolean)[0]; grid-template-columns: 1.5rem 1fr; column-gap: 0.6rem; align-items: center; - padding: 0.35rem 0.6rem; + padding: 0.3rem 0.6rem; border-radius: 0.75rem; border: 1px solid transparent; color: var(--sl-color-gray-2); @@ -65,18 +63,10 @@ const keyOf = (link: string) => link.split('/').filter(Boolean)[0]; } .cl-topics img { - grid-row: span 2; width: 1.5rem; height: 1.5rem; } - .cl-topics small { - grid-column: 2; - font-weight: 400; - font-size: var(--sl-text-xs); - color: var(--sl-color-gray-3); - } - .cl-topics a:hover { color: var(--sl-color-white); border-color: color-mix(in srgb, var(--cl-topic-hue) 45%, transparent); diff --git a/src/content/docs/brand/index.mdx b/src/content/docs/brand/index.mdx index b059987..ecb7e2b 100644 --- a/src/content/docs/brand/index.mdx +++ b/src/content/docs/brand/index.mdx @@ -1,7 +1,9 @@ --- -title: Lean Mean Clean Apps – Brand +title: Brand kit description: Logos, colours, type and social templates for every Lean Mean Clean Apps template. template: splash +editUrl: false +lastUpdated: false hero: title: Everything that makes us look this clean tagline: Logos, colours, type and social templates for every Lean Mean Clean Apps template. Take what you need and put it everywhere. diff --git a/src/content/docs/graphql/explanation/architecture.mdx b/src/content/docs/graphql/explanation/architecture.mdx index 14f9df1..7c11fcb 100644 --- a/src/content/docs/graphql/explanation/architecture.mdx +++ b/src/content/docs/graphql/explanation/architecture.mdx @@ -45,7 +45,7 @@ There's a little CQRS in the style of the commands and queries, but reads and wr In textbook Clean Architecture, Presentation never references Infrastructure. Here it does, so it can wire up dependency injection without a fourth project whose only job is to call two methods. -To keep that from turning into a free-for-all, every class in Infrastructure is `internal`. Presentation can call `AddInfrastructure` and nothing else. If you try to new up a repository from a resolver, the compiler will politely decline. +To keep that from turning into a free-for-all, every class in Infrastructure except `DependencyInjection` is `internal`. Presentation can call `AddInfrastructure` and nothing else. If you try to new up a repository from a resolver, the compiler will politely decline. ## What happens on a query diff --git a/src/content/docs/graphql/explanation/decisions.mdx b/src/content/docs/graphql/explanation/decisions.mdx index c98eccd..1653b22 100644 --- a/src/content/docs/graphql/explanation/decisions.mdx +++ b/src/content/docs/graphql/explanation/decisions.mdx @@ -60,4 +60,4 @@ The one rule we bend is letting Presentation reference Infrastructure for depend ## Tests that don't share -Every test class gets its own in-memory SQLite database, built from the real migrations and the same fixed seed. Tests can run in any order, in parallel, forever, and still agree with each other. +Every test gets its own in-memory SQLite database, built from the real migrations and the same fixed seed. Tests can run in any order, in parallel, forever, and still agree with each other. diff --git a/src/content/docs/graphql/explanation/how-its-built.mdx b/src/content/docs/graphql/explanation/how-its-built.mdx index 5480490..9d197b7 100644 --- a/src/content/docs/graphql/explanation/how-its-built.mdx +++ b/src/content/docs/graphql/explanation/how-its-built.mdx @@ -1,36 +1,17 @@ --- title: "How it's built" -description: "The pipeline, the gates and the scanners that keep every pull request honest." +description: "How the template repository itself is run: the rules on main, the monthly release and where these docs come from." sidebar: order: 3 --- -import ReportCard from '../../../../components/docs/ReportCard.astro'; +This page is about the template repository, not your solution. Your solution starts with a simpler pipeline, and [Set up CI](/graphql/guides/set-up-ci/) covers what it runs, along with every check the template runs on itself and what each one needs if you want to borrow it. -This page is about how we build the template itself. Your solution starts with a simpler pipeline, covered in [Set up CI](/graphql/guides/set-up-ci/), and you can borrow any of the checks below when you're ready. - -These are templates we build for fun, but the pipeline doesn't know that. Every pull request goes through the same checks, and some of them are allowed to say no. - -**Gatekeepers** fail the build and block the merge. **Tattletales** report what they find and leave the decision to a human. - -## The checks - - +These are templates we build for fun, but the repository doesn't know that. Every pull request goes through the same checks, and some of them are allowed to say no. ## The rules on main -- Every change goes through a pull request, and every check above must pass. +- Every change goes through a pull request, and every check must pass. - Only the maintainer can merge. Pull requests from anyone are welcome, but the green button has one owner. - Commits must be signed, and merges are squashed so the history stays readable. - Release tags can't be moved or deleted once they exist, so a version always means the same code. diff --git a/src/content/docs/graphql/getting-started.mdx b/src/content/docs/graphql/getting-started.mdx index 5416646..599039c 100644 --- a/src/content/docs/graphql/getting-started.mdx +++ b/src/content/docs/graphql/getting-started.mdx @@ -13,7 +13,7 @@ By the end of this page you'll have your own solution, a GraphQL API running on You need the [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). [Docker](https://www.docker.com/products/docker-desktop) is optional, but it gets you the Aspire dashboard for the logs, traces and metrics, and a container you can ship, so it's worth having around. -## Make it yours +## Create and run your solution diff --git a/src/content/docs/graphql/guides/add-a-field.mdx b/src/content/docs/graphql/guides/add-a-field.mdx index 1990b25..98ce4f1 100644 --- a/src/content/docs/graphql/guides/add-a-field.mdx +++ b/src/content/docs/graphql/guides/add-a-field.mdx @@ -7,7 +7,7 @@ sidebar: import { Steps, Aside } from '@astrojs/starlight/components'; -This guide adds `bestReview` to the `Movie` type: the highest rated review of the movie, or null when it has none. `Movie` already carries its reviews, so this is pure Presentation work, a resolver on the type. For a field that needs new data, add a query to `src/Application` first and send it through Mediator the way the existing resolvers do. +This guide adds `bestReview` to the `Movie` type: the highest rated review of the movie, or null when it has none. `Movie` already carries its reviews, so this is pure Presentation work, a resolver on the type. For a field that needs new data, add a query to `src/Application` first and send it through Mediator the way the existing resolvers do. [Make it yours](/graphql/guides/make-it-yours/) walks through a whole new entity, from the Application layer to the tests.