Files
Steve Cliff b07572fed5 Released v1
2026-02-12 10:37:19 +00:00

7.8 KiB

1. Project Scaffolding

  • 1.1 Initialize Go module (go mod init github.com/dcgsteve/pcli)
  • 1.2 Create directory structure: cmd/, client/, model/, output/, logging/
  • 1.3 Add Cobra dependency (go get github.com/spf13/cobra)
  • 1.4 Create main.go entry point that calls cmd.Execute()

2. Logging

  • 2.1 Implement logging/logging.goNewLogger(level string) *slog.Logger that parses level string, creates JSON handler writing to stderr

3. Model Types

  • 3.1 Define model/types.go — Project, Board, List, Card, Comment, TaskList, Task, Label, Action, CardLabel, CardMembership structs with JSON tags and pointer types for nullable fields
  • 3.2 Define Envelope struct (Data any, Error *string) in model/types.go
  • 3.3 Define APIError struct (StatusCode int, Message string) implementing the error interface

4. Output Formatting

  • 4.1 Implement output/output.goPrint(data any, format string, w io.Writer) function that switches on format
  • 4.2 Implement JSON output mode — marshal Envelope{Data: data, Error: nil} to stdout
  • 4.3 Implement error output — PrintError(err error, format string, w io.Writer) that writes Envelope{Data: nil, Error: msg} for JSON, or error to stderr for table
  • 4.4 Implement table output mode — tabwriter-based rendering with per-resource column definitions

5. Base HTTP Client

  • 5.1 Implement client/client.goClient struct with BaseURL, Token, HTTPClient, Logger fields
  • 5.2 Implement NewClient(baseURL, token string, logger *slog.Logger) *Client
  • 5.3 Implement Do(ctx, method, path string, body any) (json.RawMessage, error) — URL construction, bearer header, JSON marshal/unmarshal, DEBUG logging with method/path/status/duration
  • 5.4 Implement APIError handling — map 4xx/5xx responses to APIError, WARN logging on errors
  • 5.5 Implement DoNoBody(ctx, method, path string) (json.RawMessage, error) convenience method for GET/DELETE

6. Root Command and Global Flags

  • 6.1 Implement cmd/root.go — root Cobra command with --format, --url, --token, --log-level persistent flags
  • 6.2 Implement PersistentPreRunE — resolve URL/token from flags or env vars (flag > env), validate both present, initialize logger, create client instance
  • 6.3 Wire output format into a shared variable accessible by all subcommands

7. Client — Project Operations

  • 7.1 Implement client/projects.goListProjects(ctx) ([]model.Project, error)
  • 7.2 Implement GetProject(ctx, id string) (*model.Project, error)

8. Client — Board Operations

  • 8.1 Implement client/boards.goGetBoard(ctx, id string) (*model.Board, error)
  • 8.2 Implement ListBoardActions(ctx, boardId string, limit int) ([]model.Action, error) with cursor-based pagination using beforeId

9. Client — Card Operations

  • 9.1 Implement client/cards.goGetCard(ctx, id string) (*model.Card, error)
  • 9.2 Implement CreateCard(ctx, listId string, fields) (*model.Card, error)
  • 9.3 Implement UpdateCard(ctx, id string, fields) (*model.Card, error)
  • 9.4 Implement DeleteCard(ctx, id string) error
  • 9.5 Implement DuplicateCard(ctx, id string, name *string, position *float64) (*model.Card, error)
  • 9.6 Implement ListCards(ctx, listId string, limit int) ([]model.Card, error) with cursor-based pagination using before
  • 9.7 Implement ListCardActions(ctx, cardId string, limit int) ([]model.Action, error) with cursor-based pagination using beforeId
  • 9.8 Implement ListCardsByBoard(ctx, boardId string, limit int) ([]model.CardWithList, error) — multi-call enrichment: get board → get cards per list → inject listName
  • 9.9 Implement AddCardLabel(ctx, cardId, labelId string) error
  • 9.10 Implement RemoveCardLabel(ctx, cardId, labelId string) error
  • 9.11 Implement AddCardMember(ctx, cardId, userId string) error
  • 9.12 Implement RemoveCardMember(ctx, cardId, userId string) error

10. Client — Comment Operations

  • 10.1 Implement client/comments.goListComments(ctx, cardId string, limit int) ([]model.Comment, error) with cursor-based pagination using beforeId
  • 10.2 Implement CreateComment(ctx, cardId, text string) (*model.Comment, error)
  • 10.3 Implement UpdateComment(ctx, id, text string) (*model.Comment, error)
  • 10.4 Implement DeleteComment(ctx, id string) error

11. Client — Task List Operations

  • 11.1 Implement client/task_lists.goCreateTaskList(ctx, cardId string, fields) (*model.TaskList, error)
  • 11.2 Implement GetTaskList(ctx, id string) (*model.TaskList, error)
  • 11.3 Implement UpdateTaskList(ctx, id string, fields) (*model.TaskList, error)
  • 11.4 Implement DeleteTaskList(ctx, id string) error

12. Client — Task Operations

  • 12.1 Implement client/tasks.goCreateTask(ctx, taskListId string, fields) (*model.Task, error)
  • 12.2 Implement UpdateTask(ctx, id string, fields) (*model.Task, error)
  • 12.3 Implement DeleteTask(ctx, id string) error

13. Client — Label Operations

  • 13.1 Implement client/labels.goCreateLabel(ctx, boardId string, fields) (*model.Label, error)
  • 13.2 Implement UpdateLabel(ctx, id string, fields) (*model.Label, error)
  • 13.3 Implement DeleteLabel(ctx, id string) error

14. CLI — Project Commands

  • 14.1 Implement cmd/project.goproject parent command, project list subcommand, project get <id> subcommand

15. CLI — Board Commands

  • 15.1 Implement cmd/board.goboard parent command, board get <id> subcommand, board actions <id> subcommand with --limit flag

16. CLI — Card Commands

  • 16.1 Implement cmd/card.gocard parent command
  • 16.2 Implement card list subcommand with mutually required --board / --list flags and --limit
  • 16.3 Implement card get <id> subcommand
  • 16.4 Implement card create subcommand with --list, --name (required), --description, --type, --position, --due-date, --due-completed flags
  • 16.5 Implement card update <id> subcommand with optional update flags
  • 16.6 Implement card delete <id> subcommand
  • 16.7 Implement card duplicate <id> subcommand with optional --name, --position
  • 16.8 Implement card move <id> subcommand with required --list and optional --position
  • 16.9 Implement card assign <id> and card unassign <id> subcommands with required --user
  • 16.10 Implement card add-label <id> and card remove-label <id> subcommands with required --label
  • 16.11 Implement card actions <id> subcommand with --limit

17. CLI — Comment Commands

  • 17.1 Implement cmd/comment.gocomment parent command, comment list with --card and --limit, comment create with --card and --text, comment update <id> with --text, comment delete <id>

18. CLI — Task List Commands

  • 18.1 Implement cmd/task_list.gotask-list parent command, task-list create with --card, --name, optional flags, task-list get <id>, task-list update <id>, task-list delete <id>

19. CLI — Task Commands

  • 19.1 Implement cmd/task.gotask parent command, task create with --task-list, --name, optional flags, task update <id> with optional flags, task delete <id>

20. CLI — Label Commands

  • 20.1 Implement cmd/label.golabel parent command, label create with --board, --name, optional --color, --position, label update <id>, label delete <id>

21. Build and Verify

  • 21.1 Verify go build produces a clean binary
  • 21.2 Verify pcli --help displays all commands and global flags
  • 21.3 Verify error output when PLANKA_URL / PLANKA_TOKEN are missing
  • 21.4 Add README.md with installation, configuration, and usage examples