Add project documentation and beads configuration

- Added CLAUDE.md with project overview and architecture details
- Added PRD.md with product requirements
- Added AGENTS.md for agent workflow documentation
- Initialized beads issue tracking system
- Added .gitattributes for Git configuration
This commit is contained in:
Oliver Jakoubek 2026-01-30 09:38:32 +01:00
commit 9f613b1901
12 changed files with 933 additions and 1 deletions

44
.beads/.gitignore vendored Normal file
View file

@ -0,0 +1,44 @@
# SQLite databases
*.db
*.db?*
*.db-journal
*.db-wal
*.db-shm
# Daemon runtime files
daemon.lock
daemon.log
daemon.pid
bd.sock
sync-state.json
last-touched
# Local version tracking (prevents upgrade notification spam after git ops)
.local_version
# Legacy database files
db.sqlite
bd.db
# Worktree redirect file (contains relative path to main repo's .beads/)
# Must not be committed as paths would be wrong in other clones
redirect
# Merge artifacts (temporary files from 3-way merge)
beads.base.jsonl
beads.base.meta.json
beads.left.jsonl
beads.left.meta.json
beads.right.jsonl
beads.right.meta.json
# Sync state (local-only, per-machine)
# These files are machine-specific and should not be shared across clones
.sync.lock
sync_base.jsonl
# NOTE: Do NOT add negation patterns (e.g., !issues.jsonl) here.
# They would override fork protection in .git/info/exclude, allowing
# contributors to accidentally commit upstream issue databases.
# The JSONL files (issues.jsonl, interactions.jsonl) and config files
# are tracked by git by default since no pattern above ignores them.

89
.beads/PRIME.md Normal file
View file

@ -0,0 +1,89 @@
# Beads Workflow Context
> **Context Recovery**: Run `bd prime` after compaction, clear, or new session
> Hooks auto-call this in Claude Code when .beads/ detected
# 🚨 TWO-PHASE WORKFLOW 🚨
**This project uses a split workflow:**
| Phase | Command | Actions |
|-------|---------|---------|
| **1. Implement** | `/start-issue <id>` | Set status → Plan → Implement |
| **2. Finalize** | `/finish-issue` | Commit → Close → Push |
## What this means for you:
### ✅ ALLOWED during implementation:
- Set ticket to `in_progress`
- Read, analyze, plan
- Write and modify code
- Run tests, build, verify
### ❌ FORBIDDEN during implementation:
- `git add` / `git commit` / `git push`
- `bd close`
- `bd sync` (syncs commits)
### When implementation is complete:
**DO NOT** run the old "Session Close Protocol". Instead say:
> "✅ Implementation complete. Files changed: [list files]. Run `/finish-issue` when ready to commit and close."
Then **STOP** and wait for the user.
---
## Core Rules
- Track strategic work in beads (multi-session, dependencies, discovered work)
- Use `bd create` for issues, TodoWrite for simple single-session execution
- When in doubt, prefer bd—persistence you don't need beats lost context
- Session management: check `bd ready` for available work
## Essential Commands
### Finding Work
- `bd ready` - Show issues ready to work (no blockers)
- `bd list --status=open` - All open issues
- `bd list --status=in_progress` - Your active work
- `bd show <id>` - Detailed issue view with dependencies
### Creating & Updating
- `bd create --title="..." --type=task|bug|feature --priority=2` - New issue
- Priority: 0-4 or P0-P4 (0=critical, 2=medium, 4=backlog). NOT "high"/"medium"/"low"
- `bd update <id> --status=in_progress` - Claim work
- `bd update <id> --assignee=username` - Assign to someone
- `bd update <id> --title/--description/--notes/--design` - Update fields inline
- `bd close <id>` - Mark complete (⚠️ only in /finish-issue!)
- **WARNING**: Do NOT use `bd edit` - it opens $EDITOR which blocks agents
### Dependencies & Blocking
- `bd dep add <issue> <depends-on>` - Add dependency
- `bd blocked` - Show all blocked issues
- `bd show <id>` - See what's blocking/blocked by this issue
### Project Health
- `bd stats` - Project statistics
- `bd doctor` - Check for issues
## Workflow Summary
```
/start-issue <id>
├── bd update <id> --status=in_progress
├── [Plan mode]
├── [Implement]
└── STOP → "Implementation complete"
... user reviews ...
/finish-issue
├── bd close <id>
├── git add -A
├── git commit -m "..."
├── bd sync
└── Done!
```

81
.beads/README.md Normal file
View file

@ -0,0 +1,81 @@
# Beads - AI-Native Issue Tracking
Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code.
## What is Beads?
Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git.
**Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads)
## Quick Start
### Essential Commands
```bash
# Create new issues
bd create "Add user authentication"
# View all issues
bd list
# View issue details
bd show <issue-id>
# Update issue status
bd update <issue-id> --status in_progress
bd update <issue-id> --status done
# Sync with git remote
bd sync
```
### Working with Issues
Issues in Beads are:
- **Git-native**: Stored in `.beads/issues.jsonl` and synced like code
- **AI-friendly**: CLI-first design works perfectly with AI coding agents
- **Branch-aware**: Issues can follow your branch workflow
- **Always in sync**: Auto-syncs with your commits
## Why Beads?
✨ **AI-Native Design**
- Built specifically for AI-assisted development workflows
- CLI-first interface works seamlessly with AI coding agents
- No context switching to web UIs
🚀 **Developer Focused**
- Issues live in your repo, right next to your code
- Works offline, syncs when you push
- Fast, lightweight, and stays out of your way
🔧 **Git Integration**
- Automatic sync with git commits
- Branch-aware issue tracking
- Intelligent JSONL merge resolution
## Get Started with Beads
Try Beads in your own projects:
```bash
# Install Beads
curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
# Initialize in your repo
bd init
# Create your first issue
bd create "Try out Beads"
```
## Learn More
- **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs)
- **Quick Start Guide**: Run `bd quickstart`
- **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples)
---
*Beads: Issue tracking that moves at the speed of thought* ⚡

62
.beads/config.yaml Normal file
View file

@ -0,0 +1,62 @@
# Beads Configuration File
# This file configures default behavior for all bd commands in this repository
# All settings can also be set via environment variables (BD_* prefix)
# or overridden with command-line flags
# Issue prefix for this repository (used by bd init)
# If not set, bd init will auto-detect from directory name
# Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc.
# issue-prefix: ""
# Use no-db mode: load from JSONL, no SQLite, write back after each command
# When true, bd will use .beads/issues.jsonl as the source of truth
# instead of SQLite database
# no-db: false
# Disable daemon for RPC communication (forces direct database access)
# no-daemon: false
# Disable auto-flush of database to JSONL after mutations
# no-auto-flush: false
# Disable auto-import from JSONL when it's newer than database
# no-auto-import: false
# Enable JSON output by default
# json: false
# Default actor for audit trails (overridden by BD_ACTOR or --actor)
# actor: ""
# Path to database (overridden by BEADS_DB or --db)
# db: ""
# Auto-start daemon if not running (can also use BEADS_AUTO_START_DAEMON)
# auto-start-daemon: true
# Debounce interval for auto-flush (can also use BEADS_FLUSH_DEBOUNCE)
# flush-debounce: "5s"
# Git branch for beads commits (bd sync will commit to this branch)
# IMPORTANT: Set this for team projects so all clones use the same sync branch.
# This setting persists across clones (unlike database config which is gitignored).
# Can also use BEADS_SYNC_BRANCH env var for local override.
# If not set, bd sync will require you to run 'bd config set sync.branch <branch>'.
# sync-branch: "beads-sync"
# Multi-repo configuration (experimental - bd-307)
# Allows hydrating from multiple repositories and routing writes to the correct JSONL
# repos:
# primary: "." # Primary repo (where this database lives)
# additional: # Additional repos to hydrate from (read-only)
# - ~/beads-planning # Personal planning repo
# - ~/work-planning # Work planning repo
# Integration settings (access with 'bd config get/set')
# These are stored in the database, not in this file:
# - jira.url
# - jira.project
# - linear.url
# - linear.api-key
# - github.org
# - github.repo

View file

@ -0,0 +1,6 @@
{
"worktree_root": "/home/oli/Dev/bookstack-api",
"last_export_commit": "a6adae98dd1697df76e68e562a4f84e7a38aa52d",
"last_export_time": "2026-01-30T09:36:58.353806809+01:00",
"jsonl_hash": "274bd67ea9399c10b88ec481bf082fe529a2d0cff39af1f6cbe89339a2f57f75"
}

View file

@ -8,7 +8,7 @@
{"id":"bookstack-api-8op","title":"Implement Client and Config structs","description":"Create the main Client struct and Config for client initialization with token-based authentication.\n\n## Requirements\nFrom PRD Section 5 (API \u0026 Interface-Spezifikation):\n\n```go\ntype Config struct {\n BaseURL string // e.g. \"https://docs.jakoubek.net\"\n TokenID string // API Token ID\n TokenSecret string // API Token Secret\n HTTPClient *http.Client // optional, for tests/mocking\n}\n\ntype Client struct {\n Books *BooksService\n Pages *PagesService\n Chapters *ChaptersService\n Shelves *ShelvesService\n Search *SearchService\n}\n\nfunc NewClient(cfg Config) *Client\n```\n\n## Authentication\nHeader format: `Authorization: Token \u003ctoken_id\u003e:\u003ctoken_secret\u003e`\n\n## Acceptance Criteria\n- [ ] Config struct with BaseURL, TokenID, TokenSecret, optional HTTPClient\n- [ ] Client struct with service fields (initially nil)\n- [ ] NewClient() constructor validates required fields\n- [ ] Default http.Client used when not provided\n- [ ] Unit tests for NewClient()","status":"open","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:39:06.037277135+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:39:06.037277135+01:00"}
{"id":"bookstack-api-9at","title":"Implement Pages Delete","description":"Implement delete operation for Pages.\n\n## Requirements\nFrom PRD Section 5:\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| Delete | DELETE /api/pages/{id} | Delete page |\n\n## API Method\n```go\nfunc (s *PagesService) Delete(ctx context.Context, id int) error\n```\n\n## Technical Details\n- Returns no content on success\n- 404 if page not found\n- May require appropriate permissions\n\n## Acceptance Criteria\n- [ ] Delete() removes page by ID\n- [ ] Returns nil on success\n- [ ] Proper error handling (404 -\u003e ErrNotFound, 403 -\u003e ErrForbidden)\n- [ ] Unit tests with mock server","status":"open","priority":2,"issue_type":"feature","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:39:53.980583894+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:39:53.980583894+01:00"}
{"id":"bookstack-api-9xo","title":"Implement BooksService (List, Get)","description":"Implement the BooksService with List and Get operations.\n\n## Requirements\nFrom PRD Section 5:\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| List | GET /api/books | All books |\n| Get | GET /api/books/{id} | Single book |\n\n## API Methods\n```go\ntype BooksService struct {\n client *Client\n}\n\nfunc (s *BooksService) List(ctx context.Context, opts *ListOptions) ([]*Book, error)\nfunc (s *BooksService) Get(ctx context.Context, id int) (*Book, error)\n```\n\n## ListOptions\nSupport pagination parameters:\n- count (max 500)\n- offset\n- sort (+name, -created_at, etc.)\n- filter[field]\n\n## Acceptance Criteria\n- [ ] BooksService struct created\n- [ ] List() returns paginated books\n- [ ] Get() returns single book by ID\n- [ ] Proper error handling (404 -\u003e ErrNotFound)\n- [ ] Unit tests with mock server","status":"open","priority":0,"issue_type":"feature","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:39:30.949469353+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:39:30.949469353+01:00"}
{"id":"bookstack-api-adp","title":"Set up Go module and project structure","description":"Initialize the Go module and create the basic project structure as defined in the PRD.\n\n## Requirements\n- Initialize go.mod with module name\n- Create placeholder files for the flat package structure:\n - bookstack.go (Client, Config, NewClient)\n - types.go (data structures)\n - errors.go (error types)\n - http.go (HTTP helpers)\n- Set up .gitignore for Go projects\n\n## Technical Details\n- Go 1.21+ required\n- Zero external dependencies (standard library only)\n- Module should be publishable as standalone Go module\n\n## Acceptance Criteria\n- [ ] go.mod exists with proper module name\n- [ ] Basic file structure created\n- [ ] `go build ./...` succeeds\n- [ ] .gitignore includes Go-specific patterns","status":"in_progress","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:39:05.818311718+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-30T09:33:48.689831698+01:00"}
{"id":"bookstack-api-adp","title":"Set up Go module and project structure","description":"Initialize the Go module and create the basic project structure as defined in the PRD.\n\n## Requirements\n- Initialize go.mod with module name\n- Create placeholder files for the flat package structure:\n - bookstack.go (Client, Config, NewClient)\n - types.go (data structures)\n - errors.go (error types)\n - http.go (HTTP helpers)\n- Set up .gitignore for Go projects\n\n## Technical Details\n- Go 1.21+ required\n- Zero external dependencies (standard library only)\n- Module should be publishable as standalone Go module\n\n## Acceptance Criteria\n- [ ] go.mod exists with proper module name\n- [ ] Basic file structure created\n- [ ] `go build ./...` succeeds\n- [ ] .gitignore includes Go-specific patterns","status":"closed","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:39:05.818311718+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-30T09:38:24.407997076+01:00","closed_at":"2026-01-30T09:38:24.407997076+01:00","close_reason":"Closed"}
{"id":"bookstack-api-bu8","title":"Add GoDoc documentation for all public APIs","description":"Ensure all exported types and functions have proper GoDoc comments.\n\n## Requirements\nFrom PRD Section 8 (Definition of Done):\n- Alle public APIs dokumentiert (GoDoc)\n\n## Documentation Standards\n- Package-level doc comment in bookstack.go\n- All exported types documented\n- All exported functions documented\n- All exported constants/variables documented\n- Include usage examples in doc comments where helpful\n\n## Example\n```go\n// Client is the Bookstack API client. Use NewClient to create a new instance.\n// Client is safe for concurrent use.\ntype Client struct {\n // Books provides access to the Books API.\n Books *BooksService\n ...\n}\n\n// NewClient creates a new Bookstack API client with the provided configuration.\n// BaseURL, TokenID, and TokenSecret are required.\n//\n// Example:\n//\n// client := bookstack.NewClient(bookstack.Config{\n// BaseURL: \"https://docs.example.com\",\n// TokenID: \"token-id\",\n// TokenSecret: \"token-secret\",\n// })\nfunc NewClient(cfg Config) *Client\n```\n\n## Acceptance Criteria\n- [ ] Package documentation present\n- [ ] All exported types documented\n- [ ] All exported functions documented\n- [ ] Documentation renders correctly in pkg.go.dev style\n- [ ] No golint documentation warnings","status":"open","priority":1,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:40:24.752365504+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:40:24.752365504+01:00"}
{"id":"bookstack-api-cpg","title":"Implement PagesService (List, Get)","description":"Implement the PagesService with List and Get operations.\n\n## Requirements\nFrom PRD Section 5:\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| List | GET /api/pages | All pages |\n| Get | GET /api/pages/{id} | Single page |\n\n## API Methods\n```go\ntype PagesService struct {\n client *Client\n}\n\nfunc (s *PagesService) List(ctx context.Context, opts *ListOptions) ([]*Page, error)\nfunc (s *PagesService) Get(ctx context.Context, id int) (*Page, error)\n```\n\n## Page Content\nThe Get response includes:\n- HTML content\n- RawHTML content \n- Markdown content (if available)\n\n## Acceptance Criteria\n- [ ] PagesService struct created\n- [ ] List() returns paginated pages\n- [ ] Get() returns single page by ID with content\n- [ ] Proper error handling (404 -\u003e ErrNotFound)\n- [ ] Unit tests with mock server","status":"open","priority":0,"issue_type":"feature","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:39:31.188568742+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:39:31.188568742+01:00"}
{"id":"bookstack-api-d2c","title":"Implement Pages Create and Update","description":"Implement write operations for Pages: Create and Update.\n\n## Requirements\nFrom PRD Section 5:\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| Create | POST /api/pages | Create page |\n| Update | PUT /api/pages/{id} | Update page |\n\n## API Methods\n```go\ntype PageCreateRequest struct {\n BookID int `json:\"book_id\"`\n ChapterID int `json:\"chapter_id,omitempty\"`\n Name string `json:\"name\"`\n HTML string `json:\"html,omitempty\"`\n Markdown string `json:\"markdown,omitempty\"`\n}\n\ntype PageUpdateRequest struct {\n Name string `json:\"name,omitempty\"`\n HTML string `json:\"html,omitempty\"`\n Markdown string `json:\"markdown,omitempty\"`\n}\n\nfunc (s *PagesService) Create(ctx context.Context, req *PageCreateRequest) (*Page, error)\nfunc (s *PagesService) Update(ctx context.Context, id int, req *PageUpdateRequest) (*Page, error)\n```\n\n## Workflow (from PRD)\n1. Get page\n2. Edit content locally\n3. Update page\n\n## Acceptance Criteria\n- [ ] PageCreateRequest and PageUpdateRequest structs\n- [ ] Create() creates new page in book or chapter\n- [ ] Update() modifies existing page\n- [ ] Returns updated Page object\n- [ ] Proper error handling (400 -\u003e ErrBadRequest)\n- [ ] Unit tests with mock server","status":"open","priority":1,"issue_type":"feature","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:39:53.734987403+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:39:53.734987403+01:00"}

4
.beads/metadata.json Normal file
View file

@ -0,0 +1,4 @@
{
"database": "beads.db",
"jsonl_export": "issues.jsonl"
}

3
.gitattributes vendored Normal file
View file

@ -0,0 +1,3 @@
# Use bd merge for beads JSONL files
.beads/issues.jsonl merge=beads

40
AGENTS.md Normal file
View file

@ -0,0 +1,40 @@
# Agent Instructions
This project uses **bd** (beads) for issue tracking. Run `bd onboard` to get started.
## Quick Reference
```bash
bd ready # Find available work
bd show <id> # View issue details
bd update <id> --status in_progress # Claim work
bd close <id> # Complete work
bd sync # Sync with git
```
## Landing the Plane (Session Completion)
**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
**MANDATORY WORKFLOW:**
1. **File issues for remaining work** - Create issues for anything that needs follow-up
2. **Run quality gates** (if code changed) - Tests, linters, builds
3. **Update issue status** - Close finished work, update in-progress items
4. **PUSH TO REMOTE** - This is MANDATORY:
```bash
git pull --rebase
bd sync
git push
git status # MUST show "up to date with origin"
```
5. **Clean up** - Clear stashes, prune remote branches
6. **Verify** - All changes committed AND pushed
7. **Hand off** - Provide context for next session
**CRITICAL RULES:**
- Work is NOT complete until `git push` succeeds
- NEVER stop before pushing - that leaves work stranded locally
- NEVER say "ready to push when you are" - YOU must push
- If push fails, resolve and retry until it succeeds

102
CLAUDE.md Normal file
View file

@ -0,0 +1,102 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
A Go library for the Bookstack REST API. Primary consumers are AI agents via CLI (with `--json` flag) and Go developers needing programmatic Bookstack access.
## Build & Test Commands
```bash
# Build
go build ./...
# Run all tests
go test ./...
# Run single test
go test -run TestName ./...
# Run tests with coverage
go test -cover ./...
# Lint (if golangci-lint is installed)
golangci-lint run
# Format code
gofmt -w .
```
## Architecture
### Flat Package Structure
All code lives in the root package `bookstack`. No subpackages.
```
bookstack.go # Client, Config, NewClient()
books.go # BooksService
pages.go # PagesService
chapters.go # ChaptersService
shelves.go # ShelvesService
search.go # SearchService
types.go # All data structures (Book, Page, Chapter, Shelf, SearchResult)
errors.go # Error types (ErrNotFound, ErrUnauthorized, APIError, etc.)
http.go # HTTP helpers, request building
iterator.go # Pagination iterator using Go 1.23+ iter.Seq
```
### Client Pattern
Services are attached to the main `Client` struct:
```go
client := bookstack.NewClient(bookstack.Config{
BaseURL: "https://docs.example.com",
TokenID: os.Getenv("BOOKSTACK_TOKEN_ID"),
TokenSecret: os.Getenv("BOOKSTACK_TOKEN_SECRET"),
})
// Access services via client
books, err := client.Books.List(ctx, nil)
page, err := client.Pages.Get(ctx, 123)
```
### Pagination via Iterators
Use Go 1.23+ iterator pattern for list operations:
```go
for book, err := range client.Books.ListAll(ctx) {
if err != nil {
return err
}
// process book
}
```
### Error Handling
Use sentinel errors with `errors.Is()`:
```go
if errors.Is(err, bookstack.ErrNotFound) {
// handle 404
}
```
`APIError` provides detailed information when needed.
## Key Design Decisions
- **Zero external dependencies** - Only Go standard library
- **Go 1.21+** required
- **No caching/rate-limiting** - Caller responsibility
- **Token auth** via `Authorization: Token <id>:<secret>` header
- **Bookstack hierarchy**: Shelf → Book → Chapter → Page
## Bookstack API Reference
- Rate limit: 180 req/min (server configurable)
- Pagination: `count` (max 500), `offset`, `sort`, `filter[field]`

498
PRD.md Normal file
View file

@ -0,0 +1,498 @@
# Product Requirements Document: bookstack-api
## 1. Projektübersicht
- **Ziel und Vision:**
Eine Go-Library für die Bookstack REST-API, die programmatischen Zugriff auf das Dokumentationssystem ermöglicht. Die Library wird in hqcli integriert und soll veröffentlichungsfähig sein.
- **Zielgruppe:**
- Primär: AI-Agenten (via hqcli mit `--json` Flag)
- Sekundär: Go-Entwickler, die Bookstack programmatisch nutzen wollen
- **Erfolgs-Metriken:**
- Vollständige Abdeckung der Kern-API (Books, Pages, Search)
- Nutzbar in hqcli für AI-gestützte Dokumentationssuche
- Veröffentlichung als eigenständiges Go-Modul
- **Projektscope:**
- **In Scope:** REST-API-Client für Bookstack, Iterator-basierte Pagination, Export-Funktionen
- **Out of Scope:** Webhooks, Caching, Admin-Funktionen (Users, Roles)
## 2. Funktionale Anforderungen
### Kern-Features
| Feature | Priorität | Version |
|---------|-----------|---------|
| Books: List, Get | P0 | v0.1 |
| Pages: List, Get | P0 | v0.1 |
| Search: All | P0 | v0.1 |
| Pages: Export (Markdown, PDF) | P1 | v0.2 |
| Chapters: List, Get | P1 | v0.2 |
| Shelves: List, Get | P1 | v0.2 |
| Pages: Create, Update | P1 | v0.3 |
| Pages: Delete | P2 | v0.4 |
| Attachments: CRUD | P2 | v0.4 |
| Comments: CRUD | P3 | v0.5 |
### User Stories
**US1: Dokumentation durchsuchen (AI-Agent)**
> Als AI-Agent möchte ich die Bookstack-Dokumentation durchsuchen können, um relevante Seiten für Benutzeranfragen zu finden.
```bash
hqcli docs search "deployment" --json
```
**US2: Seite abrufen**
> Als Benutzer möchte ich eine Dokumentationsseite anzeigen können, um deren Inhalt zu lesen.
```bash
hqcli docs page 123
hqcli docs page deployment-guide # via Slug
```
**US3: Bücher auflisten**
> Als Benutzer möchte ich alle verfügbaren Bücher sehen, um die Dokumentationsstruktur zu verstehen.
```bash
hqcli docs books --json
```
**US4: Seite exportieren**
> Als Benutzer möchte ich eine Seite als Markdown oder PDF exportieren können.
```bash
hqcli docs page 123 --export=md > page.md
hqcli docs page 123 --export=pdf > page.pdf
```
**US5: Seite im Browser öffnen**
> Als Benutzer möchte ich eine Seite schnell im Browser öffnen können.
```bash
hqcli docs open 123
```
### Detaillierte Workflows
**Workflow: Suche und Anzeige**
```
1. Benutzer/Agent führt Suche aus
2. API gibt Liste von Treffern zurück (ID, Typ, Name, Preview)
3. Benutzer/Agent wählt Treffer aus
4. Seite wird abgerufen und angezeigt (Markdown oder JSON)
```
**Workflow: Seite bearbeiten (v0.3)**
```
1. Seite abrufen (Get)
2. Inhalt lokal bearbeiten
3. Seite aktualisieren (Update)
```
### Feature-Prioritäten
- **Must-have (v1):** List, Get, Search für Books/Pages
- **Should-have (v1):** Export Markdown/PDF, Chapters, Shelves
- **Nice-to-have (v2):** Create, Update, Delete
- **Future:** Attachments, Comments, Image Gallery
## 3. Technische Anforderungen
- **Performance-Ziele:**
- API-Calls < 500ms (abhängig von Netzwerk)
- Iterator verarbeitet 10.000+ Einträge ohne Memory-Probleme
- **Concurrent User-Kapazität:**
Nicht zutreffend (Library, kein Server)
- **Real-time Features:**
Nicht zutreffend
- **Sicherheitsstandards:**
- Token-basierte Authentifizierung (Token ID + Secret)
- Keine Speicherung von Credentials (Aufrufer-Verantwortung)
- **Compliance-Vorgaben:**
Keine speziellen
- **Plattform-Support:**
- Go 1.21+
- Linux, macOS, Windows
## 4. Datenarchitektur
*Nicht zutreffend keine eigene Datenhaltung*
### Bookstack-Hierarchie (extern)
```
Shelf (Regal)
└── Book (Buch)
├── Chapter (Kapitel)
│ └── Page (Seite)
└── Page (Seite)
```
### Datenstrukturen
```go
// Book repräsentiert ein Bookstack-Buch
type Book struct {
ID int `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Description string `json:"description"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
CreatedBy int `json:"created_by"`
UpdatedBy int `json:"updated_by"`
}
// Page repräsentiert eine Bookstack-Seite
type Page struct {
ID int `json:"id"`
BookID int `json:"book_id"`
ChapterID int `json:"chapter_id"`
Name string `json:"name"`
Slug string `json:"slug"`
HTML string `json:"html"`
RawHTML string `json:"raw_html"`
Markdown string `json:"markdown"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// Chapter repräsentiert ein Bookstack-Kapitel
type Chapter struct {
ID int `json:"id"`
BookID int `json:"book_id"`
Name string `json:"name"`
Slug string `json:"slug"`
Description string `json:"description"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// Shelf repräsentiert ein Bookstack-Regal
type Shelf struct {
ID int `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Description string `json:"description"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// SearchResult repräsentiert ein Suchergebnis
type SearchResult struct {
ID int `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Type string `json:"type"` // page, chapter, book, bookshelf
URL string `json:"url"`
Preview string `json:"preview"`
}
```
## 5. API & Interface-Spezifikation
### Client-Initialisierung
```go
type Config struct {
BaseURL string // z.B. "https://docs.jakoubek.net"
TokenID string // API Token ID
TokenSecret string // API Token Secret
HTTPClient *http.Client // optional, für Tests/Mocking
}
func NewClient(cfg Config) *Client
```
**Beispiel:**
```go
client := bookstack.NewClient(bookstack.Config{
BaseURL: "https://docs.jakoubek.net",
TokenID: os.Getenv("BOOKSTACK_TOKEN_ID"),
TokenSecret: os.Getenv("BOOKSTACK_TOKEN_SECRET"),
})
```
### Service-Struktur
```go
type Client struct {
Books *BooksService
Pages *PagesService
Chapters *ChaptersService
Shelves *ShelvesService
Search *SearchService
}
```
### REST-Endpoints (Bookstack API)
| Service | Methode | Endpoint | Beschreibung |
|---------|---------|----------|--------------|
| Books | List | GET /api/books | Alle Bücher |
| Books | Get | GET /api/books/{id} | Einzelnes Buch |
| Pages | List | GET /api/pages | Alle Seiten |
| Pages | Get | GET /api/pages/{id} | Einzelne Seite |
| Pages | Create | POST /api/pages | Seite erstellen |
| Pages | Update | PUT /api/pages/{id} | Seite aktualisieren |
| Pages | Delete | DELETE /api/pages/{id} | Seite löschen |
| Pages | ExportMD | GET /api/pages/{id}/export/markdown | Markdown-Export |
| Pages | ExportPDF | GET /api/pages/{id}/export/pdf | PDF-Export |
| Chapters | List | GET /api/chapters | Alle Kapitel |
| Chapters | Get | GET /api/chapters/{id} | Einzelnes Kapitel |
| Shelves | List | GET /api/shelves | Alle Regale |
| Shelves | Get | GET /api/shelves/{id} | Einzelnes Regal |
| Search | All | GET /api/search?query=... | Volltextsuche |
### Authentifizierung
```
Authorization: Token <token_id>:<token_secret>
```
### Pagination (Iterator-Pattern)
```go
// ListAll gibt einen Iterator über alle Einträge zurück
// Nutzt Go 1.23+ iter.Seq oder eigene Implementation
func (s *BooksService) ListAll(ctx context.Context) iter.Seq2[*Book, error]
// Nutzung:
for book, err := range client.Books.ListAll(ctx) {
if err != nil {
return err
}
fmt.Println(book.Name)
}
```
**Begründung:** Iterator-Pattern ist Go-idiomatisch (ab 1.23), Memory-effizient und ermöglicht frühen Abbruch.
### Rate Limiting
- Bookstack: 180 Requests/Minute (default)
- **Keine Library-interne Behandlung** Aufrufer muss Rate-Limiting selbst handhaben
- Bei 429-Response: `ErrRateLimited` zurückgeben
## 6. Benutzeroberfläche
*Nicht zutreffend Library ohne UI*
### hqcli-Integration (separates Projekt)
```bash
# Bücher auflisten
hqcli docs books
hqcli docs books --json
# Seiten eines Buchs
hqcli docs pages --book=<id|slug>
# Seite anzeigen
hqcli docs page <id|slug>
hqcli docs page <id> --json
# Seite exportieren
hqcli docs page <id> --export=md
hqcli docs page <id> --export=pdf
# Suche
hqcli docs search "query"
hqcli docs search "query" --json
# Im Browser öffnen
hqcli docs open <id|slug>
```
**Output-Priorität:** `--json` für AI-Agenten ist Hauptanwendungsfall
## 7. Nicht-funktionale Anforderungen
- **Verfügbarkeit:**
Nicht zutreffend (Library)
- **Dependencies:**
Nur Go-Standardbibliothek (net/http, encoding/json, etc.)
- **Backward Compatibility:**
Semantic Versioning (v0.x während Entwicklung, v1.x nach Stabilisierung)
- **Logging-Strategie:**
Keine eigene Logging Fehler werden als `error` zurückgegeben
- **Konfiguration:**
Via `Config`-Struct bei Client-Erstellung
## 8. Qualitätssicherung
### Definition of Done
- [ ] Alle public APIs dokumentiert (GoDoc)
- [ ] Unit-Tests für alle Services (≥80% Coverage)
- [ ] Integration-Tests gegen Mock-Server
- [ ] Beispiel-Code in examples/
- [ ] README mit Quick-Start
### Test-Anforderungen
```go
// Unit-Tests mit Mock-HTTP-Client
func TestBooksService_List(t *testing.T) {
server := httptest.NewServer(...)
client := bookstack.NewClient(bookstack.Config{
BaseURL: server.URL,
TokenID: "test",
TokenSecret: "test",
})
books, err := client.Books.List(ctx, nil)
// assertions...
}
```
### Launch-Kriterien v1.0
- [ ] Books, Pages, Search vollständig implementiert
- [ ] Export (Markdown, PDF) funktioniert
- [ ] Dokumentation vollständig
- [ ] Keine bekannten Bugs
- [ ] hqcli-Integration getestet
## 9. Technische Implementierungshinweise
### Go-Projektstruktur
```
bookstack-api/
├── bookstack.go # Client, Config, NewClient()
├── books.go # BooksService
├── pages.go # PagesService
├── chapters.go # ChaptersService
├── shelves.go # ShelvesService
├── search.go # SearchService
├── types.go # Alle Datenstrukturen
├── errors.go # Error-Typen
├── http.go # HTTP-Helfer, Request-Building
├── iterator.go # Pagination-Iterator
├── bookstack_test.go # Tests
├── README.md
├── go.mod
├── go.sum
└── examples/
└── basic/
└── main.go
```
### Error-Handling-Strategie
```go
// Definierte Error-Typen für häufige Fälle
var (
ErrNotFound = errors.New("bookstack: resource not found")
ErrUnauthorized = errors.New("bookstack: unauthorized")
ErrForbidden = errors.New("bookstack: forbidden")
ErrRateLimited = errors.New("bookstack: rate limited")
ErrBadRequest = errors.New("bookstack: bad request")
)
// APIError für detaillierte Fehlerinformationen
type APIError struct {
StatusCode int
Code int `json:"code"`
Message string `json:"message"`
Body []byte // Original Response Body
}
func (e *APIError) Error() string {
return fmt.Sprintf("bookstack: API error %d: %s", e.StatusCode, e.Message)
}
func (e *APIError) Is(target error) bool {
switch target {
case ErrNotFound:
return e.StatusCode == 404
case ErrUnauthorized:
return e.StatusCode == 401
case ErrForbidden:
return e.StatusCode == 403
case ErrRateLimited:
return e.StatusCode == 429
case ErrBadRequest:
return e.StatusCode == 400
}
return false
}
```
**Begründung:** `errors.Is()` ermöglicht einfache Fehlerprüfung, `APIError` bietet Details wenn nötig.
### HTTP-Wrapper
```go
// Interner HTTP-Helfer
func (c *Client) do(ctx context.Context, method, path string, body, result any) error {
// 1. Request bauen
// 2. Auth-Header setzen
// 3. Request ausführen
// 4. Response prüfen
// 5. Bei Fehler: APIError zurückgeben
// 6. Bei Erfolg: JSON in result unmarshalen
}
```
### Entwicklungs-Prioritäten
1. **Phase 1 (v0.1):** Foundation
- Client-Setup, Auth, HTTP-Wrapper
- Books.List, Books.Get
- Pages.List, Pages.Get
- Error-Handling
2. **Phase 2 (v0.2):** Core Features
- Search.All
- Pages.ExportMarkdown, Pages.ExportPDF
- Iterator für Pagination
- Chapters, Shelves
3. **Phase 3 (v0.3):** Write Operations
- Pages.Create
- Pages.Update
4. **Phase 4 (v1.0):** Release
- Dokumentation
- Beispiele
- CI/CD
- Veröffentlichung
### Potenzielle Risiken
| Risiko | Wahrscheinlichkeit | Mitigation |
|--------|-------------------|------------|
| API-Änderungen in Bookstack | Niedrig | Semantic Versioning, Tests |
| Rate-Limiting-Probleme | Mittel | Dokumentation für Aufrufer |
| Große PDF-Exports | Mittel | Streaming statt Buffer |
---
## Anhang: Bookstack API-Referenz
- **Basis-URL:** https://docs.jakoubek.net/api
- **Dokumentation:** https://docs.jakoubek.net/api/docs
- **Beispiele:** https://codeberg.org/bookstack/api-scripts
- **Rate Limit:** 180 req/min (konfigurierbar serverseitig)
### Pagination-Parameter
| Parameter | Beschreibung | Default |
|-----------|--------------|---------|
| count | Anzahl Ergebnisse | 100 (max 500) |
| offset | Start-Position | 0 |
| sort | Sortierung (+name, -created_at) | - |
| filter[field] | Filter (eq, ne, gt, lt, like) | - |

3
go.mod Normal file
View file

@ -0,0 +1,3 @@
module code.beautifulmachines.dev/jakoubek/bookstack-api
go 1.25.6