Set up Go module and project structure
- Populated .gitignore with Go-specific patterns - Created placeholder Go files with basic package structure: - bookstack.go: Client and Config setup - types.go: Data structures (Book, Page, Chapter, Shelf, SearchResult) - errors.go: Error handling types with sentinel errors - http.go: HTTP helper placeholder with ListOptions - books.go, pages.go, chapters.go, shelves.go, search.go: Service placeholders - Verified build succeeds with go build ./... - No external dependencies added (stdlib only) All files compile successfully and follow flat package structure.
This commit is contained in:
parent
a6adae98dd
commit
62e299192d
12 changed files with 457 additions and 0 deletions
0
.beads/interactions.jsonl
Normal file
0
.beads/interactions.jsonl
Normal file
19
.beads/issues.jsonl
Normal file
19
.beads/issues.jsonl
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{"id":"bookstack-api-02m","title":"Create example code in examples/ directory","description":"Create example programs demonstrating library usage.\n\n## Requirements\nFrom PRD Section 8 (Definition of Done):\n- Beispiel-Code in examples/\n\nFrom PRD Section 9 (Go-Projektstruktur):\n```\nexamples/\n└── basic/\n └── main.go\n```\n\n## Examples to Create\n\n### examples/basic/main.go\nBasic usage: client setup, list books, get page\n\n### examples/search/main.go\nSearch workflow: search -\u003e select result -\u003e display page\n\n### examples/export/main.go\nExport page to markdown or PDF file\n\n### examples/iterator/main.go\nUsing ListAll() to iterate all pages\n\n## Technical Details\n- Each example should be runnable standalone\n- Use environment variables for credentials\n- Include error handling\n- Add comments explaining the code\n\n## Acceptance Criteria\n- [ ] examples/basic/main.go exists and runs\n- [ ] At least 2-3 different examples\n- [ ] All examples compile and work\n- [ ] Examples demonstrate key features","status":"open","priority":1,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:40:24.46706112+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:40:24.46706112+01:00"}
|
||||||
|
{"id":"bookstack-api-1us","title":"Write README with Quick-Start guide","description":"Create comprehensive README.md with usage documentation.\n\n## Requirements\nFrom PRD Section 8 (Definition of Done):\n- README mit Quick-Start\n\n## Content\n1. **Overview** - What the library does\n2. **Installation** - go get command\n3. **Quick Start** - Basic usage example\n4. **Authentication** - How to get and use API tokens\n5. **Usage Examples**\n - List books\n - Search documentation\n - Get page content\n - Export page\n6. **API Reference** - Link to GoDoc\n7. **License**\n\n## Example Code\n```go\nclient := bookstack.NewClient(bookstack.Config{\n BaseURL: \"https://docs.example.com\",\n TokenID: os.Getenv(\"BOOKSTACK_TOKEN_ID\"),\n TokenSecret: os.Getenv(\"BOOKSTACK_TOKEN_SECRET\"),\n})\n\n// Search documentation\nresults, err := client.Search.Search(ctx, \"deployment\", nil)\n\n// Get a page\npage, err := client.Pages.Get(ctx, 123)\n```\n\n## Acceptance Criteria\n- [ ] Clear installation instructions\n- [ ] Working quick-start example\n- [ ] All main features documented\n- [ ] Links to full documentation","status":"open","priority":1,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:40:24.187495378+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:40:24.187495378+01:00"}
|
||||||
|
{"id":"bookstack-api-2x5","title":"Implement SearchService","description":"Implement the SearchService for full-text search across Bookstack content.\n\n## Requirements\nFrom PRD Section 5:\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| All | GET /api/search?query=... | Full-text search |\n\n## API Methods\n```go\ntype SearchService struct {\n client *Client\n}\n\ntype SearchOptions struct {\n Query string\n // Pagination options\n Count int\n Offset int\n}\n\nfunc (s *SearchService) Search(ctx context.Context, query string, opts *SearchOptions) ([]*SearchResult, error)\n```\n\n## SearchResult\nReturns results across all types:\n- page\n- chapter\n- book\n- bookshelf\n\nEach result includes ID, Name, Slug, Type, URL, Preview.\n\n## User Story\nUS1: Als AI-Agent möchte ich die Bookstack-Dokumentation durchsuchen können, um relevante Seiten für Benutzeranfragen zu finden.\n\n## Acceptance Criteria\n- [ ] SearchService struct created\n- [ ] Search() accepts query string and options\n- [ ] Results include all content types\n- [ ] Proper error handling\n- [ ] Unit tests with mock server","status":"open","priority":0,"issue_type":"feature","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:39:31.430412917+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:39:31.430412917+01:00"}
|
||||||
|
{"id":"bookstack-api-42g","title":"Implement ShelvesService (List, Get)","description":"Implement the ShelvesService with List and Get operations.\n\n## Requirements\nFrom PRD Section 5:\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| List | GET /api/shelves | All shelves |\n| Get | GET /api/shelves/{id} | Single shelf |\n\n## API Methods\n```go\ntype ShelvesService struct {\n client *Client\n}\n\nfunc (s *ShelvesService) List(ctx context.Context, opts *ListOptions) ([]*Shelf, error)\nfunc (s *ShelvesService) Get(ctx context.Context, id int) (*Shelf, error)\nfunc (s *ShelvesService) ListAll(ctx context.Context) iter.Seq2[*Shelf, error]\n```\n\n## Shelf Fields\n- ID, Name, Slug, Description, CreatedAt, UpdatedAt\n\n## Bookstack Hierarchy\nShelf is the top-level container: Shelf -\u003e Book -\u003e Chapter -\u003e Page\n\n## Acceptance Criteria\n- [ ] ShelvesService struct created\n- [ ] List() returns paginated shelves\n- [ ] Get() returns single shelf by ID\n- [ ] ListAll() iterator implemented\n- [ ] Proper error handling\n- [ ] Unit tests with mock server","status":"open","priority":1,"issue_type":"feature","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:39:53.490673653+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:39:53.490673653+01:00"}
|
||||||
|
{"id":"bookstack-api-5gi","title":"Implement Attachments CRUD","description":"Implement CRUD operations for Attachments.\n\n## Requirements\nFrom PRD feature table: Attachments: CRUD (P2, v0.4)\n\n## API Endpoints (typical Bookstack pattern)\n- GET /api/attachments - List attachments\n- GET /api/attachments/{id} - Get attachment\n- POST /api/attachments - Create attachment\n- PUT /api/attachments/{id} - Update attachment\n- DELETE /api/attachments/{id} - Delete attachment\n\n## API Methods\n```go\ntype AttachmentsService struct {\n client *Client\n}\n\ntype Attachment struct {\n ID int `json:\"id\"`\n Name string `json:\"name\"`\n Extension string `json:\"extension\"`\n PageID int `json:\"uploaded_to\"`\n CreatedAt time.Time `json:\"created_at\"`\n UpdatedAt time.Time `json:\"updated_at\"`\n}\n\nfunc (s *AttachmentsService) List(ctx context.Context, opts *ListOptions) ([]*Attachment, error)\nfunc (s *AttachmentsService) Get(ctx context.Context, id int) (*Attachment, error)\nfunc (s *AttachmentsService) Create(ctx context.Context, req *AttachmentCreateRequest) (*Attachment, error)\nfunc (s *AttachmentsService) Update(ctx context.Context, id int, req *AttachmentUpdateRequest) (*Attachment, error)\nfunc (s *AttachmentsService) Delete(ctx context.Context, id int) error\n```\n\n## Technical Details\n- May need multipart/form-data for file uploads\n- Consider file size limits\n\n## Acceptance Criteria\n- [ ] Attachment type defined\n- [ ] AttachmentsService with all CRUD methods\n- [ ] File upload handling\n- [ ] Unit tests with mock server","status":"open","priority":2,"issue_type":"feature","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:39:54.242422591+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:39:54.242422591+01:00"}
|
||||||
|
{"id":"bookstack-api-7qx","title":"Implement Comments CRUD","description":"Implement CRUD operations for Comments.\n\n## Requirements\nFrom PRD feature table: Comments: CRUD (P3, v0.5)\n\n## API Endpoints (typical Bookstack pattern)\n- GET /api/comments - List comments\n- GET /api/comments/{id} - Get comment\n- POST /api/comments - Create comment\n- PUT /api/comments/{id} - Update comment\n- DELETE /api/comments/{id} - Delete comment\n\n## API Methods\n```go\ntype CommentsService struct {\n client *Client\n}\n\ntype Comment struct {\n ID int `json:\"id\"`\n PageID int `json:\"page_id\"`\n ParentID int `json:\"parent_id,omitempty\"`\n HTML string `json:\"html\"`\n CreatedAt time.Time `json:\"created_at\"`\n UpdatedAt time.Time `json:\"updated_at\"`\n CreatedBy int `json:\"created_by\"`\n}\n\nfunc (s *CommentsService) List(ctx context.Context, opts *ListOptions) ([]*Comment, error)\nfunc (s *CommentsService) Get(ctx context.Context, id int) (*Comment, error)\nfunc (s *CommentsService) Create(ctx context.Context, req *CommentCreateRequest) (*Comment, error)\nfunc (s *CommentsService) Update(ctx context.Context, id int, req *CommentUpdateRequest) (*Comment, error)\nfunc (s *CommentsService) Delete(ctx context.Context, id int) error\n```\n\n## Technical Details\n- Comments are attached to pages\n- Support nested comments (parent_id)\n\n## Acceptance Criteria\n- [ ] Comment type defined\n- [ ] CommentsService with all CRUD methods\n- [ ] Support for page filtering\n- [ ] Unit tests with mock server","status":"open","priority":3,"issue_type":"feature","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:40:23.920608941+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:40:23.920608941+01:00"}
|
||||||
|
{"id":"bookstack-api-8ea","title":"Implement HTTP helper and request building","description":"Create internal HTTP helper for making authenticated API requests.\n\n## Requirements\nImplement the internal `do` method on Client:\n\n```go\nfunc (c *Client) do(ctx context.Context, method, path string, body, result any) error {\n // 1. Build request\n // 2. Set Auth header: Authorization: Token \u003cid\u003e:\u003csecret\u003e\n // 3. Execute request\n // 4. Check response status\n // 5. On error: return APIError\n // 6. On success: unmarshal JSON into result\n}\n```\n\n## Technical Details\n- Support GET, POST, PUT, DELETE methods\n- JSON content type for request/response\n- Context support for cancellation\n- Proper URL joining (BaseURL + path)\n\n## Acceptance Criteria\n- [ ] do() method implemented\n- [ ] Auth header correctly formatted\n- [ ] JSON marshaling/unmarshaling works\n- [ ] Context cancellation supported\n- [ ] Unit tests with httptest.Server","status":"open","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:39:06.247263859+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:39:06.247263859+01:00"}
|
||||||
|
{"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-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"}
|
||||||
|
{"id":"bookstack-api-dd0","title":"Implement ChaptersService (List, Get)","description":"Implement the ChaptersService with List and Get operations.\n\n## Requirements\nFrom PRD Section 5:\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| List | GET /api/chapters | All chapters |\n| Get | GET /api/chapters/{id} | Single chapter |\n\n## API Methods\n```go\ntype ChaptersService struct {\n client *Client\n}\n\nfunc (s *ChaptersService) List(ctx context.Context, opts *ListOptions) ([]*Chapter, error)\nfunc (s *ChaptersService) Get(ctx context.Context, id int) (*Chapter, error)\nfunc (s *ChaptersService) ListAll(ctx context.Context) iter.Seq2[*Chapter, error]\n```\n\n## Chapter Fields\n- ID, BookID, Name, Slug, Description, CreatedAt, UpdatedAt\n\n## Bookstack Hierarchy\nBook -\u003e Chapter -\u003e Page (Chapter is optional level)\n\n## Acceptance Criteria\n- [ ] ChaptersService struct created\n- [ ] List() returns paginated chapters\n- [ ] Get() returns single chapter by ID\n- [ ] ListAll() iterator implemented\n- [ ] Proper error handling\n- [ ] Unit tests with mock server","status":"open","priority":1,"issue_type":"feature","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:39:53.235414205+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:39:53.235414205+01:00"}
|
||||||
|
{"id":"bookstack-api-jt9","title":"Implement Pages Export (Markdown, PDF)","description":"Implement page export functionality for Markdown and PDF formats.\n\n## Requirements\nFrom PRD Section 5:\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| ExportMD | GET /api/pages/{id}/export/markdown | Markdown export |\n| ExportPDF | GET /api/pages/{id}/export/pdf | PDF export |\n\n## API Methods\n```go\nfunc (s *PagesService) ExportMarkdown(ctx context.Context, id int) ([]byte, error)\nfunc (s *PagesService) ExportPDF(ctx context.Context, id int) ([]byte, error)\n```\n\n## Technical Details\n- Markdown export returns plain text\n- PDF export returns binary data\n- Consider streaming for large PDFs (risk mitigation from PRD)\n- Return raw bytes, caller handles file writing\n\n## User Story\nUS4: Als Benutzer möchte ich eine Seite als Markdown oder PDF exportieren können.\n\n## Acceptance Criteria\n- [ ] ExportMarkdown() returns markdown content as bytes\n- [ ] ExportPDF() returns PDF content as bytes\n- [ ] Proper error handling (404 -\u003e ErrNotFound)\n- [ ] Large file handling considered\n- [ ] Unit tests with mock server","status":"open","priority":1,"issue_type":"feature","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:39:31.924404898+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:39:31.924404898+01:00"}
|
||||||
|
{"id":"bookstack-api-m6n","title":"Implement pagination iterator (ListAll)","description":"Implement Go 1.23+ iterator pattern for memory-efficient pagination.\n\n## Requirements\nFrom PRD Section 5 (Pagination Iterator-Pattern):\n\n```go\n// ListAll returns an iterator over all entries\n// Uses Go 1.23+ iter.Seq or custom implementation\nfunc (s *BooksService) ListAll(ctx context.Context) iter.Seq2[*Book, error]\n\n// Usage:\nfor book, err := range client.Books.ListAll(ctx) {\n if err != nil {\n return err\n }\n fmt.Println(book.Name)\n}\n```\n\n## Technical Details\n- Go 1.23+ iter.Seq2 for yield-based iteration\n- Memory-efficient: only one page in memory at a time\n- Supports early break\n- Handle 10,000+ entries without memory issues\n\n## Pagination Parameters\n- count: 100 default, max 500\n- offset: auto-incremented per page\n- total: from API response to know when done\n\n## Services to Implement\n- BooksService.ListAll()\n- PagesService.ListAll()\n- ChaptersService.ListAll() (v0.2)\n- ShelvesService.ListAll() (v0.2)\n- SearchService.SearchAll() (v0.2)\n\n## Acceptance Criteria\n- [ ] iter.Seq2 based iterator implementation\n- [ ] Automatic pagination through all results\n- [ ] Early termination works correctly\n- [ ] Error propagation through iterator\n- [ ] Unit tests for pagination logic","status":"open","priority":1,"issue_type":"feature","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:39:31.682196545+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:39:31.682196545+01:00"}
|
||||||
|
{"id":"bookstack-api-q8z","title":"Implement data types (Book, Page, Chapter, Shelf, SearchResult)","description":"Create all data structure types as defined in the PRD.\n\n## Requirements\nFrom PRD Section 4 (Datenstrukturen):\n\n```go\ntype Book struct {\n ID int `json:\"id\"`\n Name string `json:\"name\"`\n Slug string `json:\"slug\"`\n Description string `json:\"description\"`\n CreatedAt time.Time `json:\"created_at\"`\n UpdatedAt time.Time `json:\"updated_at\"`\n CreatedBy int `json:\"created_by\"`\n UpdatedBy int `json:\"updated_by\"`\n}\n\ntype Page struct {\n ID int `json:\"id\"`\n BookID int `json:\"book_id\"`\n ChapterID int `json:\"chapter_id\"`\n Name string `json:\"name\"`\n Slug string `json:\"slug\"`\n HTML string `json:\"html\"`\n RawHTML string `json:\"raw_html\"`\n Markdown string `json:\"markdown\"`\n CreatedAt time.Time `json:\"created_at\"`\n UpdatedAt time.Time `json:\"updated_at\"`\n}\n\ntype Chapter struct {\n ID int `json:\"id\"`\n BookID int `json:\"book_id\"`\n Name string `json:\"name\"`\n Slug string `json:\"slug\"`\n Description string `json:\"description\"`\n CreatedAt time.Time `json:\"created_at\"`\n UpdatedAt time.Time `json:\"updated_at\"`\n}\n\ntype Shelf struct {\n ID int `json:\"id\"`\n Name string `json:\"name\"`\n Slug string `json:\"slug\"`\n Description string `json:\"description\"`\n CreatedAt time.Time `json:\"created_at\"`\n UpdatedAt time.Time `json:\"updated_at\"`\n}\n\ntype SearchResult struct {\n ID int `json:\"id\"`\n Name string `json:\"name\"`\n Slug string `json:\"slug\"`\n Type string `json:\"type\"\\ // page, chapter, book, bookshelf\n URL string `json:\"url\"`\n Preview string `json:\"preview\"`\n}\n```\n\n## Acceptance Criteria\n- [ ] All types defined in types.go\n- [ ] JSON tags match Bookstack API format\n- [ ] time.Time fields parse correctly from API\n- [ ] GoDoc comments on all exported types","status":"open","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:39:06.701609698+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:39:06.701609698+01:00"}
|
||||||
|
{"id":"bookstack-api-vl3","title":"Implement error types and APIError","description":"Create error handling infrastructure with sentinel errors and APIError type.\n\n## Requirements\nFrom PRD Section 9 (Error-Handling-Strategie):\n\n```go\nvar (\n ErrNotFound = errors.New(\"bookstack: resource not found\")\n ErrUnauthorized = errors.New(\"bookstack: unauthorized\")\n ErrForbidden = errors.New(\"bookstack: forbidden\")\n ErrRateLimited = errors.New(\"bookstack: rate limited\")\n ErrBadRequest = errors.New(\"bookstack: bad request\")\n)\n\ntype APIError struct {\n StatusCode int\n Code int `json:\"code\"`\n Message string `json:\"message\"`\n Body []byte\n}\n\nfunc (e *APIError) Error() string\nfunc (e *APIError) Is(target error) bool // Maps status codes to sentinel errors\n```\n\n## Status Code Mapping\n- 400 -\u003e ErrBadRequest\n- 401 -\u003e ErrUnauthorized\n- 403 -\u003e ErrForbidden\n- 404 -\u003e ErrNotFound\n- 429 -\u003e ErrRateLimited\n\n## Acceptance Criteria\n- [ ] All sentinel errors defined\n- [ ] APIError struct with Error() method\n- [ ] APIError.Is() correctly maps status codes\n- [ ] errors.Is() works with wrapped APIError\n- [ ] Unit tests for error matching","status":"open","priority":0,"issue_type":"task","owner":"mail@oliverjakoubek.de","created_at":"2026-01-28T09:39:06.467984697+01:00","created_by":"Oliver Jakoubek","updated_at":"2026-01-28T09:39:06.467984697+01:00"}
|
||||||
35
.gitignore
vendored
35
.gitignore
vendored
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
bin/
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# Test binary, built with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool
|
||||||
|
*.out
|
||||||
|
coverage.txt
|
||||||
|
coverage.html
|
||||||
|
|
||||||
|
# Go workspace file
|
||||||
|
go.work
|
||||||
|
go.work.sum
|
||||||
|
|
||||||
|
# Dependency directories (vendor is optional)
|
||||||
|
vendor/
|
||||||
|
|
||||||
|
# IDE and editor directories
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*.tmp
|
||||||
|
tmp/
|
||||||
43
books.go
Normal file
43
books.go
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
package bookstack
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// BooksService handles operations on books.
|
||||||
|
type BooksService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns a list of books with optional filtering.
|
||||||
|
// TODO: Implement API call to GET /api/books
|
||||||
|
func (s *BooksService) List(ctx context.Context, opts *ListOptions) ([]Book, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves a single book by ID.
|
||||||
|
// TODO: Implement API call to GET /api/books/{id}
|
||||||
|
func (s *BooksService) Get(ctx context.Context, id int) (*Book, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create creates a new book.
|
||||||
|
// TODO: Implement API call to POST /api/books
|
||||||
|
func (s *BooksService) Create(ctx context.Context, book *Book) (*Book, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update updates an existing book.
|
||||||
|
// TODO: Implement API call to PUT /api/books/{id}
|
||||||
|
func (s *BooksService) Update(ctx context.Context, id int, book *Book) (*Book, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes a book by ID.
|
||||||
|
// TODO: Implement API call to DELETE /api/books/{id}
|
||||||
|
func (s *BooksService) Delete(ctx context.Context, id int) error {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil
|
||||||
|
}
|
||||||
63
bookstack.go
Normal file
63
bookstack.go
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
package bookstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config holds configuration for the Bookstack API client.
|
||||||
|
type Config struct {
|
||||||
|
// BaseURL is the base URL of the Bookstack instance (e.g., "https://docs.example.com")
|
||||||
|
BaseURL string
|
||||||
|
|
||||||
|
// TokenID is the Bookstack API token ID
|
||||||
|
TokenID string
|
||||||
|
|
||||||
|
// TokenSecret is the Bookstack API token secret
|
||||||
|
TokenSecret string
|
||||||
|
|
||||||
|
// HTTPClient is the HTTP client to use for requests.
|
||||||
|
// If nil, a default client with 30s timeout will be used.
|
||||||
|
HTTPClient *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client is the main Bookstack API client.
|
||||||
|
type Client struct {
|
||||||
|
baseURL string
|
||||||
|
tokenID string
|
||||||
|
tokenSecret string
|
||||||
|
httpClient *http.Client
|
||||||
|
|
||||||
|
// Service instances
|
||||||
|
Books *BooksService
|
||||||
|
Pages *PagesService
|
||||||
|
Chapters *ChaptersService
|
||||||
|
Shelves *ShelvesService
|
||||||
|
Search *SearchService
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient creates a new Bookstack API client.
|
||||||
|
func NewClient(cfg Config) *Client {
|
||||||
|
httpClient := cfg.HTTPClient
|
||||||
|
if httpClient == nil {
|
||||||
|
httpClient = &http.Client{
|
||||||
|
Timeout: 30 * time.Second,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c := &Client{
|
||||||
|
baseURL: cfg.BaseURL,
|
||||||
|
tokenID: cfg.TokenID,
|
||||||
|
tokenSecret: cfg.TokenSecret,
|
||||||
|
httpClient: httpClient,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize services
|
||||||
|
c.Books = &BooksService{client: c}
|
||||||
|
c.Pages = &PagesService{client: c}
|
||||||
|
c.Chapters = &ChaptersService{client: c}
|
||||||
|
c.Shelves = &ShelvesService{client: c}
|
||||||
|
c.Search = &SearchService{client: c}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
43
chapters.go
Normal file
43
chapters.go
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
package bookstack
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// ChaptersService handles operations on chapters.
|
||||||
|
type ChaptersService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns a list of chapters with optional filtering.
|
||||||
|
// TODO: Implement API call to GET /api/chapters
|
||||||
|
func (s *ChaptersService) List(ctx context.Context, opts *ListOptions) ([]Chapter, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves a single chapter by ID.
|
||||||
|
// TODO: Implement API call to GET /api/chapters/{id}
|
||||||
|
func (s *ChaptersService) Get(ctx context.Context, id int) (*Chapter, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create creates a new chapter.
|
||||||
|
// TODO: Implement API call to POST /api/chapters
|
||||||
|
func (s *ChaptersService) Create(ctx context.Context, chapter *Chapter) (*Chapter, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update updates an existing chapter.
|
||||||
|
// TODO: Implement API call to PUT /api/chapters/{id}
|
||||||
|
func (s *ChaptersService) Update(ctx context.Context, id int, chapter *Chapter) (*Chapter, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes a chapter by ID.
|
||||||
|
// TODO: Implement API call to DELETE /api/chapters/{id}
|
||||||
|
func (s *ChaptersService) Delete(ctx context.Context, id int) error {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil
|
||||||
|
}
|
||||||
49
errors.go
Normal file
49
errors.go
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
package bookstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Sentinel errors for common API error conditions.
|
||||||
|
var (
|
||||||
|
ErrNotFound = errors.New("resource not found")
|
||||||
|
ErrUnauthorized = errors.New("unauthorized")
|
||||||
|
ErrForbidden = errors.New("forbidden")
|
||||||
|
ErrRateLimited = errors.New("rate limited")
|
||||||
|
ErrBadRequest = errors.New("bad request")
|
||||||
|
)
|
||||||
|
|
||||||
|
// APIError represents an error returned by the Bookstack API.
|
||||||
|
type APIError struct {
|
||||||
|
StatusCode int // HTTP status code
|
||||||
|
Code string // Error code from API response
|
||||||
|
Message string // Error message from API response
|
||||||
|
Body string // Raw response body
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e *APIError) Error() string {
|
||||||
|
if e.Code != "" {
|
||||||
|
return fmt.Sprintf("bookstack API error (status %d, code %s): %s", e.StatusCode, e.Code, e.Message)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("bookstack API error (status %d): %s", e.StatusCode, e.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is implements error matching for sentinel errors.
|
||||||
|
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
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
28
http.go
Normal file
28
http.go
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
package bookstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// buildRequest creates an HTTP request with proper authentication headers.
|
||||||
|
// TODO: Implement request building with Authorization header (Token <id>:<secret>)
|
||||||
|
func (c *Client) buildRequest(ctx context.Context, method, path string, body interface{}) (*http.Request, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// doRequest executes an HTTP request and handles the response.
|
||||||
|
// TODO: Implement response handling, error parsing, and JSON unmarshaling
|
||||||
|
func (c *Client) doRequest(ctx context.Context, req *http.Request, v interface{}) error {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListOptions contains common options for list operations.
|
||||||
|
type ListOptions struct {
|
||||||
|
Count int // Max items per page (default 100, max 500)
|
||||||
|
Offset int // Offset for pagination
|
||||||
|
Sort string // Sort field (e.g., "name", "-created_at")
|
||||||
|
Filter map[string]string // Filters (e.g., {"name": "value"})
|
||||||
|
}
|
||||||
43
pages.go
Normal file
43
pages.go
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
package bookstack
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// PagesService handles operations on pages.
|
||||||
|
type PagesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns a list of pages with optional filtering.
|
||||||
|
// TODO: Implement API call to GET /api/pages
|
||||||
|
func (s *PagesService) List(ctx context.Context, opts *ListOptions) ([]Page, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves a single page by ID.
|
||||||
|
// TODO: Implement API call to GET /api/pages/{id}
|
||||||
|
func (s *PagesService) Get(ctx context.Context, id int) (*Page, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create creates a new page.
|
||||||
|
// TODO: Implement API call to POST /api/pages
|
||||||
|
func (s *PagesService) Create(ctx context.Context, page *Page) (*Page, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update updates an existing page.
|
||||||
|
// TODO: Implement API call to PUT /api/pages/{id}
|
||||||
|
func (s *PagesService) Update(ctx context.Context, id int, page *Page) (*Page, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes a page by ID.
|
||||||
|
// TODO: Implement API call to DELETE /api/pages/{id}
|
||||||
|
func (s *PagesService) Delete(ctx context.Context, id int) error {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil
|
||||||
|
}
|
||||||
15
search.go
Normal file
15
search.go
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
package bookstack
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// SearchService handles search operations.
|
||||||
|
type SearchService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search performs a search query across all content types.
|
||||||
|
// TODO: Implement API call to GET /api/search
|
||||||
|
func (s *SearchService) Search(ctx context.Context, query string, opts *ListOptions) ([]SearchResult, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
43
shelves.go
Normal file
43
shelves.go
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
package bookstack
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// ShelvesService handles operations on shelves.
|
||||||
|
type ShelvesService struct {
|
||||||
|
client *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns a list of shelves with optional filtering.
|
||||||
|
// TODO: Implement API call to GET /api/shelves
|
||||||
|
func (s *ShelvesService) List(ctx context.Context, opts *ListOptions) ([]Shelf, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves a single shelf by ID.
|
||||||
|
// TODO: Implement API call to GET /api/shelves/{id}
|
||||||
|
func (s *ShelvesService) Get(ctx context.Context, id int) (*Shelf, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create creates a new shelf.
|
||||||
|
// TODO: Implement API call to POST /api/shelves
|
||||||
|
func (s *ShelvesService) Create(ctx context.Context, shelf *Shelf) (*Shelf, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update updates an existing shelf.
|
||||||
|
// TODO: Implement API call to PUT /api/shelves/{id}
|
||||||
|
func (s *ShelvesService) Update(ctx context.Context, id int, shelf *Shelf) (*Shelf, error) {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes a shelf by ID.
|
||||||
|
// TODO: Implement API call to DELETE /api/shelves/{id}
|
||||||
|
func (s *ShelvesService) Delete(ctx context.Context, id int) error {
|
||||||
|
// Placeholder for future implementation
|
||||||
|
return nil
|
||||||
|
}
|
||||||
76
types.go
Normal file
76
types.go
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
package bookstack
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// Book represents a Bookstack book.
|
||||||
|
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"`
|
||||||
|
OwnedBy int `json:"owned_by"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Page represents a Bookstack page.
|
||||||
|
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"`
|
||||||
|
Markdown string `json:"markdown"`
|
||||||
|
Priority int `json:"priority"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
CreatedBy int `json:"created_by"`
|
||||||
|
UpdatedBy int `json:"updated_by"`
|
||||||
|
Draft bool `json:"draft"`
|
||||||
|
Revision int `json:"revision_count"`
|
||||||
|
Template bool `json:"template"`
|
||||||
|
OwnedBy int `json:"owned_by"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chapter represents a Bookstack chapter.
|
||||||
|
type Chapter struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
BookID int `json:"book_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Slug string `json:"slug"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Priority int `json:"priority"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
CreatedBy int `json:"created_by"`
|
||||||
|
UpdatedBy int `json:"updated_by"`
|
||||||
|
OwnedBy int `json:"owned_by"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shelf represents a Bookstack shelf.
|
||||||
|
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"`
|
||||||
|
CreatedBy int `json:"created_by"`
|
||||||
|
UpdatedBy int `json:"updated_by"`
|
||||||
|
OwnedBy int `json:"owned_by"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchResult represents a search result from Bookstack.
|
||||||
|
type SearchResult struct {
|
||||||
|
Type string `json:"type"` // "page", "chapter", "book", or "shelf"
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Slug string `json:"slug"`
|
||||||
|
BookID int `json:"book_id"` // For pages and chapters
|
||||||
|
ChapterID int `json:"chapter_id"` // For pages
|
||||||
|
Preview string `json:"preview"`
|
||||||
|
Score float64 `json:"score"`
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue