Skip to content

feat: markdown-first architecture (Phases 1-6)#13

Merged
RickCogley merged 22 commits intomainfrom
feat/markdown-first-architecture
Mar 1, 2026
Merged

feat: markdown-first architecture (Phases 1-6)#13
RickCogley merged 22 commits intomainfrom
feat/markdown-first-architecture

Conversation

@RickCogley
Copy link
Member

Summary

Complete implementation of the markdown-first content architecture for Hanawa CMS, covering Phases 1-6 of the plan.

  • Phase 1: Tiptap 3.x with @tiptap/markdown — all custom extensions serialize to/from markdown
  • Phase 2: Fragment migration — 54 YAML files → 108 bilingual markdown files, D1 fragment_index table
  • Phase 3: Fragment editing — list/edit/new routes with R2 load/save, AI translate, version auto-bump
  • Phase 4: Assembled document builder — manifest-based multi-section editor, RBAC guards, section translate, type filter
  • Phase 6: Centralized standards — MCP Worker on R2, content migration (29 docs), CMS routes, GitHub Action for R2 seeding, bootstrap scripts for consuming repos

Key changes

  • 16 commits, 86 files changed, ~27k lines added
  • New content/standards/ directory with 29 migrated coding standards
  • New packages/esolia-standards-mcp/ — Cloudflare Worker exposing standards via MCP protocol
  • New /standards CMS routes (list, create, edit with HanawaEditor)
  • New config/claude/ distributable rules, commands, and MCP config template
  • New GitHub Action seed-standards.yml for automatic R2 uploads
  • Cross-platform bootstrap scripts (setup-claude-env.sh / .ps1)

Post-merge steps

  1. Run D1 migrations (npm run db:migrate in hanawa-cms)
  2. Seed standards to R2: npx tsx scripts/seed-standards.ts --remote
  3. Deploy MCP Worker: cd packages/esolia-standards-mcp && npx wrangler deploy
  4. Run bootstrap scripts in consuming repos
  5. Retire rsync distribution from nexus

Test plan

  • Verify svelte-check passes (0 errors confirmed)
  • Verify ESLint passes (0 errors, only expected no-raw-db-prepare warnings)
  • Run D1 migration 0027 locally and verify standards_index table
  • Seed standards with --dry-run to verify parsing
  • Test /standards list, create, edit routes in dev
  • Deploy MCP Worker and test list_standards / get_standard / search_standards

Add markdown input/output rules to all custom Tiptap extensions
(callout, fragment-reference, mermaid-block, page-break, privacy-mask,
status-badge) so the editor can round-trip content as markdown.
Update HanawaEditor to accept contentType="markdown" prop.

InfoSec: CSP style-src updated for editor inline styles (OWASP A05)
Rewrite fragment system to store content as markdown files in R2
(fragments/{category}/{id}.{lang}.md) with a D1 fragment_index table
for metadata and search.

- Add migration 0025 for fragment_index table
- Add frontmatter parser for extracting/serializing YAML frontmatter
- Rewrite fragment CRUD routes for R2-backed markdown storage
- Add fragment API endpoint for individual fragment operations
- Update schemas for markdown-first fragment fields

InfoSec: Input validation via Zod schemas, parameterized D1 queries (OWASP A03)
Replace JSON fragment references with a copy-on-insert, manifest-based
architecture. Each document is now an R2 directory with manifest.yaml
+ per-section markdown files, enabling independent editing of copied
fragment content.

- Add migration 0026 for document_type and r2_manifest_key columns
- Add manifest.ts utilities (parse, serialize, add/remove/reorder sections)
- Add SectionEditor component with per-section Tiptap editors
- Rewrite document create to build manifest + copy fragment content to R2
- Add document edit actions: saveManifest, insertFragment, refreshSection,
  removeSection, reorderSections, addCustomSection
- Adapt generatePdf for manifest-based documents (read sections from R2)
- Add document type selector and type badge on list page
- Legacy JSON-based documents continue to work via fallback path
- Add mode prop to FragmentPicker for document assembly context

InfoSec: Parameterized D1 queries, Zod validation on all actions (OWASP A03)
Add AI translate buttons (→ JA / → EN) next to document title fields
so users can translate the title before creating the document.

InfoSec: Locale enum validated server-side (OWASP A03)
- Rename default action to named 'create' action (SvelteKit does not
  allow mixing default with named actions like aiTranslate)
- Use isRedirect() instead of instanceof Response for SvelteKit 2
- Use goto() for explicit redirect navigation after form submission
- Include actual error message in fail() response for debugging
- Handle failure results explicitly in use:enhance callback
onDestroy runs during SSR where document is undefined. Guard
the removeEventListener call with browser check to prevent
ReferenceError on server-rendered pages.
Add a button above section editors to collapse or expand all
sections at once, making it easier to reorder via drag and drop.
SectionEditor now accepts a bindable collapsed prop.
…ype filter

- Add requireRole() helper and RBAC guards on all 13 document form actions
- delete action restricted to admin only; approve requires admin role
- Add isReadOnly/isAdmin derived state with UI-level defense-in-depth
- Add per-section AI translate button in SectionEditor tab bar (EN↔JA)
- Add document type filter dropdown on list page (proposal/report/quote/sow/assessment)
- Preserve selected filter values across submissions

InfoSec: OWASP A01 — server-side role checks are primary enforcement;
UI guards (disabled buttons, conditional rendering) are defense-in-depth.
Closes Phase 4 of markdown-first architecture. See #12 for RBAC follow-up.
…x-sync phase

- Mark Phase 4 as complete
- Add detailed Typst #outline() research for bilingual per-language TOCs
  (scoped selectors eliminate the 3-PDF assembly workaround)
- Add Phase 6: Codex Sync (Git ↔ R2) — content synchronization worker
- Renumber Standing Documents → Phase 7, Website Content → Phase 8
- Update risk table (RBAC resolved, add git/R2 desync risk)
…tmatter

29 files migrated from docs/shared/ into content/standards/ organized by
category (guides/, reference/, prompts/, seo/). Each markdown file gets
YAML frontmatter with title, slug, category, tags, summary, author, and
dates for R2 storage and MCP server compatibility. Filenames normalized
to kebab-case. Migration script at scripts/migrate-standards.mjs.
Cloudflare Worker using McpAgent + Durable Object exposing three MCP
tools: list_standards, get_standard, search_standards. Reads from the
codex R2 bucket at standards/{slug}.md — consistent with fragments and
documents storage. Includes optional Bearer token auth, CORS, and health
endpoint. Seed script uploads markdown files to R2 via wrangler CLI.
config/claude/ contains rules (backpressure-verify, security-standards),
commands (backpressure-review, seo-setup, update-diagram), and an
mcp.json.example template for consuming repos. Bootstrap scripts
(setup-claude-env.sh for macOS/Linux, setup-claude-env.ps1 for Windows)
create symlinks from codex into target repos and copy the MCP template.
Phase 6 (Centralized Standards) Tasks 1-5 complete: content migration,
MCP Worker, R2 seeder, config/claude, bootstrap scripts. All references
updated from KV to R2 for consistency with the rest of the architecture.
Phase 5 marked complete. Phases renumbered 7-10.
- 0027_standards_index.sql: metadata index table (slug PK, category, tags, summary)
- schemas.ts: saveStandard, createStandard, renameStandard, deleteStandard
- frontmatter.ts: buildStandardMarkdown() for monolingual standards, updated key ordering
- /standards: list page with category/tag filters and search
- /standards/new: create page with auto-slug from title
- /standards/[slug]: edit page with metadata panel + HanawaEditor
- Save, rename, delete actions with R2 + D1 sync
- Standards nav link added between Fragments and Templates
Triggers on changes to content/standards/ or seed script.
Uploads markdown files to R2 codex bucket via wrangler CLI.
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Feb 28, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
esolia-hanawa 4e52f95 Commit Preview URL

Branch Preview URL
Mar 01 2026, 12:14 AM

…ration

54 YAML fragments migrated to 106 markdown files (EN + JA pairs).
Categories: capabilities, closing, company, comparisons, diagrams,
products, proposals, services, terms.
Rename Writing-Guide-AI-Proof-Editing-{en,ja}.md to
WRITING_GUIDE_AI_PROOF_EDITING_{EN,JA}.md for consistency with
other shared guides. Updated overused phrases table.
…ation

- packages/typst-pdf/: Cloudflare Container with pandoc + typst
  - Dockerfile, Hono server, bilingual template, pipeline
  - Accepts markdown + metadata, returns branded PDF
- hanawa-cms: TYPST_PDF_SERVICE binding in app.d.ts and wrangler.jsonc
- documents/[id]: Typst pipeline in PDF generation (falls through to
  HTML pipeline when unavailable)
Scripts for Phase 2 fragment migration (migrate, cleanup, seed SQL/TS)
and md-to-pdf tooling (generate.sh, Typst template, test input).
- SvelteKit editor architecture research document
- Standards MCP server concept files and archive
- Cloudflare auth and deploy guide for shared docs
…ployed

The TYPST_PDF_SERVICE binding references a Worker that doesn't exist yet
in Cloudflare, causing deploy failures. The binding is optional and the
code already falls through to the HTML PDF pipeline when unavailable.
@RickCogley RickCogley merged commit ab2f16b into main Mar 1, 2026
3 checks passed
@RickCogley RickCogley deleted the feat/markdown-first-architecture branch March 1, 2026 00:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant