bookstack-api/PRD.md
Oliver Jakoubek 9f613b1901 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
2026-01-30 09:38:32 +01:00

498 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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) | - |