summaryrefslogtreecommitdiffstats
path: root/CLAUDE.md
diff options
context:
space:
mode:
Diffstat (limited to 'CLAUDE.md')
-rw-r--r--CLAUDE.md172
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.