docs: write detailed Phase 2 spec for HTTP server + rendering
5 steps: Markdown rendering (goldmark), HTTP server (6 routes), HTML templates (dark theme, embedded), static site generator, CLI help text ingestion. All pure Go, no external deps except goldmark. Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
fc758a832b
commit
179c55ab98
1 changed files with 125 additions and 5 deletions
130
TODO.md
130
TODO.md
|
|
@ -32,12 +32,132 @@ Dispatched from core/go orchestration. Pick up tasks in order.
|
|||
- [x] **Multi-word bonus** -- All query words present in topic adds +2.0.
|
||||
- [x] **Tests for all new features** -- Levenshtein, min3, extractPhrases, fuzzy search, phrase search, tag boost, multi-word bonus, scoring constants, phrase highlighting, section phrase matching.
|
||||
|
||||
## Phase 2: core.help Integration
|
||||
## Phase 2: HTTP Server & Rendering
|
||||
|
||||
- [ ] Feed CLI docs into help catalog (parse `core` subcommand help text)
|
||||
- [ ] Serve catalog via HTTP for the `core.help` domain
|
||||
- [ ] Add Markdown rendering for topic bodies in HTTP responses
|
||||
- [ ] Generate static site from catalog for BunnyCDN deployment
|
||||
### 2.1 Markdown Rendering (`render.go`)
|
||||
|
||||
- [ ] **Add `github.com/yuin/goldmark` dependency** — CommonMark-compliant Markdown renderer. Run `go get github.com/yuin/goldmark`.
|
||||
- [ ] **Create `render.go`** — Markdown-to-HTML conversion:
|
||||
- `func RenderMarkdown(content string) (string, error)` — converts Markdown to HTML using goldmark. Configure with:
|
||||
- `html.WithUnsafe()` — allow raw HTML in source (needed for embedded code examples)
|
||||
- `extension.GFM` — GitHub Flavoured Markdown (tables, strikethrough, autolinks)
|
||||
- `extension.Typographer` — smart quotes and dashes
|
||||
- Returns HTML fragment (no `<html>`/`<body>` wrapper — the server templates handle that)
|
||||
- [ ] **Create `render_test.go`** — Tests:
|
||||
- (a) heading hierarchy (H1-H6) produces correct `<h1>`-`<h6>` tags
|
||||
- (b) fenced code blocks (```` ```go ````) produce `<pre><code class="language-go">`
|
||||
- (c) inline code backticks produce `<code>`
|
||||
- (d) lists (ordered + unordered)
|
||||
- (e) links and images
|
||||
- (f) tables (GFM extension)
|
||||
- (g) empty input returns empty string
|
||||
- (h) special characters are properly escaped
|
||||
|
||||
### 2.2 HTTP Server (`server.go`)
|
||||
|
||||
- [ ] **Create `server.go`** — HTTP server for the help catalog:
|
||||
- `type Server struct { catalog *Catalog; addr string; mux *http.ServeMux }` — holds catalog reference and HTTP mux
|
||||
- `func NewServer(catalog *Catalog, addr string) *Server` — constructor. Creates mux with all routes registered.
|
||||
- `func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)` — delegates to mux (implements `http.Handler`)
|
||||
- `func (s *Server) ListenAndServe() error` — starts listening
|
||||
|
||||
**Routes:**
|
||||
- `GET /` — Index page: rendered HTML listing all topics grouped by tags, sorted by Order then Title
|
||||
- `GET /topics/{id}` — Topic page: rendered Markdown content + table of contents from Sections + related topics sidebar
|
||||
- `GET /search?q={query}` — Search results page: rendered HTML with highlighted snippets, scores
|
||||
- `GET /api/topics` — JSON array of all topics (without rendered HTML — raw content field)
|
||||
- `GET /api/topics/{id}` — JSON single topic
|
||||
- `GET /api/search?q={query}` — JSON array of SearchResult
|
||||
|
||||
**Response format:**
|
||||
- HTML routes: render using Go `html/template` with embedded templates (see 2.3)
|
||||
- JSON routes: `application/json` with `json.NewEncoder`
|
||||
- All routes: set `Content-Type`, `X-Content-Type-Options: nosniff`
|
||||
- Search routes: return 400 if query is empty
|
||||
|
||||
- [ ] **Create `server_test.go`** — Tests using `httptest.NewServer`:
|
||||
- (a) `GET /` returns 200 with HTML containing topic titles
|
||||
- (b) `GET /topics/getting-started` returns 200 with rendered content
|
||||
- (c) `GET /topics/nonexistent` returns 404
|
||||
- (d) `GET /search?q=install` returns 200 with results
|
||||
- (e) `GET /search` (no query) returns 400
|
||||
- (f) `GET /api/topics` returns JSON array
|
||||
- (g) `GET /api/topics/getting-started` returns JSON object
|
||||
- (h) `GET /api/topics/nonexistent` returns 404
|
||||
- (i) `GET /api/search?q=config` returns JSON results
|
||||
- (j) Content-Type headers correct for HTML vs JSON routes
|
||||
|
||||
### 2.3 HTML Templates (`templates.go`)
|
||||
|
||||
- [ ] **Create `templates.go`** — Embedded HTML templates using `embed.FS`:
|
||||
- Use `html/template` with a `//go:embed templates/*.html` directive
|
||||
- Create `templates/` directory with:
|
||||
- `base.html` — shared layout: `<!DOCTYPE html>`, dark theme CSS (reuse go-session's colour palette: `--bg: #0d1117; --fg: #c9d1d9; --accent: #58a6ff`), nav bar with search input, footer
|
||||
- `index.html` — topic listing: cards grouped by first tag, topic count, search bar
|
||||
- `topic.html` — single topic: rendered Markdown body, table of contents (from Sections), related topics, prev/next navigation
|
||||
- `search.html` — search results: query echo, result count, ranked list with snippets, "no results" state with fuzzy suggestions
|
||||
- `404.html` — not found page with search suggestion
|
||||
- Template functions: `renderMarkdown` (calls RenderMarkdown), `truncate`, `pluralise`
|
||||
- All templates use the dark theme. Monospace font. Clean, minimal.
|
||||
|
||||
- [ ] **Create `templates_test.go`** — Tests:
|
||||
- (a) all templates parse without error
|
||||
- (b) index template renders topic titles
|
||||
- (c) topic template renders Markdown content
|
||||
- (d) search template renders results with snippets
|
||||
- (e) 404 template contains "not found"
|
||||
|
||||
### 2.4 Static Site Generator (`generate.go`)
|
||||
|
||||
- [ ] **Create `generate.go`** — Generate a static site from the catalog:
|
||||
- `func Generate(catalog *Catalog, outputDir string) error` — writes static HTML files:
|
||||
- `{outputDir}/index.html` — index page (rendered from index template)
|
||||
- `{outputDir}/topics/{id}.html` — one file per topic (rendered from topic template)
|
||||
- `{outputDir}/search.html` — search page with client-side JS search
|
||||
- `{outputDir}/search-index.json` — JSON search index for client-side search:
|
||||
```json
|
||||
[{"id":"getting-started","title":"Getting Started","tags":["intro"],"content":"...truncated..."}]
|
||||
```
|
||||
- `{outputDir}/404.html` — not found page
|
||||
- Client-side search JS: inline `<script>` in search.html that:
|
||||
- Loads search-index.json on page load
|
||||
- Filters topics by title/content matching (simple substring for static site)
|
||||
- Updates DOM with results (no server round-trip)
|
||||
- All CSS inlined (no external stylesheets for CDN simplicity)
|
||||
|
||||
- [ ] **Create `generate_test.go`** — Tests:
|
||||
- (a) generates expected file structure in temp dir
|
||||
- (b) index.html contains all topic titles
|
||||
- (c) topic files contain rendered Markdown
|
||||
- (d) search-index.json is valid JSON with all topics
|
||||
- (e) 404.html exists
|
||||
- (f) generates into empty dir successfully
|
||||
- (g) overwrites existing files without error
|
||||
|
||||
### 2.5 CLI Help Text Ingestion (`ingest.go`)
|
||||
|
||||
- [ ] **Create `ingest.go`** — Parse standard Go CLI help output into Topics:
|
||||
- `func ParseHelpText(name string, text string) *Topic` — parses help text format:
|
||||
- Title: derived from name (e.g., `"dev commit"` → `"Dev Commit"`)
|
||||
- ID: `GenerateID(name)` (e.g., `"dev-commit"`)
|
||||
- Content: the full help text, converted to Markdown:
|
||||
- Lines starting with `Usage:` → `## Usage` + code block
|
||||
- Lines starting with `Flags:` or `Options:` → `## Flags` + code block
|
||||
- Lines starting with `Examples:` → `## Examples` + code block
|
||||
- Descriptive paragraphs → plain Markdown text
|
||||
- Subcommand listings → bulleted list with links
|
||||
- Tags: `["cli", first-word-of-name]` (e.g., `["cli", "dev"]`)
|
||||
- Related: extracted from "See also:" lines if present
|
||||
- `func IngestCLIHelp(helpTexts map[string]string) *Catalog` — batch ingest: create catalog, parse each help text, add all topics. Key = command name (e.g., `"dev commit"`), Value = help text.
|
||||
|
||||
- [ ] **Create `ingest_test.go`** — Tests:
|
||||
- (a) standard Go flag-style help text (Usage + Flags + description)
|
||||
- (b) cobra-style help text (with subcommand listing)
|
||||
- (c) minimal help text (single line description)
|
||||
- (d) help text with examples section
|
||||
- (e) batch ingest creates catalog with all topics
|
||||
- (f) "See also" line populates Related field
|
||||
- (g) empty help text produces topic with empty content
|
||||
|
||||
## Phase 3: AI-Assisted Search
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue