Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/brownfield-workflow.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Ralf D. Müller

== Introduction

You have mastered the link:#/workflow[greenfield workflow].
You have mastered the link:#/spec-driven-development[greenfield workflow].
Now you want to apply it to an existing codebase.

The core principles remain the same: small steps, high autonomy, error correction loops.
Expand Down Expand Up @@ -152,7 +152,7 @@ Stable code that nobody touches does not need specs.
|link:#/anchor/tdd-london-school[TDD London] / link:#/anchor/tdd-chicago-school[Chicago]

|Continue
|Follow link:#/workflow[the standard workflow] from Step 3 (PRD) or Step 8 (Implementation), depending on whether you are adding new features or fixing bugs.
|Follow link:#/spec-driven-development[the standard workflow] from Step 3 (PRD) or Step 8 (Implementation), depending on whether you are adding new features or fixing bugs.
|{empty}--
|===

Expand Down
4 changes: 2 additions & 2 deletions docs/brownfield-workflow.de.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Ralf D. Müller

== Einleitung

Du hast den link:#/workflow[Greenfield-Workflow] gemeistert.
Du hast den link:#/spec-driven-development[Greenfield-Workflow] gemeistert.
Jetzt willst du ihn auf eine bestehende Codebasis anwenden.

Die Grundprinzipien bleiben gleich: kleine Schritte, hohe Autonomie, Fehlerkorrektur-Schleifen.
Expand Down Expand Up @@ -151,7 +151,7 @@ Stabiler Code, den niemand anfasst, braucht keine Specs.
|link:#/anchor/tdd-london-school[TDD London] / link:#/anchor/tdd-chicago-school[Chicago]

|Weiter
|Ab hier dem link:#/workflow[Standard-Workflow] ab Schritt 3 (PRD) oder Schritt 8 (Implementierung) folgen, je nachdem ob neue Features oder Bugs bearbeitet werden.
|Ab hier dem link:#/spec-driven-development[Standard-Workflow] ab Schritt 3 (PRD) oder Schritt 8 (Implementierung) folgen, je nachdem ob neue Features oder Bugs bearbeitet werden.
|{empty}--
|===

