diff options
Diffstat (limited to 'CLAUDE.md')
| -rw-r--r-- | CLAUDE.md | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..aaede3c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,172 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +**nebbet** is a static site generator (SSG) with an integrated admin UI for managing blog posts. It compiles markdown content to HTML, maintains metadata and search indices in SQLite, and provides a web interface for post creation/editing without redeploying. + +## Build & Run Commands + +### Build a production site +```bash +go run ./cmd/nebbet build +``` + +### Watch mode (continuous rebuild on file changes) +```bash +go run ./cmd/nebbet watch +``` + +### Development server (watch + live admin UI) +```bash +go run ./cmd/nebbet serve --port 8080 +``` +Visit `http://localhost:8080/admin/` to manage posts. Admin requires a user; create one first: + +### User management +```bash +# Add a user (prompts for password) +go run ./cmd/nebbet user add alice + +# List users +go run ./cmd/nebbet user list + +# Change password +go run ./cmd/nebbet user passwd alice + +# Delete user +go run ./cmd/nebbet user delete alice +``` + +## High-Level Architecture + +### The Build Pipeline + +1. **Source**: Markdown files in `content/` with YAML frontmatter +2. **Parse**: Extract frontmatter (title, date, tags, layout, draft flag) and body +3. **Render**: Convert markdown → HTML using Goldmark with GFM extensions +4. **Process**: Replace component directives with custom element tags +5. **Output**: Write HTML to `public/` using layout templates +6. **Index**: Update two SQLite databases: + - **meta.db**: Page metadata for listing/filtering by tag + - **search.db**: Full-text search index (FTS5) +7. **Watch**: Monitor content, templates, components for changes; rebuild with 150ms debounce + +### Directory Structure + +``` +content/ # Source markdown files (mirrored in public/ as .html) + index.md # Becomes /index.html → / + admin/ # Skipped from build (admin UI only) + posts/ # Blog posts (managed via admin UI) + +public/ # Generated static output + +templates/ # HTML layout templates + base.html # Default page layout + admin.html # Admin template (for future) + +components/ # JavaScript web components + site-greeting.js # Example component + +lib/ # JavaScript import map + libraries + +styles/ # CSS files (served directly, not copied) + +data/ # SQLite databases (created on first build) + meta.db # Page metadata + search.db # Full-text search index +``` + +### Component System + +Components are declared as HTML comments in markdown and converted to custom elements at build time: + +```markdown +<!-- component:site-greeting {"name": "visitor"} --> +``` + +becomes: + +```html +<site-greeting name="visitor"></site-greeting> +``` + +The `components/` directory contains JavaScript modules that define these custom elements. An importmap is auto-generated from `lib/` and injected into each page. + +### Frontmatter Spec + +Supported frontmatter fields (YAML-style): +``` +title: Page Title # Required +date: 2024-03-31 # Optional; ISO date format +tags: tag1, tag2 # Optional; comma-separated or JSON array +layout: base # Optional; template name (default: base) +draft: false # Optional; if true, page is skipped at build time +``` + +## Key Modules + +### `internal/builder/` +- **builder.go**: Core orchestrator (BuildAll, BuildFile, Watch, RemovePage) +- **frontmatter.go**: Parse YAML frontmatter from markdown +- **markdown.go**: Markdown → HTML conversion (Goldmark + GFM) +- **components.go**: Component directive processing (comments → custom elements) +- **importmap.go**: Auto-generate ES module importmap from lib/ + +### `internal/admin/` +- **server.go**: HTTP handlers for listing, creating, editing, and deleting posts +- Uses Basic Auth (htpasswd-compatible bcrypt passwords) +- Serves form UI for post management +- Triggers rebuilds via the builder after create/edit/delete + +### `internal/auth/` +Manages password file (compatible with nginx auth_basic): +- AddUser, DeleteUser, ChangePassword, ListUsers +- Verify passwords with bcrypt.CompareHashAndPassword +- File format: `username:$2a$...` (one per line) + +### `internal/db/` +Two SQLite databases: + +**meta.db** (PageMeta): +- Stores path, title, date, tags, html_path for each page +- Indexed by path and date +- Used for tag filtering and chronological listing + +**search.db** (SearchDB): +- FTS5 virtual table for full-text search +- Tokenizer: porter unicode61 +- Stores path, title, searchable plain-text content + +## Deployment + +### systemd service +See `nebbet.service` for running the watch daemon as a service. Update SITE_ROOT placeholder. + +### nginx configuration +See `nginx.conf` for: +- Public site serving from `public/` +- Admin UI with htpasswd auth (via `.passwords` file) +- Static assets (styles/, components/, lib/) served directly from source +- Clean URLs (/about → /about.html) + +Replace SITE_ROOT with absolute path to project directory. + +## Testing & Debugging + +The watch debounce is 150ms. When developing: +- Markdown changes only rebuild that file (fast) +- Template/component/lib changes trigger full rebuild +- Multiple simultaneous markdown changes trigger full rebuild (optimization) + +To test the admin UI locally: +```bash +go run ./cmd/nebbet serve +# Create a user first if .passwords doesn't exist +go run ./cmd/nebbet user add admin +# Visit http://localhost:8080/admin/ +``` + +Draft pages (draft: true) are silently skipped during builds but can be tested by removing the draft flag temporarily. |
