Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
753e927
feat(docs): add Fumadocs application
leoafarias Sep 2, 2026
5eb465c
chore(docs): add pnpm lockfile
github-actions[bot] Sep 2, 2026
c3e18de
ci(docs): validate Fumadocs static site
leoafarias Sep 2, 2026
5838d94
fix(docs): use the shared MDX component declaration
leoafarias Sep 2, 2026
bd717b7
fix(docs): mirror canonical content into the app
leoafarias Sep 2, 2026
b4d660e
chore(docs): normalize legacy page metadata
leoafarias Sep 2, 2026
4e110a2
docs: add architecture page metadata
github-actions[bot] Sep 2, 2026
1fba86a
chore(docs): remove migration helper workflow
leoafarias Sep 2, 2026
6879b84
fix(docs): scan the generated content mirror
leoafarias Sep 2, 2026
9a10c54
docs: update support links for Fumadocs routes
leoafarias Sep 2, 2026
90ca603
docs: update package documentation link
leoafarias Sep 2, 2026
622d153
docs: update repository links for the Fumadocs site
leoafarias Sep 2, 2026
e89f5b9
docs: update annotation guide link
leoafarias Sep 2, 2026
1e6673d
docs: update generator guide link
leoafarias Sep 2, 2026
d506df0
fix(docs): use absolute URLs in LLM page content
leoafarias Sep 2, 2026
10e2408
fix(docs): include the deployment path in llms links
leoafarias Sep 2, 2026
10ddb9e
test(docs): verify generated search and AI assets
leoafarias Sep 2, 2026
b4d8974
feat(docs): refresh canonical content during development
leoafarias Sep 2, 2026
4688020
chore(docs): use the live content sync in development
leoafarias Sep 2, 2026
d4711a7
docs: explain live canonical-content syncing
leoafarias Sep 2, 2026
406017c
test(docs): validate local content-sync scripts
leoafarias Sep 2, 2026
608d9da
docs: document the Fumadocs contribution workflow
leoafarias Sep 2, 2026
7188b2b
test(docs): reject retired documentation URLs
leoafarias Sep 2, 2026
53c522b
fix(ci): satisfy the pinned npm install policy
leoafarias Sep 2, 2026
6d6854e
test(docs): validate the Fumadocs navigation manifest
leoafarias Sep 2, 2026
091399a
docs: ignore generated documentation output
leoafarias Sep 2, 2026
5153a74
docs: add shared theme workspace snapshot
leoafarias Sep 2, 2026
4d34a1a
docs: add Concepta theme configuration helpers
leoafarias Sep 2, 2026
c7fe127
docs: add shared MDX component registry
leoafarias Sep 2, 2026
f49de84
docs: add Concepta documentation styles
leoafarias Sep 2, 2026
c6ca692
docs: synchronize existing Markdown into Fumadocs
leoafarias Sep 2, 2026
cf0d220
docs: redirect documentation root
leoafarias Sep 2, 2026
0143017
docs: add Fumadocs documentation layout
leoafarias Sep 2, 2026
38adb6d
docs: render synchronized ACK documentation
leoafarias Sep 2, 2026
1e1e408
docs: add dynamic Open Graph images
leoafarias Sep 2, 2026
089073f
docs: add per-page Markdown output
leoafarias Sep 2, 2026
7bb153f
docs: add documentation sitemap
leoafarias Sep 2, 2026
d6acb72
docs: add robots metadata
leoafarias Sep 2, 2026
cd63430
ci: validate Fumadocs documentation site
leoafarias Sep 2, 2026
21a43ce
ci: bootstrap documentation lockfile
leoafarias Sep 2, 2026
4c2ee1e
chore(docs): add pnpm lockfile
github-actions[bot] Sep 2, 2026
116c940
fix(docs): consolidate Fumadocs migration and restore validated contr…
leoafarias Sep 7, 2026
a201610
chore(docs): lock the repaired Base UI dependency graph
leoafarias Sep 7, 2026
85612b4
fix(docs): isolate MDX build-time schema imports from UI modules
leoafarias Sep 7, 2026
2bcdd51
docs: fix the Common recipes link for static page routing
leoafarias Sep 7, 2026
d86a208
test(docs): target native Fumadocs search result buttons
leoafarias Sep 7, 2026
548a866
test: cover inline workflow steps in dependency pin checks
leoafarias Sep 7, 2026
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
87 changes: 45 additions & 42 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -1,63 +1,66 @@
name: Documentation

on:
push:
branches: [main]
paths:
- 'docs/**'
- 'docs.json'
- 'llms.txt'
# No `branches:` filter. A stacked pull request targets its parent
# branch, not main, and would otherwise run no checks at all.
paths: ['docs/**', 'docs-site/**', '.github/workflows/docs.yml', 'llms.txt']
pull_request:
paths:
- 'docs/**'
- 'docs.json'
- 'llms.txt'

