diff --git a/.github/skills/doc-writer/SKILL.md b/.github/skills/doc-writer/SKILL.md index 0b782d768..bd52164cd 100644 --- a/.github/skills/doc-writer/SKILL.md +++ b/.github/skills/doc-writer/SKILL.md @@ -73,8 +73,36 @@ description: A brief summary of the page content (required for SEO) Optional frontmatter fields: - `next: false` - Disable "Next page" link for terminal pages +- `seoTitle` - Override the page's `og:title` / `twitter:title` only, + without touching the visible H1 or sidebar label. Use this **only** + when the natural H1 must stay short (commands, terse labels). When + set, the value is emitted verbatim — no `· Aspire` suffix is appended. - Custom metadata as needed by Starlight theme +#### SEO length targets + +The site uses Open Graph metadata to render social cards and feed SEO +tooling. To keep previews scannable on every social network and to +avoid the "title too short / description too long" lints that surface +on Yoast, LinkedIn, and the search-console reports, follow these +length targets when authoring frontmatter: + +| Field | Composed length target | Hard limit | +| ------------- | ---------------------: | ---------: | +| `title` | 41-51 characters | 70 characters | +| `seoTitle` | 50-60 characters | 70 characters | +| `description` | 110-160 characters | 200 characters (auto-truncated) | + +`title` becomes `og:title` composed as `${title} · Aspire`, so the +target window leaves room for the 9-character suffix. `seoTitle` +overrides the composition outright — write the full string yourself. + +Surface keywords from the article body itself in the description +(verbs, integration names, API surfaces). The CI guard at +`tests/unit/seo-lengths.vitest.test.ts` fails when any English page +strays outside the wider 30-65 / 80-200 character guard ranges, so a +draft can land slightly off-target and tighten in follow-ups. + ### Required Imports Import Starlight components at the top of your MDX file: diff --git a/src/frontend/config/redirects.mjs b/src/frontend/config/redirects.mjs index 43726d99c..9097b1a43 100644 --- a/src/frontend/config/redirects.mjs +++ b/src/frontend/config/redirects.mjs @@ -175,6 +175,8 @@ export const redirects = { '/integrations/devtools/flagd/': '/integrations/devtools/flagd/flagd-get-started/', '/integrations/devtools/goff/': '/integrations/devtools/goff/goff-get-started/', '/integrations/devtools/mailpit/': '/integrations/devtools/mailpit/mailpit-get-started/', + '/integrations/frameworks/go/': '/integrations/frameworks/go/go-get-started/', + '/integrations/frameworks/go-apps/': '/integrations/frameworks/go/go-get-started/', '/integrations/frameworks/csharp-file-based-apps/': '/integrations/dotnet/csharp-file-based-apps/', '/integrations/frameworks/maui/': '/integrations/dotnet/maui/', '/fundamentals/service-defaults/': '/get-started/csharp-service-defaults/', diff --git a/src/frontend/config/sidebar/docs.topics.ts b/src/frontend/config/sidebar/docs.topics.ts index 419aa2e62..02565d14d 100644 --- a/src/frontend/config/sidebar/docs.topics.ts +++ b/src/frontend/config/sidebar/docs.topics.ts @@ -90,6 +90,10 @@ export const docsTopics: StarlightSidebarTopicsUserConfig = { label: "What's new", collapsed: true, items: [ + { + label: 'Aspire 13.4', + slug: 'whats-new/aspire-13-4', + }, { label: 'Aspire 13.3', slug: 'whats-new/aspire-13-3', diff --git a/src/frontend/config/sidebar/integrations.topics.ts b/src/frontend/config/sidebar/integrations.topics.ts index 6a845b82b..7196d3b4c 100644 --- a/src/frontend/config/sidebar/integrations.topics.ts +++ b/src/frontend/config/sidebar/integrations.topics.ts @@ -1248,7 +1248,7 @@ export const integrationTopics: StarlightSidebarTopicsUserConfig = { }, ], }, - { + { label: 'SQLite', collapsed: true, items: [ @@ -1338,7 +1338,20 @@ export const integrationTopics: StarlightSidebarTopicsUserConfig = { ], }, { label: 'Dapr', slug: 'integrations/frameworks/dapr' }, - { label: 'Go', slug: 'integrations/frameworks/go-apps' }, + { + label: 'Go', + collapsed: true, + items: [ + { + label: 'Get started', + slug: 'integrations/frameworks/go/go-get-started', + }, + { + label: 'Set up Go apps in the AppHost', + slug: 'integrations/frameworks/go/go-host', + }, + ], + }, { label: 'Java', slug: 'integrations/frameworks/java' }, { label: 'JavaScript and Node.js', diff --git a/src/frontend/config/sidebar/reference.topics.ts b/src/frontend/config/sidebar/reference.topics.ts index 91ec7435f..402da1bcc 100644 --- a/src/frontend/config/sidebar/reference.topics.ts +++ b/src/frontend/config/sidebar/reference.topics.ts @@ -666,6 +666,10 @@ export const referenceTopics: StarlightSidebarTopicsUserConfig[number] = { label: 'ASPIREPOSTGRES001', link: '/diagnostics/aspirepostgres001', }, + { + label: 'ASPIREPROCESSCOMMAND001', + link: '/diagnostics/aspireprocesscommand001', + }, { label: 'ASPIREUSERSECRETS001', link: '/diagnostics/aspireusersecrets001', diff --git a/src/frontend/scripts/update-integrations.ts b/src/frontend/scripts/update-integrations.ts index 5ff35f5dc..743dcb9f8 100644 --- a/src/frontend/scripts/update-integrations.ts +++ b/src/frontend/scripts/update-integrations.ts @@ -21,6 +21,7 @@ const EXCLUDED_PACKAGES = [ 'Aspire.RabbitMQ.Client.v7', 'CommunityToolkit.Aspire.Hosting.Azure.StaticWebApps', 'CommunityToolkit.Aspire.Hosting.EventStore', + 'CommunityToolkit.Aspire.Hosting.Golang', 'CommunityToolkit.Aspire.EventStore', ]; const OUTPUT_PATH = './src/data/aspire-integrations.json'; diff --git a/src/frontend/src/content.config.ts b/src/frontend/src/content.config.ts index 9bd2819f9..34c8b58bb 100644 --- a/src/frontend/src/content.config.ts +++ b/src/frontend/src/content.config.ts @@ -31,6 +31,18 @@ export const collections = { * site-wide `og-image.png` is used in social cards instead. */ og: z.boolean().optional(), + /** + * SEO-only title override. Used **verbatim** as the page's + * `og:title` and `twitter:title` (no `· Aspire` suffix is + * appended) so authors can tune the social-card title to the + * 50–60 character optimal range without bloating the visible + * `

