Documentation
¶
Overview ¶
Package tracker mounts the Hanzo Cloud /v1/tracker/* surface: a native-Go, per-org issue tracker (projects + issues) on SQLite. It is the durable replacement for the prior Svelte hanzo.team tracker, whose upstream each-block reactive-batching render race left issue lists rendering zero rows. Native @hanzo/gui over this one store sidesteps that entire class of bug: the rows come back as plain JSON and render deterministically.
Org isolation is enforced SERVER-SIDE on every request: the org is principal.Org(c) — the value SanitizeIdentity minted from the VALIDATED bearer owner claim (HIP-0026) — and NEVER a client-supplied header. Every store query filters WHERE org=?, so one org can never read or mutate another's projects or issues.
Surface (all org-scoped; /v1 only):
POST /v1/tracker/projects create a project -> Project (201) GET /v1/tracker/projects list projects -> [Project] GET /v1/tracker/projects/:key project detail -> Project PATCH /v1/tracker/projects/:key update a project -> Project DELETE /v1/tracker/projects/:key delete a project (+ issues) POST /v1/tracker/projects/:key/issues create an issue -> Issue (201) GET /v1/tracker/projects/:key/issues[?status=&kind=&repo=&source=] list -> [Issue] GET /v1/tracker/projects/:key/issues/:num issue detail -> Issue PATCH /v1/tracker/projects/:key/issues/:num update an issue -> Issue DELETE /v1/tracker/projects/:key/issues/:num delete an issue
Order 129: binds /v1/tracker/* before the AI subsystem's /v1/* catch-all (150). serve.go auto-registers GET /v1/tracker/health.
Index ¶
- func Mount(app *zip.App, deps cloud.Deps) error
- func Shutdown() error
- type AgentPR
- type AgentPRInput
- type Issue
- type IssueFilter
- type Project
- type Store
- func (s *Store) Close() error
- func (s *Store) CreateIssue(ctx context.Context, i Issue) (Issue, error)
- func (s *Store) CreateProject(ctx context.Context, p Project) error
- func (s *Store) DeleteIssue(ctx context.Context, org, projectID string, number int) (bool, error)
- func (s *Store) DeleteProject(ctx context.Context, org, key string) (bool, error)
- func (s *Store) GetIssue(ctx context.Context, org, projectID string, number int) (Issue, error)
- func (s *Store) GetProject(ctx context.Context, org, key string) (Project, error)
- func (s *Store) ListIssues(ctx context.Context, org, projectID string, f IssueFilter) ([]Issue, error)
- func (s *Store) ListProjects(ctx context.Context, org string) ([]Project, error)
- func (s *Store) UpdateIssue(ctx context.Context, i Issue) error
- func (s *Store) UpdateProject(ctx context.Context, p Project) error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type AgentPR ¶ added in v1.801.23
type AgentPR struct {
Identifier string // "KEY-N" — the human handle
ProjectKey string // the tracker project KEY the row lives under
Number int // per-project monotonic number
}
AgentPR is the created row's stable handle: KEY-N plus the parts to build it.
func CreateAgentPR ¶ added in v1.801.23
func CreateAgentPR(ctx context.Context, in AgentPRInput) (AgentPR, error)
CreateAgentPR opens the PR work item for a coding run: it get-or-creates the tracker project keyed off the repo (so a repo's PRs share one board), then inserts the Kind:"pr" Source:"agent" issue and returns its KEY-N identifier. Idempotent at the project layer (a concurrent create resolves back to the same project); the issue itself is always a new row (per-run PR).
type AgentPRInput ¶ added in v1.801.23
type AgentPRInput struct {
Org string // tenant (isolation key)
Project string // IAM project slug (physical DB scope); "" = the org default
Repo string // git repo the branch was pushed to (the Repo binding)
Base string // base branch the PR targets (recorded in the body)
Head string // the pushed branch (the ExtRef anchor)
Title string // work-item title (from the task)
Body string // description: summary / diffstat + session link
Assignee string // the agent ref (e.g. "hanzo")
}
AgentPRInput is the closed set a coding run supplies to open its PR row. The four discriminators are set here: Kind is always "pr", Source always "agent", Repo binds the git repo, and Head (the pushed branch) is the ExtRef anchor.
type Issue ¶
type Issue struct {
ID string
ProjectID string
Org string
Number int
Kind string // issue | pr | epic (default "issue")
Source string // team | git | crm | helpdesk | cms | agent (default "team")
Repo string // git repo binding; "" = not repo-bound
ExtRef string // external anchor (PR branch, or link into another plane)
Title string
Description string
Status string
Priority string
Assignee string
Labels string
CreatedAt int64
UpdatedAt int64
}
Issue is THE ONE engineering/project work-item primitive for Hanzo — polymorphic by Kind so a git issue, a pull request and a parent epic are all the same row, and every work-item surface (hanzo.team's board, a git repo's Issues/PRs tab, an agent's queue) is a FILTER over this table, never a second tracker. It is NOT the domain-record plane: helpdesk tickets, CMS content and CRM deals live on framework.DocType / crm and link here by ExtRef — see contract.go for the three-plane boundary. Number is monotonic PER PROJECT (KEY-1, KEY-2, …), allocated under the single-writer transaction in CreateIssue so it never races. Status is the board column; Labels is a comma-joined tag string (split at the HTTP boundary).
The four discriminators (Kind, Source, Repo, ExtRef) are the alignment spine:
- Kind: issue | pr | epic — what it IS (the small closed work-item set).
- Source: team | git | crm | helpdesk | cms | agent — which surface OPENED it.
- Repo: the git repo it belongs to (Kind pr/issue from git); "" otherwise — so a repo's Issues/PRs tab is `ListIssues(... Filter{Repo, Kind})`.
- ExtRef: the external anchor (PR branch, or a link INTO another plane).
They are identity, set once at Create and immutable thereafter (Update touches only the mutable board state), so a row never migrates between surfaces.
type IssueFilter ¶ added in v1.800.1
IssueFilter narrows ListIssues. All fields optional (empty = no constraint). This is the ONE knob every work-item surface turns: hanzo.team passes {Status}, a git repo's Issues tab passes {Repo, Kind:"issue"}, its PRs tab {Repo, Kind:"pr"}, an agent's queue {Source:"agent"}.
type Project ¶
type Project struct {
ID string
Org string
Key string
Name string
Description string
CreatedAt int64
UpdatedAt int64
}
Project is an org-scoped issue tracker project (a Linear "team"). Its Key is the org-unique, uppercase handle that both routes the URL (/v1/tracker/ projects/:key) AND prefixes every issue identifier (KEY-<number>). Org isolation is the org column, filtered on every query.
Distinct from projects.Project (not a duplicate): that is the Slug-keyed deployable site forming this tracker's physical tenant boundary; these KEY-prefixed teams are rows WITHIN it.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is one (org, project)'s tracker database — ONE SQLite file per project at {DataDir}/orgs/{orgSlug}/projects/{projectSlug}/tracker.db (opened via cloud.OrgDB). tracker is project-scoped: the physical boundary is the IAM project, with the org column retained as defense-in-depth. MaxOpenConns(1) serializes writes against the file lock (and makes the CreateIssue number allocation a safe read-modify-write inside one transaction).
func (*Store) CreateIssue ¶
CreateIssue allocates the next per-project number and inserts the issue in ONE transaction. The transaction holds the single pool connection for its whole duration, so the MAX(number)+1 read and the INSERT are serialized against any concurrent create — the number can never be handed out twice.
func (*Store) CreateProject ¶
CreateProject inserts one project. A UNIQUE(org,key) violation surfaces as errConflict.
func (*Store) DeleteIssue ¶
DeleteIssue removes one issue scoped to (org, project, number). Reports whether a row was deleted.
func (*Store) DeleteProject ¶
DeleteProject removes a project and all its issues in one transaction. Reports whether a project row was deleted.
func (*Store) GetIssue ¶
GetIssue returns one issue scoped to (org, project, number) or errNotFound.
func (*Store) GetProject ¶
GetProject returns the project for (org,key) or errNotFound.
func (*Store) ListIssues ¶
func (s *Store) ListIssues(ctx context.Context, org, projectID string, f IssueFilter) ([]Issue, error)
ListIssues returns issues for a project narrowed by IssueFilter. Ordered by status then number so a status-grouped view renders deterministically and a single-column board reads oldest-first.
func (*Store) ListProjects ¶
ListProjects returns every project for org, most-recently-updated first.
func (*Store) UpdateIssue ¶
UpdateIssue overwrites the mutable fields of an issue scoped to (org, project, number). id+project_id+org+number+created_at are immutable.