paths: ['docs/**', 'docs-site/**', '.github/workflows/docs.yml', 'docs.json', 'llms.txt']
permissions:
contents: read

concurrency:
group: docs-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
validate:
name: validate
runs-on: ubuntu-24.04
timeout-minutes: 15
timeout-minutes: 20
env:
DOCS_BASE_PATH: /ack
NEXT_PUBLIC_SITE_URL: https://concepta.dev/ack
NEXT_TELEMETRY_DISABLED: '1'
defaults:
run:
working-directory: docs-site
steps:
- name: Checkout repository
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
persist-credentials: false

- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: '22'

- name: Verify llms.txt sources
run: |
set -euo pipefail
test -s llms.txt || {
echo "llms.txt is missing or empty."
exit 1
}
test ! -e docs/llms.txt.mdx || {
echo "docs.page reserves /llms.txt; remove docs/llms.txt.mdx to avoid a duplicate index entry."
exit 1
}
grep -q 'https://docs.page/conceptadev/ack/llms.txt' docs/index.mdx || {
echo "The docs homepage must link to the generated docs.page llms.txt export."
exit 1
}

# Pin the CLI version. An unpinned `npm install -g @docs.page/cli` would
# execute whatever the registry serves at run time, which is the
# mutable-dependency problem that the other workflows removed.
- name: Validate documentation
node-version: '24.14.0'
- name: Install pinned pnpm
run: npm install --global pnpm@11.5.3
- name: Install documentation dependencies
run: pnpm install --frozen-lockfile
- name: Check helper contracts and dependency identity
run: pnpm test
- name: Type-check documentation
run: pnpm typecheck
- name: Verify the canonical content mirror
run: diff -qr ../docs content/docs
- name: Install the pinned browser test runtime
run: pnpm exec playwright install --with-deps chromium
- name: Build and verify a root deployment
env:
DOCS_PAGE_CLI_VERSION: '2.0.0'
run: npx --yes "@docs.page/cli@$DOCS_PAGE_CLI_VERSION" check
DOCS_BASE_PATH: ''
NEXT_PUBLIC_SITE_URL: https://docs.example.test
run: |
pnpm build
python3 scripts/verify-export.py
pnpm test:browser
- name: Build and verify the production subpath
run: |
pnpm build
python3 scripts/verify-export.py
pnpm test:browser
- name: Check runtime dependency advisories
run: pnpm audit --prod --audit-level=high
- name: Check migration invariants
run: |
test ! -e ../docs.json
test ! -e theme
test ! -e app/docs
test ! -e scripts/sync-content.mjs
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ CLAUDE.md
tools/node_modules/
tools/package-lock.json

# Fumadocs application outputs
docs-site/node_modules/
docs-site/.next/
docs-site/.source/
docs-site/content/
docs-site/out/

# Temporary test files
temp/
*.tmp
Expand Down
28 changes: 28 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,34 @@ dart run melos bootstrap
Ack uses a Melos workspace. Run commands from the repository root unless a
package README says otherwise.

## Documentation changes

The canonical documentation source is in `docs/`. Do not edit
`docs-site/content`; the Fumadocs application generates that mirror for local
and production builds.

Set up and run the documentation site with:

```bash
cd docs-site
npm install --global pnpm@11.5.3
pnpm install --frozen-lockfile
pnpm dev
```

The development server watches `docs/` and refreshes the content mirror. Open
`http://localhost:3000`.

Before submitting documentation changes, run:

```bash
cd docs-site
pnpm typecheck
DOCS_BASE_PATH=/ack \
NEXT_PUBLIC_SITE_URL=https://concepta.dev/ack \
pnpm build
```

## Before opening a PR