` or sidebar label. Falls back to `title` when unset. + * + * Prefer rewriting the visible `title` when the natural H1 can + * accommodate the longer string. Use `seoTitle` only when the + * sidebar/H1 must stay short (commands, terse labels, etc.). + */ + seoTitle: z.string().optional(), /** * The date the release was published to NuGet. Used on What's New * pages to display the release date near the top of the page. diff --git a/src/frontend/src/content/docs/app-host/certificate-configuration.mdx b/src/frontend/src/content/docs/app-host/certificate-configuration.mdx index 57385d665..281bd79f2 100644 --- a/src/frontend/src/content/docs/app-host/certificate-configuration.mdx +++ b/src/frontend/src/content/docs/app-host/certificate-configuration.mdx @@ -1,6 +1,7 @@ --- title: Certificate configuration -description: Learn how to configure HTTPS endpoints and certificate trust for resources in Aspire to enable secure communication. +seoTitle: Aspire HTTPS certificate configuration for AppHost +description: Configure HTTPS endpoints and certificate trust for Aspire resources to enable secure local development, container-to-container TLS, and trusted browser connections. --- import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/app-host/configuration.mdx b/src/frontend/src/content/docs/app-host/configuration.mdx index 4d665aef4..b20040a5d 100644 --- a/src/frontend/src/content/docs/app-host/configuration.mdx +++ b/src/frontend/src/content/docs/app-host/configuration.mdx @@ -1,6 +1,7 @@ --- title: AppHost configuration -description: Learn about the Aspire AppHost configuration options. +seoTitle: Aspire AppHost configuration reference and overview +description: Configure the Aspire AppHost — environment variables, launch profiles, network ports, container runtime selection, and the options that change orchestration behavior. --- import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/app-host/container-files.mdx b/src/frontend/src/content/docs/app-host/container-files.mdx index ea2186027..ddd477937 100644 --- a/src/frontend/src/content/docs/app-host/container-files.mdx +++ b/src/frontend/src/content/docs/app-host/container-files.mdx @@ -1,6 +1,7 @@ --- title: Container files -description: Learn how to inject files and directories into containers at development time and publish time using the container file APIs in Aspire. +seoTitle: Inject container files in your Aspire AppHost project +description: Inject files and directories into Aspire container resources at development and publish time using WithContainerFiles, with options for source paths and permissions. --- import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/app-host/container-registry.mdx b/src/frontend/src/content/docs/app-host/container-registry.mdx index f93eefb79..7bdb40b30 100644 --- a/src/frontend/src/content/docs/app-host/container-registry.mdx +++ b/src/frontend/src/content/docs/app-host/container-registry.mdx @@ -1,6 +1,7 @@ --- title: Container registry configuration -description: Learn how to configure container registries for your Aspire applications, including generic registries and Azure Container Registry. +seoTitle: Configure container registries for your Aspire AppHost +description: Configure container registries for Aspire — generic registries, Docker Hub, Azure Container Registry, GitHub Container Registry, and per-resource image tagging. --- import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/app-host/docker-compose-to-apphost-reference.mdx b/src/frontend/src/content/docs/app-host/docker-compose-to-apphost-reference.mdx index 999e63780..fa440161d 100644 --- a/src/frontend/src/content/docs/app-host/docker-compose-to-apphost-reference.mdx +++ b/src/frontend/src/content/docs/app-host/docker-compose-to-apphost-reference.mdx @@ -1,6 +1,6 @@ --- -title: Docker Compose to Aspire AppHost -description: Quick reference for converting Docker Compose YAML syntax to Aspire AppHost API calls. +title: Docker Compose to Aspire AppHost reference +description: Quick reference for converting Docker Compose YAML syntax to Aspire AppHost API calls — services, networks, volumes, environment variables, and health checks. --- import LearnMore from '@components/LearnMore.astro'; diff --git a/src/frontend/src/content/docs/app-host/eventing.mdx b/src/frontend/src/content/docs/app-host/eventing.mdx index deaae65d9..541525043 100644 --- a/src/frontend/src/content/docs/app-host/eventing.mdx +++ b/src/frontend/src/content/docs/app-host/eventing.mdx @@ -1,6 +1,7 @@ --- title: AppHost eventing APIs -description: Learn how to use the Aspire AppHost eventing features for lifecycle events, custom event publishing, and event-driven resource orchestration. +seoTitle: AppHost eventing APIs in your Aspire AppHost project +description: Use the Aspire AppHost eventing APIs for lifecycle events, custom event publishing, and reactive integrations that respond to resource state transitions at runtime. --- import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/app-host/executable-resources.mdx b/src/frontend/src/content/docs/app-host/executable-resources.mdx index 036fec721..d9ae3913a 100644 --- a/src/frontend/src/content/docs/app-host/executable-resources.mdx +++ b/src/frontend/src/content/docs/app-host/executable-resources.mdx @@ -1,6 +1,6 @@ --- title: Host external executables in Aspire -description: Learn how to host external executable applications in your Aspire AppHost using AddExecutable. +description: Host external executable applications in your Aspire AppHost using AddExecutable — model CLI tools, daemons, and language runtimes alongside containers and projects. --- import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/app-host/hot-reload-and-watch.mdx b/src/frontend/src/content/docs/app-host/hot-reload-and-watch.mdx index cee1742e2..8550103bf 100644 --- a/src/frontend/src/content/docs/app-host/hot-reload-and-watch.mdx +++ b/src/frontend/src/content/docs/app-host/hot-reload-and-watch.mdx @@ -1,6 +1,7 @@ --- title: Hot Reload and watch -description: Learn how hot reload works in Aspire. +seoTitle: Aspire AppHost hot reload and aspire watch overview +description: "Learn how hot reload works in Aspire and how `aspire watch` rebuilds and restarts resources automatically when project files change during development." --- import { Tabs, TabItem } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx b/src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx index cb8b862ea..d985e5679 100644 --- a/src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx +++ b/src/frontend/src/content/docs/app-host/migrate-from-docker-compose.mdx @@ -1,6 +1,6 @@ --- title: Migrate from Docker Compose to Aspire -description: Learn how to migrate your Docker Compose applications to Aspire and understand the key conceptual differences. +description: Migrate your Docker Compose applications to Aspire — map services, volumes, networks, and environment variables to AppHost APIs and modernize your developer workflow. --- import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/app-host/persistent-containers.mdx b/src/frontend/src/content/docs/app-host/persistent-containers.mdx index ed4f97630..07648e8a2 100644 --- a/src/frontend/src/content/docs/app-host/persistent-containers.mdx +++ b/src/frontend/src/content/docs/app-host/persistent-containers.mdx @@ -1,6 +1,7 @@ --- title: Persistent container lifetimes -description: Learn how to configure containers to persist and be re-used between Aspire AppHost runs. +seoTitle: Persistent container lifetimes in your Aspire AppHost +description: Configure Aspire containers to persist and be re-used between AppHost runs so databases, caches, and message brokers keep their data and accelerate the inner loop. --- import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; diff --git a/src/frontend/src/content/docs/app-host/typescript-apphost.mdx b/src/frontend/src/content/docs/app-host/typescript-apphost.mdx index 37009fc3b..2ce67aadb 100644 --- a/src/frontend/src/content/docs/app-host/typescript-apphost.mdx +++ b/src/frontend/src/content/docs/app-host/typescript-apphost.mdx @@ -1,6 +1,7 @@ --- title: TypeScript AppHost project structure -description: Learn about the files and configuration that make up a TypeScript AppHost project. +seoTitle: Aspire TypeScript AppHost project structure overview +description: Learn the files and configuration that make up a TypeScript AppHost project — entry point, package manifest, dependencies, and how the AppHost runs Aspire resources. --- import { Aside, FileTree, Steps, Tabs, TabItem } from '@astrojs/starlight/components'; @@ -138,14 +139,17 @@ await builder.build().run(); ## Package managers -The Aspire CLI automatically detects which package manager your TypeScript AppHost uses by inspecting lock files and the `packageManager` field in `package.json`. The following package managers are supported: +The Aspire CLI supports the following package managers at the **AppHost root** — the directory that contains your `apphost.ts` and `aspire.config.json`. The CLI selects between them by inspecting the `packageManager` field in `package.json` and any lock files in the AppHost root. -| Package manager | Lock file detected | Notes | +| Package manager | Lock file | Support | |---|---|---| -| npm | `package-lock.json` | Default; no extra setup required | -| pnpm | `pnpm-lock.yaml` | | -| Yarn (v4+) | `yarn.lock` | Must be Yarn 4 or later (Berry) | -| Bun | `bun.lock` / `bun.lockb` | | +| npm | `package-lock.json` | **Supported (default)** — no extra setup required | +| pnpm | `pnpm-lock.yaml` | **Supported** | +| Yarn 4+ (Berry) | `yarn.lock` (with Yarn 4 metadata) | **Supported** | +| Bun | `bun.lock` / `bun.lockb` | **Supported** | +| Yarn Classic (v1) | `yarn.lock` with `# yarn lockfile v1` | **Not supported** | + +This policy governs the **AppHost root only**. Apps the AppHost orchestrates — for example, a Node.js service added with `addNodeApp`, a Bun guest app, or a workspace package — can use any package manager their own tooling requires; they are independent of the AppHost-root toolchain.