Commit graph

36 commits

Author SHA1 Message Date
f8daa20ddd feat: use random request IDs instead of sequential counter v1.0.0
Replace the atomic counter-based request ID generation with random
int64 values using math/rand/v2. This improves unpredictability and
avoids potential ID collisions across client instances or restarts.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 10:21:31 +01:00
735b288504 fix: add HTML response body validation before JSON parsing
Adds a backup check that validates the response body starts with '{'
before attempting JSON unmarshal. This catches cases where:
- Server returns HTML with incorrect Content-Type header
- Reverse proxy/load balancer modifies headers but not body
- PHP error pages with HTTP 200 status

Includes a preview of the HTML content (up to 200 chars) for debugging.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 20:35:21 +01:00
770e05ef7c Update beads export state 2026-01-23 18:27:14 +01:00
192053952f Add WithAuthHeader for custom authentication header name
Support configuring a custom HTTP header name for authentication
(e.g., X-API-Auth instead of Authorization) for Kanboard servers
with specific proxy configurations that use alternative auth headers.

- Add headerName field to apiTokenAuth and basicAuth structs
- Add WithAuthHeader() fluent method to Client
- Auth methods pass custom header name when creating auth structs
- Add tests for custom header with API token, basic auth, and custom user

Closes kanboard-9wa

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 18:26:55 +01:00
10e2ecf47e Add optional API user support for token authentication
- Add user field to apiTokenAuth struct
- Add WithAPITokenUser(token, user) method for custom username
- Default to "jsonrpc" when no user specified (backward compatible)
- Add tests for custom user and empty user scenarios

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 17:55:31 +01:00
ef7bd74e4a Added debug output to jsonrpc.go 2026-01-23 11:42:11 +01:00
a34a40cb12 Add IntOrFalse type to handle polymorphic API responses
Kanboard API returns int (ID) on success and false (bool) on failure
for create operations. Add IntOrFalse type that handles both cases
and update CreateTask, CreateComment, CreateTag, CreateTaskFile, and
CreateTaskLink to use it.
2026-01-15 20:23:53 +01:00
59252a3f63 Fix StringBool to handle numeric JSON values
Some Kanboard versions return is_active and similar fields as
numeric 0/1 instead of string "0"/"1". Update UnmarshalJSON to
try string, then number, then bool parsing.
2026-01-15 20:11:58 +01:00
8aa611d3d7 Add MIT license 2026-01-15 19:25:27 +01:00
a2913c6b8d Add example programs
- examples/basic: Client setup, projects, tasks, and create operations
- examples/fluent: Fluent API with TaskParams, TaskUpdateParams, tags
- examples/search: Project-specific and global search functionality
2026-01-15 19:24:58 +01:00
ff06643bc8 Add package-level GoDoc documentation
Creates doc.go with comprehensive package documentation including
quick start, authentication, fluent API usage, task creation,
error handling, thread safety, and tag operation warnings.
2026-01-15 19:23:32 +01:00
408fb60b54 Add comprehensive README.md documentation
Documents installation, quick start, authentication methods,
fluent and direct API usage, task operations, error handling,
thread safety, and configuration options.
2026-01-15 19:20:57 +01:00
b325e7b3fd Add Mage build system
Set up magefiles/ directory with targets for test, coverage,
lint, and build commands. Uses github.com/magefile/mage v1.15.0.
2026-01-15 19:19:58 +01:00
610998283b Implement File API methods
- GetAllTaskFiles: retrieve all files attached to a task
- CreateTaskFile: upload file with base64 encoding
- DownloadTaskFile: download file with base64 decoding
- RemoveTaskFile: delete a task file
- TaskScope.GetFiles and UploadFile for fluent API
- Automatic base64 encoding/decoding for file content
- Comprehensive test coverage
2026-01-15 18:45:11 +01:00
39ff0a90c8 Implement Link API methods
- GetAllTaskLinks: retrieve all links for a task
- CreateTaskLink: create link between two tasks
- RemoveTaskLink: delete a task link
- TaskScope.GetLinks and LinkTo for fluent API
- Link types include "blocks", "is blocked by", etc.
- Comprehensive test coverage
2026-01-15 18:43:35 +01:00
4907a7caad Implement MoveToNextColumn and MoveToPreviousColumn
- MoveToNextColumn: moves task to next column in workflow
- MoveToPreviousColumn: moves task to previous column
- Gets columns sorted by position, finds current, moves to adjacent
- Returns ErrAlreadyInLastColumn when at workflow end
- Returns ErrAlreadyInFirstColumn when at workflow start
- Handles column gaps (non-sequential positions)
- Comprehensive test coverage for all edge cases
2026-01-15 18:42:02 +01:00
527d27b73f Implement global task search with parallel execution
- SearchTasksGlobally: cross-project search using errgroup
- Gets all projects, then searches each in parallel
- Results aggregated from all accessible projects
- Context cancellation propagates to all goroutines
- Single project failure cancels remaining searches
- Added golang.org/x/sync/errgroup dependency
- Comprehensive test coverage
2026-01-15 18:40:14 +01:00
87adebd798 Implement Comment API methods
- GetAllComments: retrieve all comments for a task
- GetComment: retrieve single comment by ID
- CreateComment: create comment and return the created comment
- UpdateComment: update comment content
- RemoveComment: delete a comment
- TaskScope.GetComments and AddComment for fluent API
- Returns ErrCommentNotFound when appropriate
- Comprehensive test coverage
2026-01-15 18:38:24 +01:00
c8eea853e5 Implement TaskScope tag methods with read-modify-write (CRITICAL)
- GetTags: retrieve task tags as map[int]string
- SetTags: replace all tags on a task
- ClearTags: remove all tags
- AddTag: read-modify-write, idempotent (no-op if tag exists)
- RemoveTag: read-modify-write, idempotent (no-op if tag doesn't exist)
- HasTag: check if task has a specific tag

WARNING: Tag operations are NOT atomic. Concurrent modifications may
cause data loss due to the read-modify-write pattern required by
Kanboard's setTaskTags API.

Comprehensive test coverage including idempotency tests.
2026-01-15 18:36:40 +01:00
371bdb8ba9 Implement TaskScope fluent builder (core methods)
- TaskScope struct for task-scoped operations
- Client.Task(taskID) returns a TaskScope
- Methods: Get, Close, Open, MoveToColumn, MoveToProject, Update
- MoveToColumn fetches task to get project_id and swimlane_id
- All methods delegate to direct Client methods
- Comprehensive test coverage
2026-01-15 18:34:38 +01:00
0c5b7fd6e9 Implement TaskUpdateParams builder
- TaskUpdateParams struct with fluent setter methods
- NewTaskUpdate() constructor
- Setters: SetTitle, SetDescription, SetColor, SetOwner, SetCategory,
  SetPriority, SetScore, SetDueDate, SetStartDate, SetReference, SetTags
- Clear methods: ClearDueDate, ClearStartDate, ClearOwner, ClearCategory
- Only set fields are included in update request (partial updates)
- Client.UpdateTaskFromParams for fluent task updates
- Comprehensive test coverage
2026-01-15 18:33:20 +01:00
28e517289a Implement TaskParams builder (Options Pattern)
- TaskParams struct with fluent setter methods
- NewTask(title) constructor
- Setters: WithDescription, InColumn, WithCategory, WithOwner, WithCreator,
  WithColor, WithPriority, WithScore, WithDueDate, WithStartDate,
  InSwimlane, WithReference, WithTags
- toCreateTaskRequest for conversion to CreateTaskRequest
- BoardScope.CreateTaskFromParams for fluent task creation
- Comprehensive test coverage for all setters and chaining
2026-01-15 18:31:13 +01:00
f04ea8866f Implement BoardScope fluent builder
- BoardScope struct for project-scoped operations
- Client.Board(projectID) returns a BoardScope
- Methods: GetColumns, GetCategories, GetTasks, SearchTasks, CreateTask
- All methods delegate to direct Client methods
- CreateTask automatically sets project ID from scope
- Comprehensive test coverage
2026-01-15 18:29:35 +01:00
c2a107054f Implement Task search and move methods
- SearchTasks: search tasks using Kanboard query syntax
- MoveTaskPosition: move task to specific position in column/swimlane
- MoveTaskToProject: move task to different project
- Comprehensive test coverage for all methods
2026-01-15 18:28:11 +01:00
d27aabe4c4 Implement Task API methods (CRUD operations)
- GetTask: retrieve single task by ID
- GetAllTasks: retrieve all tasks for a project with status filter
- CreateTask: create new task and return the created task
- UpdateTask: partial updates via pointer fields
- CloseTask/OpenTask: status operations with proper error handling
- Returns ErrTaskNotFound, ErrTaskClosed, ErrTaskOpen as appropriate
- Comprehensive test coverage for all methods and edge cases
2026-01-15 18:26:55 +01:00
fc4577e729 Implement Category API methods (GetAllCategories, GetCategory)
- GetAllCategories returns all categories for a project
- GetCategory returns a single category by ID
- Returns ErrCategoryNotFound for non-existent categories
- Added ErrCategoryNotFound to IsNotFound helper
- Comprehensive test coverage
2026-01-15 18:25:12 +01:00
2d3be3619c Implement Column API methods (GetColumns, GetColumn)
- GetColumns returns all columns for a project, sorted by position
- GetColumn returns a single column by ID
- Returns ErrColumnNotFound for non-existent columns
- Comprehensive test coverage including edge cases
2026-01-15 18:23:44 +01:00
7c8ebcc491 Implement Project API methods
Add direct client methods for project/board operations:

- GetAllProjects(ctx) - list all accessible projects
- GetProjectByID(ctx, projectID) - get project by ID
- GetProjectByName(ctx, name) - get project by name

All methods:
- Use context for cancellation support
- Return ErrProjectNotFound when project doesn't exist
- Properly wrap errors with context

Closes: kanboard-api-apl
2026-01-15 18:21:42 +01:00
88b92aa028 Implement Tag API methods (CRITICAL)
Add direct client methods for tag operations:

Must-have methods:
- GetTaskTags(ctx, taskID) - returns map[tagID]tagName
- SetTaskTags(ctx, projectID, taskID, tags) - replaces all tags

Nice-to-have methods:
- GetAllTags(ctx) - list all tags in system
- GetTagsByProject(ctx, projectID) - list project tags
- CreateTag(ctx, projectID, name, colorID) - create new tag
- UpdateTag(ctx, tagID, name, colorID) - update existing tag
- RemoveTag(ctx, tagID) - delete tag

Note: setTaskTags REPLACES all tags. Individual add/remove
requires read-modify-write pattern (to be implemented in TaskScope).

Closes: kanboard-api-16r
2026-01-15 18:20:23 +01:00
a38e62e77a Implement entity structs for Kanboard API responses
Add all entity structs matching Kanboard's JSON-RPC API format:

Entity structs:
- Project, Task, Column, Category, Comment
- TaskLink, TaskFile, Tag
- TaskStatus enum (StatusActive, StatusInactive)

Request structs:
- CreateTaskRequest with omitempty for optional fields
- UpdateTaskRequest with pointer fields for zero-value distinction

Custom JSON types for Kanboard's string-encoded values:
- StringBool - handles "0"/"1" string booleans
- StringInt - handles string-encoded integers
- StringInt64 - handles string-encoded int64 values

All structs properly handle Kanboard's quirky JSON format where
numeric fields are often returned as quoted strings.

Closes: kanboard-api-cyc
2026-01-15 18:18:47 +01:00
dbac08ac1e Implement Timestamp type for Unix timestamp JSON handling
Add custom Timestamp type that wraps time.Time for Kanboard's
Unix timestamp format:

UnmarshalJSON supports:
- Unix timestamps as integers
- Empty strings and "0" strings as zero time
- Null values as zero time
- Numeric strings (e.g., "1609459200")

MarshalJSON returns:
- 0 for zero time
- Unix timestamp for non-zero time

Includes comprehensive tests for round-trip marshaling
and struct embedding scenarios.

Closes: kanboard-api-25y
2026-01-15 18:15:33 +01:00
a56456cc00 Complete Client struct with fluent configuration
Add full client configuration with fluent builder pattern:

- WithTimeout(duration) - configurable request timeout
- WithLogger(slog.Logger) - optional debug logging
- DefaultTimeout constant (30 seconds)
- Default HTTP client with timeout on construction

All fluent methods return same client instance for chaining.
Client is thread-safe for concurrent use.

Closes: kanboard-api-uls
2026-01-15 18:14:22 +01:00
79385df87b Implement comprehensive error types and handling
Add complete error handling system for Kanboard API client:

Sentinel errors:
- Network: ErrConnectionFailed, ErrTimeout
- Auth: ErrUnauthorized, ErrForbidden
- Resources: ErrNotFound, ErrProjectNotFound, ErrTaskNotFound,
  ErrColumnNotFound, ErrCommentNotFound
- Logic: ErrAlreadyInLastColumn, ErrAlreadyInFirstColumn,
  ErrTaskClosed, ErrTaskOpen
- Validation: ErrEmptyTitle, ErrInvalidProjectID

Helper functions:
- IsNotFound() - checks all not-found error variants
- IsUnauthorized() - checks auth errors
- IsAPIError() - checks for API errors via errors.As

All errors support errors.Is/errors.As for proper error
wrapping and context preservation.

Closes: kanboard-api-s7k
2026-01-15 18:13:09 +01:00
ba942f3b52 Add authentication system tests
Add comprehensive tests for HTTP Basic Auth support:
- API token authentication (jsonrpc + token)
- Username/password authentication
- Verify no auth header when unconfigured
- Fluent configuration method chaining
- Auth overwrite behavior

The auth implementation was completed in the previous commit
as a dependency for JSON-RPC client.

Closes: kanboard-api-k33
2026-01-15 18:11:48 +01:00
a486a73ce1 Implement JSON-RPC client foundation
Add core JSON-RPC 2.0 protocol implementation for Kanboard API:

- JSONRPCRequest/Response/Error structs with proper JSON tags
- Generic call() method for sending requests and parsing responses
- Thread-safe request ID generation using atomic.Int64
- Automatic /jsonrpc.php path appending to baseURL
- Support for subdirectory installations
- HTTP Basic Auth support (API token and username/password)
- Error handling for unauthorized/forbidden responses

Includes comprehensive tests with httptest mock server.

Closes: kanboard-api-2g1
2026-01-15 18:10:35 +01:00
347fb75f11 Initial commit 2026-01-15 17:48:46 +01:00