Expand Down
2 changes: 1 addition & 1 deletion docs/spec-driven-workflow.adoc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
= The Semantic Anchors Development Workflow
= Spec-Driven Development with Semantic Anchors
Ralf D. Müller
2026-03-14
:toc:
Expand Down
2 changes: 1 addition & 1 deletion docs/spec-driven-workflow.de.adoc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
= Der Semantic Anchors Entwicklungs-Workflow
= Spec-Driven Development mit Semantic Anchors
:author: Ralf D. Müller
:revdate: 2026-03-14
:toc:
Expand Down
2 changes: 1 addition & 1 deletion scripts/generate-sitemap.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const BASE_URL = 'https://llm-coding.github.io/Semantic-Anchors'
const PAGES = [
{ path: '/', priority: '1.0', changefreq: 'weekly' },
{ path: '/about', priority: '0.8', changefreq: 'monthly' },
{ path: '/workflow', priority: '0.8', changefreq: 'monthly' },
{ path: '/spec-driven-development', priority: '0.8', changefreq: 'monthly' },
{ path: '/brownfield', priority: '0.8', changefreq: 'monthly' },
{ path: '/evaluations', priority: '0.8', changefreq: 'monthly' },
{ path: '/all-anchors', priority: '0.8', changefreq: 'weekly' },
Expand Down
20 changes: 18 additions & 2 deletions scripts/prerender-routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,14 @@ const ROUTES = [
},
{
path: '/workflow',
redirectTo: '/spec-driven-development',
},
{
path: '/spec-driven-development',
fragment: 'docs/spec-driven-workflow.html',
title: 'Development Workflow — Semantic Anchors',
title: 'Spec-Driven Development with Semantic Anchors',
description:
'The Semantic Anchors spec-driven development workflow — from requirements to specification to implementation, powered by semantic anchors.',
'Spec-driven development workflow — from requirements to specification to implementation, powered by semantic anchors.',
},
Comment thread
coderabbitai[bot] marked this conversation as resolved.
{
path: '/brownfield',
Expand Down Expand Up @@ -158,6 +162,18 @@ function buildDocContentMarkup(fragmentHtml) {
* @throws {Error} When the configured fragment file does not exist.
*/
function prerenderRoute(shell, route) {
if (route.redirectTo) {
const outDir = path.join(DIST, route.path)
const outFile = path.join(outDir, 'index.html')
fs.mkdirSync(outDir, { recursive: true })
fs.writeFileSync(
outFile,
`<!doctype html><meta charset="utf-8"><link rel="canonical" href="https://llm-coding.github.io/Semantic-Anchors${route.redirectTo}"><meta http-equiv="refresh" content="0;url=${route.redirectTo}"><script>location.replace('${route.redirectTo}')</script>`,
'utf-8'
)
return
}

const fragmentPath = path.join(DIST, route.fragment)
if (!fs.existsSync(fragmentPath)) {
throw new Error(
Expand Down
4 changes: 2 additions & 2 deletions website/src/components/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function renderHeader() {
<div class="flex items-center gap-6 text-2xl">
<a href="#/" class="nav-link text-[var(--color-text-secondary)] hover:text-[var(--color-text)] transition-colors" data-route="/" data-i18n="nav.catalog">${i18n.t('nav.catalog')}</a>
<a href="#/contracts" class="nav-link text-[var(--color-text-secondary)] hover:text-[var(--color-text)] transition-colors" data-route="/contracts" data-i18n="nav.contracts">${i18n.t('nav.contracts')}</a>
<a href="#/workflow" class="nav-link text-[var(--color-text-secondary)] hover:text-[var(--color-text)] transition-colors" data-route="/workflow" data-i18n="nav.workflow">${i18n.t('nav.workflow')}</a>
<a href="#/spec-driven-development" class="nav-link text-[var(--color-text-secondary)] hover:text-[var(--color-text)] transition-colors" data-route="/spec-driven-development" data-i18n="nav.workflow">${i18n.t('nav.workflow')}</a>
<div class="relative" id="more-menu-container">
<button id="more-menu-toggle" class="nav-link text-[var(--color-text-secondary)] hover:text-[var(--color-text)] transition-colors flex items-center gap-1" data-i18n="nav.more">
${i18n.t('nav.more')}
Expand Down Expand Up @@ -155,7 +155,7 @@ export function renderHeader() {
<div class="flex flex-col gap-2">
<a href="#/" class="nav-link mobile-nav-link px-3 py-2 rounded-md text-[var(--color-text-secondary)] hover:text-[var(--color-text)] hover:bg-[var(--color-bg-secondary)] transition-colors" data-route="/" data-i18n="nav.catalog">${i18n.t('nav.catalog')}</a>
<a href="#/contracts" class="nav-link mobile-nav-link px-3 py-2 rounded-md text-[var(--color-text-secondary)] hover:text-[var(--color-text)] hover:bg-[var(--color-bg-secondary)] transition-colors" data-route="/contracts" data-i18n="nav.contracts">${i18n.t('nav.contracts')}</a>
<a href="#/workflow" class="nav-link mobile-nav-link px-3 py-2 rounded-md text-[var(--color-text-secondary)] hover:text-[var(--color-text)] hover:bg-[var(--color-bg-secondary)] transition-colors" data-route="/workflow" data-i18n="nav.workflow">${i18n.t('nav.workflow')}</a>
<a href="#/spec-driven-development" class="nav-link mobile-nav-link px-3 py-2 rounded-md text-[var(--color-text-secondary)] hover:text-[var(--color-text)] hover:bg-[var(--color-bg-secondary)] transition-colors" data-route="/spec-driven-development" data-i18n="nav.workflow">${i18n.t('nav.workflow')}</a>
<a href="#/about" class="nav-link mobile-nav-link px-3 py-2 rounded-md text-[var(--color-text-secondary)] hover:text-[var(--color-text)] hover:bg-[var(--color-bg-secondary)] transition-colors" data-route="/about" data-i18n="nav.about">${i18n.t('nav.about')}</a>
<a href="#/agentskill" class="nav-link mobile-nav-link px-3 py-2 rounded-md text-[var(--color-text-secondary)] hover:text-[var(--color-text)] hover:bg-[var(--color-bg-secondary)] transition-colors" data-route="/agentskill" data-i18n="nav.agentskill">${i18n.t('nav.agentskill')}</a>
<a href="#/contributing" class="nav-link mobile-nav-link px-3 py-2 rounded-md text-[var(--color-text-secondary)] hover:text-[var(--color-text)] hover:bg-[var(--color-bg-secondary)] transition-colors" data-route="/contributing" data-i18n="nav.contributing">${i18n.t('nav.contributing')}</a>
Expand Down
12 changes: 9 additions & 3 deletions website/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ import {
} from './components/card-grid.js'
import { fetchData, fetchContractsData } from './utils/data-loader.js'
import { buildSearchIndex, isIndexReady, isIndexBuilding } from './utils/search-index.js'
import { initRouter, addRoute, getCurrentRoute as getCurrentRouteSync } from './utils/router.js'
import {
initRouter,
addRoute,
navigate,
getCurrentRoute as getCurrentRouteSync,
} from './utils/router.js'
import { renderDocPage, loadDocContent } from './components/doc-page.js'
import {
createOnboardingModal,
Expand Down Expand Up @@ -141,7 +146,8 @@ function initApp() {
addRoute('/agentskill', renderAgentSkillPage)
addRoute('/rejected-proposals', renderRejectedProposalsPage)
addRoute('/all-anchors', renderAllAnchorsPage)
addRoute('/workflow', renderWorkflowPage)
addRoute('/spec-driven-development', renderWorkflowPage)
addRoute('/workflow', () => navigate('/spec-driven-development', { replace: true }))
addRoute('/brownfield', renderBrownfieldPage)
addRoute('/contracts', renderContractsPageHandler)
addRoute('/evaluations', renderEvaluationsPage)
Expand Down Expand Up @@ -494,7 +500,7 @@ function handleLanguageChange() {
loadDocContent('docs/rejected-proposals.adoc')
} else if (currentRoute === '/all-anchors') {
loadDocContent('docs/all-anchors.adoc')
} else if (currentRoute === '/workflow') {
} else if (currentRoute === '/spec-driven-development') {
loadDocContent('docs/spec-driven-workflow.adoc')
} else if (currentRoute === '/brownfield') {
loadDocContent('docs/brownfield-workflow.adoc')
Expand Down
2 changes: 1 addition & 1 deletion website/src/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"nav.contributing": "Mitwirken",
"nav.changelog": "Änderungsprotokoll",
"nav.agentskill": "AgentSkill",
"nav.workflow": "Workflow",
"nav.workflow": "Spec-Driven Dev",
"nav.more": "Mehr",
"nav.contracts": "Contracts",
"contracts.title": "Semantic Contracts",
Expand Down
2 changes: 1 addition & 1 deletion website/src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"nav.contributing": "Contributing",
"nav.changelog": "Changelog",
"nav.agentskill": "AgentSkill",
"nav.workflow": "Workflow",
"nav.workflow": "Spec-Driven Dev",
"nav.more": "More",
"nav.contracts": "Contracts",
"contracts.title": "Semantic Contracts",
Expand Down
16 changes: 9 additions & 7 deletions website/src/utils/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const ROUTE_TITLES = {
'/': 'Semantic Anchors — Shared Vocabulary for LLM Communication',
'/about': 'About — Semantic Anchors',
'/contracts': 'Semantic Contracts — Semantic Anchors',
'/workflow': 'Development Workflow — Semantic Anchors',
'/spec-driven-development': 'Spec-Driven Development with Semantic Anchors',
'/brownfield': 'Brownfield Workflow — Semantic Anchors',
'/evaluations': 'Evaluations — Semantic Anchors',
'/contributing': 'Contributing — Semantic Anchors',
Expand Down Expand Up @@ -55,9 +55,12 @@ export function addRoute(path, handler) {
/**
* Navigate to a specific route
* @param {string} path - Route path
* @param {object} [options]
* @param {boolean} [options.replace=false] - Replace current history entry instead of pushing
*/
export function navigate(path) {
history.pushState(null, '', buildPath(path))
export function navigate(path, { replace = false } = {}) {
const method = replace ? 'replaceState' : 'pushState'
history[method](null, '', buildPath(path))
handleRoute()
}

Expand Down Expand Up @@ -138,10 +141,9 @@ export function initRouter() {
function handleRoute() {
let path = getCurrentRoute()

// Normalize trailing slash: GitHub Pages 301-redirects /workflow to /workflow/
// when workflow/index.html is served as a directory index. Without this,
// routes.get('/workflow/') misses the '/workflow' key and falls through to
// the home handler.
// Normalize trailing slash: GitHub Pages 301-redirects routes like
// /spec-driven-development to /spec-driven-development/ when served as a
// directory index. Without this, the trailing slash misses the route key.
if (path.length > 1 && path.endsWith('/')) {
path = path.slice(0, -1)
}
Expand Down
8 changes: 4 additions & 4 deletions website/tests/e2e/website.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,13 +286,13 @@ test.describe('Routing - Documentation Pages', () => {
})

test('should render doc page when visited via trailing-slash URL', async ({ page }) => {
// GitHub Pages 301-redirects /workflow → /workflow/ when workflow/index.html
// is served as a directory index. The SPA must handle the trailing-slash
// GitHub Pages 301-redirects /spec-driven-development → /spec-driven-development/
// when served as a directory index. The SPA must handle the trailing-slash
// form or it falls through to the home handler.
await page.goto('/Semantic-Anchors/workflow/')
await page.goto('/Semantic-Anchors/spec-driven-development/')

await page.waitForSelector('#doc-content h1', { timeout: 10000 })
await expect(page.locator('#doc-content h1')).toContainText(/Workflow/i)
await expect(page.locator('#doc-content h1')).toContainText(/Spec-Driven Development/i)

// Card grid (home-only content) must not be rendered on top
await expect(page.locator('.anchor-card')).toHaveCount(0)
Expand Down
Loading