summaryrefslogtreecommitdiffstats
path: root/CLAUDE.md
blob: c2aae8b0462fc07e88b3c25788b160b0efa5003e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Commands

```bash
# Build and run
go build ./cmd/iblog
./iblog serve [--port 8080] [--root .]

# Hot reload during development (uses air)
air  # serves on :8081 per .air.toml

# Run all tests
go test ./...

# Run a single test
go test ./internal/db/... -run TestPostSearch

# User management
./iblog user add <name>
./iblog user list
./iblog user passwd <name>
./iblog user delete <name>

# Build frontend JS (from assets/lib/ or assets/admin/lib/)
cd assets/lib && bun run build
cd assets/admin/lib && bun run build
```

## Architecture

iblog is a Go blog engine with an admin UI. It uses a hybrid model: posts are authored via a browser-based editor, stored in SQLite, and then rendered to static HTML files in `public/` for serving.

**Data flow:** Admin UI (EditorJS) → SQLite (`data/iblog.db`) → static HTML (`public/`) → served to readers

**Key packages:**

- `cmd/iblog/` — CLI entry point with `serve` and `user` subcommands
- `internal/` (package `auth`) — htpasswd-compatible bcrypt password file; nginx can use the same file via `auth_basic_user_file`
- `internal/db/` — SQLite wrapper; schema includes `posts`, `pages`, `redirects`, `settings`, and an FTS5 virtual table (`pages_fts`) for full-text search
- `internal/server/` — Gin HTTP handlers: `adminserver.go` (admin CRUD, auth middleware, setup flow), `frontpage.go`, `posthandler.go`, `fileserver.go`
- `internal/builder/` — Converts EditorJS block JSON to HTML (`editorjs.go`)
- `internal/media/` — Image upload, processing (govips/libvips), and serving

**Frontend assets** are embedded into the binary via `embed.go`:
- `assets/lib/` — Shared site JS (thumbhash, built with bun → `dist/`)
- `assets/admin/lib/` — Admin editor JS (EditorJS + plugins, built with bun → `dist/`)
- `assets/components/` — Custom web components served to the public site
- `assets/styles/` — CSS
- `templates/` — Go `html/template` files; `templates/admin/` for admin UI

**Directory layout at runtime** (controlled by `--root`):
```
data/iblog.db        SQLite database
data/.passwords      htpasswd file (bcrypt, 0600)
data/media/          uploaded media originals + processed images
public/              generated static HTML output
components/          optional user-supplied web components
styles/              optional user-supplied CSS overrides
```

**Setup flow:** On first run (no password file), all requests redirect to `/setup` where the first admin user is created. After that, `/admin/` routes require HTTP Basic Auth.

**Static generation:** Saving a post in the admin UI writes HTML to `public/<slug>/index.html` and updates the FTS5 index. The `public/` directory is served as a fallback for any route not matched by dynamic handlers.

## Notes

- `govips` wraps libvips; libvips must be installed on the host (`brew install vips` on macOS).
- The JS bundles in `assets/*/lib/dist/` are committed — rebuild them with bun when changing JS dependencies.
- Posts store content as raw EditorJS JSON (`blocks` column) and render to HTML on publish, not on read.