1. Keep the change scoped to one problem.
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
[![CI/CD](https://github.com/conceptadev/ack/actions/workflows/ci.yml/badge.svg)](https://github.com/conceptadev/ack/actions/workflows/ci.yml)
[![Documentation](https://img.shields.io/badge/docs-documentation-blue)](https://concepta.dev/ack)
[![pub package](https://img.shields.io/pub/v/ack.svg)](https://pub.dev/packages/ack)
[![llms.txt](https://img.shields.io/badge/llms.txt-available-8A2BE2)](https://concepta.dev/documentation/ack/reference/llms-txt)
[![llms.txt](https://img.shields.io/badge/llms.txt-available-8A2BE2)](https://concepta.dev/ack/llms.txt)

Ack is a schema validation library for Dart and Flutter. It validates data with a fluent API. Ack is short for "acknowledge".

For AI agents: start at [`/llms.txt`](https://concepta.dev/documentation/ack/reference/llms-txt).
For AI agents: start at [`/llms.txt`](https://concepta.dev/ack/llms.txt).

## Why use Ack?

Expand Down Expand Up @@ -234,12 +234,12 @@ csv.encode(['a', 'b', 'c']); // 'a,b,c'
```

Use `.transform<R>(...)` for one-way (parse-only) conversions. See the
[Codecs guide](https://concepta.dev/documentation/ack/advanced/codecs).
[Codecs guide](https://concepta.dev/ack/core-concepts/codecs).

## Documentation

- Human docs: [concepta.dev/ack](https://concepta.dev/ack)
- AI agent index: [AI & llms.txt](https://concepta.dev/documentation/ack/reference/llms-txt)
- AI agent index: [llms.txt](https://concepta.dev/ack/llms.txt)
- Canonical plaintext source: [raw.githubusercontent.com/conceptadev/ack/main/llms.txt](https://raw.githubusercontent.com/conceptadev/ack/main/llms.txt)

## Development
Expand Down
4 changes: 2 additions & 2 deletions SUPPORT.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
## Start with the documentation

- [Ack documentation](https://concepta.dev/ack)
- [Quickstart tutorial](https://concepta.dev/documentation/ack/getting-started/quickstart-tutorial)
- [API quick reference](https://concepta.dev/documentation/ack/reference/api-reference)
- [Quickstart tutorial](https://concepta.dev/ack/getting-started/quickstart-tutorial)
- [API quick reference](https://concepta.dev/ack/api-reference/)
- [Generated API documentation](https://pub.dev/documentation/ack/latest/ack/)

Search existing [GitHub issues](https://github.com/conceptadev/ack/issues) before
Expand Down
8 changes: 8 additions & 0 deletions docs-site/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.next/
.source/
node_modules/
out/
content/
playwright-report/
test-results/
*.tsbuildinfo
50 changes: 50 additions & 0 deletions docs-site/DEPLOYMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Documentation deployment

The app exports static files to `docs-site/out`. It has one route contract:
application-relative `/core-concepts/schemas` is published at
`https://concepta.dev/ack/core-concepts/schemas`.

## Build

```bash
cd docs-site
npm install --global pnpm@11.5.3
pnpm install --frozen-lockfile
DOCS_BASE_PATH=/ack NEXT_PUBLIC_SITE_URL=https://concepta.dev/ack pnpm build
DOCS_BASE_PATH=/ack NEXT_PUBLIC_SITE_URL=https://concepta.dev/ack python3 scripts/verify-export.py
DOCS_BASE_PATH=/ack pnpm test:browser
```

Install the Playwright Chromium runtime before running browser tests. Publish
`out` at the `/ack` mount, not at `/ack/docs`. The host must serve directory
indexes and raw files, including `/ack/api/search`, `/ack/llms.txt`, Markdown
files, and PNG images. Do not use a homepage fallback for missing files.

Next.js adds basePath to its links. Raw fetches use `addBasePath`; canonical,
sitemap, image metadata, and LLM URLs use `createSiteUrl`. Do not prefix a URL
twice. `site.url` includes the deployment path, while `site.docsPath` is `/`.

## Crawler ownership

The exported `/ack/robots.txt` is not a domain-wide crawler policy. Crawlers
read the origin's `/robots.txt`. Coordinate the Concepta root site's robots
configuration and add the sitemap `https://concepta.dev/ack/sitemap.xml` there.
Do not overwrite the root site's existing crawler rules. Review dates are not
used as sitemap modification dates.

## Cutover gate

This PR removes docs.page's `docs.json`. Do not merge until the new host can
serve the complete static export and the production route has been reviewed.
No deployment, DNS change, registry publication, or merge is automated here.

Keep the previous deployment available for rollback. Verify existing public
links, search, Markdown copy, source links, images, navigation, and 404s at the
real host before completing cutover. Older `/documentation/ack` URLs require
explicit redirects at that host; this static app does not own that prefix.

## Shared package follow-up

After a reviewed theme release is published, replace the `workspace:*`
dependency, remove `packages/docs-theme`, regenerate the lockfile, and rerun the
same root/subpath checks. Do not retain two packages with the same name.
62 changes: 62 additions & 0 deletions docs-site/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Ack documentation site

This is the Fumadocs application for Ack. The canonical content is `../docs`.
Builds copy that directory byte-for-byte into ignored `content/docs`; edit only
`../docs`. This PR migrates the existing published documentation. It does not
automatically import package READMEs, the root README, or unrelated folders.

## Development

Use Node.js 24.14 or newer, pnpm 11.5.3, and Python 3 for static preview/checks.

```bash
cd docs-site
npm install --global pnpm@11.5.3
pnpm install --frozen-lockfile
pnpm dev
```

Open `http://localhost:3000`. The development process watches `../docs`.
The source loader, navigation, and pages all use application-root routes, not
an additional `/docs` prefix. Existing page paths remain unchanged.

## Validate and preview

```bash
pnpm test
pnpm typecheck
DOCS_BASE_PATH=/ack NEXT_PUBLIC_SITE_URL=https://concepta.dev/ack pnpm build
DOCS_BASE_PATH=/ack NEXT_PUBLIC_SITE_URL=https://concepta.dev/ack python3 scripts/verify-export.py
DOCS_BASE_PATH=/ack pnpm preview
```

Open `http://127.0.0.1:4173/ack/` for the exported preview. This is a static site;
`next start` is not its serving command. Production builds require a public
`NEXT_PUBLIC_SITE_URL` whose pathname matches `DOCS_BASE_PATH`.

Browser checks:

```bash
pnpm exec playwright install chromium
DOCS_BASE_PATH=/ack pnpm test:browser
```

CI tests both root and `/ack` deployments, desktop and mobile rendering,
keyboard search, Markdown and image endpoints, theme switching, missing pages,
internal links/fragments, sitemap URLs, and the Base UI dependency identity.

## Theme ownership

`packages/docs-theme` is the only local snapshot of `@conceptadev/docs-theme`.
See its `SOURCE.md`. It shares the reviewed public API with the theme repository:
`Status` takes `status`; page metadata takes `imageUrl`; source links use
`createSourceUrl`. The explicit Base UI alias and workspace peer policy prevent
a second Radix implementation. A published package can replace the snapshot
after the same validation passes; registry publishing is a separate decision.

Optional front matter uses one shared `PAGE_STATUSES` enum. `lastReviewed` is
an editorial review date, not a content modification time. `draft` is only a
label; it does not hide pages from search or Markdown exports.

See `DEPLOYMENT.md` for the hosting cutover requirement. This PR does not deploy
or change DNS, but deleting `docs.json` requires a coordinated migration.
40 changes: 40 additions & 0 deletions docs-site/app/(docs)/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { createPageMetadata, createSourceUrl, Status } from '@conceptadev/docs-theme';
import { createRelativeLink } from 'fumadocs-ui/mdx';
import { DocsBody, DocsDescription, DocsPage, DocsTitle, MarkdownCopyButton, ViewOptionsPopover } from 'fumadocs-ui/layouts/docs/page';
import type { Metadata } from 'next';
import { notFound } from 'next/navigation';
import { getMDXComponents } from '@/components/mdx';
import { docsConfig } from '@/docs.config';
import { getPageImageUrl, getPageMarkdownUrl, source } from '@/lib/source';
import { withBasePath } from '@/lib/routes';

interface PageProps { params: Promise<{ slug?: string[] }> }
export const dynamicParams = false;

export default async function Page({ params }: PageProps) {
const { slug } = await params;
const page = source.getPage(slug);
if (!page) notFound();
const MDX = page.data.body;
const markdownUrl = withBasePath(getPageMarkdownUrl(page).url);
return (
<DocsPage toc={page.data.toc} full={page.data.full}>
<DocsTitle>{page.data.title}</DocsTitle>
{page.data.status ? <Status status={page.data.status} /> : null}
<DocsDescription className="mb-0">{page.data.description}</DocsDescription>
<div className="flex flex-wrap items-center gap-2 border-b pb-6">
<MarkdownCopyButton markdownUrl={markdownUrl} />
<ViewOptionsPopover markdownUrl={markdownUrl} githubUrl={createSourceUrl(docsConfig, page.path)} />
</div>
<DocsBody><MDX components={getMDXComponents({ a: createRelativeLink(source, page) })} /></DocsBody>
{page.data.lastReviewed ? <p className="mt-6 text-sm text-fd-muted-foreground">Last reviewed: <time dateTime={page.data.lastReviewed.toISOString().slice(0, 10)}>{page.data.lastReviewed.toISOString().slice(0, 10)}</time></p> : null}
</DocsPage>
);
}
export function generateStaticParams() { return source.generateParams(); }
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
const { slug } = await params;
const page = source.getPage(slug);
if (!page) notFound();
return createPageMetadata(docsConfig, { title: page.data.title, description: page.data.description, path: page.url, imageUrl: getPageImageUrl(page).url });
}
16 changes: 16 additions & 0 deletions docs-site/app/(docs)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { ReactNode } from 'react';
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
import { baseOptions } from '@/lib/layout.shared';
import { source } from '@/lib/source';

export default function DocumentationLayout({
children,
}: {
children: ReactNode;
}) {
return (
<DocsLayout tree={source.getPageTree()} {...baseOptions()}>
{children}
</DocsLayout>
);
}
6 changes: 6 additions & 0 deletions docs-site/app/api/search/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { createFromSource } from 'fumadocs-core/search/server';
import { source } from '@/lib/source';

export const dynamic = 'force-static';
export const revalidate = false;
export const { staticGET: GET } = createFromSource(source, { language: 'english' });
Loading
Loading