Documentation
¶
Overview ¶
Package store provides filesystem-backed storage for Clinban tickets.
Store knows the active ticket directory and archive directory. It scans ticket filenames for IDs, locates tickets by ID, reads and writes Markdown ticket files, lists active and archived records, and moves files between active and archive directories.
Writes are performed by writing a temporary file in the target directory and renaming it into place, so readers never observe a partially written final file during normal operation. The package does not enforce workflow transitions or schema rules; callers combine it with package fsm and package lint for those concerns.
Index ¶
- Variables
- type BatchError
- type ManagedFile
- type OpError
- type OpKind
- type Record
- type RenameOp
- type Store
- func (s *Store) ActivePath(archivePath string) string
- func (s *Store) AllIDs() ([]string, error)
- func (s *Store) BatchRenameWithinDir(ops []RenameOp) ([]string, error)
- func (s *Store) FindAllByID(id string) ([]string, error)
- func (s *Store) FindByID(id string) (path string, inArchive bool, err error)
- func (s *Store) ListActive() ([]Record, error)
- func (s *Store) ListArchive() ([]Record, error)
- func (s *Store) ManagedFiles() ([]ManagedFile, error)
- func (s *Store) MoveToActive(path string) (string, error)
- func (s *Store) MoveToArchive(path string) (string, error)
- func (s *Store) NextID() (int, error)
- func (s *Store) ReadTicket(path string) (*ticket.Ticket, error)
- func (s *Store) Remove(path string) error
- func (s *Store) RenameWithinDir(path, newBase string) (string, error)
- func (s *Store) TicketPath(id int, slug string) string
- func (s *Store) WriteTicket(t *ticket.Ticket, path string) error
Constants ¶
This section is empty.
Variables ¶
var ErrNotFound = errors.New("ticket not found")
ErrNotFound is returned by FindByID when no active or archived ticket file matches the requested ID.
Functions ¶
This section is empty.
Types ¶
type BatchError ¶ added in v0.2.0
BatchError is the error type returned by BatchRenameWithinDir on failure. Failed is the primary operation that triggered the failure. Rollback holds any errors from the best-effort cleanup or restore steps; it is non-empty only when the filesystem may be in an inconsistent state.
func (*BatchError) Error ¶ added in v0.2.0
func (e *BatchError) Error() string
Error implements the error interface. It returns a store-scoped summary string. The CLI layer owns the "resolve:" prefix and reformats for display.
func (*BatchError) Inconsistent ¶ added in v0.2.0
func (e *BatchError) Inconsistent() bool
Inconsistent reports whether the rollback encountered errors, meaning the filesystem may be in an inconsistent state.
type ManagedFile ¶ added in v0.2.0
type ManagedFile struct {
// ID is the zero-padded four-digit filename prefix.
ID string
// Path is the full filesystem path to the managed file.
Path string
// InArchive reports whether Path is under the configured archive directory.
InArchive bool
}
ManagedFile describes a ticket file whose name follows Clinban's managed ticket filename convention.
type OpError ¶ added in v0.2.0
OpError records a single failed filesystem operation within a batch rename.
type OpKind ¶ added in v0.2.0
type OpKind int
OpKind discriminates the kind of filesystem operation in an error report.
type Record ¶
type Record struct {
// Ticket is the parsed ticket content.
Ticket *ticket.Ticket
// Path is the full filesystem path from which Ticket was read.
Path string
// InArchive reports whether Path is under the configured archive directory.
InArchive bool
}
Record pairs a parsed ticket with its filesystem location.
type RenameOp ¶ added in v0.2.0
RenameOp describes a single within-directory rename for BatchRenameWithinDir. OldPath is the full path to the existing source file. NewBase is the destination basename only (no path separators); the destination directory is the same as OldPath's directory.
type Store ¶
type Store struct {
// TicketsDir is the directory containing active ticket files.
TicketsDir string
// ArchiveDir is the directory containing archived ticket files.
ArchiveDir string
}
Store manages ticket files on disk.
Store owns filesystem concerns only: locating, reading, writing, listing, and moving ticket files. It does not enforce schema validity or workflow transitions.
func (*Store) ActivePath ¶
ActivePath returns the active-directory path for archivePath's basename.
It is used when moving a ticket from archive back to active while preserving the existing filename.
func (*Store) AllIDs ¶
AllIDs returns every managed ticket ID found in active and archived filenames.
The returned IDs are the zero-padded filename prefixes used by lint for repository-wide uniqueness checks.
func (*Store) BatchRenameWithinDir ¶ added in v0.2.0
BatchRenameWithinDir renames all ops atomically within their respective directories using a two-phase link+remove protocol with rollback.
Pre-flight: validates every NewBase is a bare basename. On failure returns a plain error with zero filesystem mutation.
Phase 1 (Link): creates destination hard links. On failure at any op, all already-created links are removed best-effort and a *BatchError is returned.
Phase 2 (Remove): removes source files. On success returns dest paths in op order and nil. On failure (TASK-002 completes the rollback): returns *BatchError.
Return type is ([]string, error) — not ([]string, *BatchError) — to avoid the Go typed-nil footgun. Callers use errors.As to extract *BatchError.
func (*Store) FindAllByID ¶ added in v0.2.0
FindAllByID returns all managed ticket file paths whose four-digit ID prefix matches id. Both TicketsDir and ArchiveDir are searched.
The id argument is normalised to a four-digit zero-padded string before matching. Unlike FindByID, all matching paths are returned — not just the first. The returned slice is never nil; it is empty when no files match. ErrNotFound is never returned; the caller is responsible for handling an empty slice.
func (*Store) FindByID ¶
FindByID locates a managed ticket file by its four-digit ID prefix.
Active tickets are searched before archived tickets. If no matching file is found, FindByID returns ErrNotFound.
The id argument is normalised to a four-digit zero-padded string before matching, so "1", "01", "001", and "0001" are all equivalent.
func (*Store) ListActive ¶
ListActive returns managed tickets in TicketsDir as Records.
Only files following the managed ticket filename convention are parsed. Returns an empty (never nil) slice if the directory is empty or absent.
func (*Store) ListArchive ¶
ListArchive returns managed tickets in ArchiveDir as Records.
Only files following the managed ticket filename convention are parsed. Returns an empty (never nil) slice if the directory is empty or absent.
func (*Store) ManagedFiles ¶ added in v0.2.0
func (s *Store) ManagedFiles() ([]ManagedFile, error)
ManagedFiles returns all active and archived files whose names follow the managed ticket filename convention.
Unlike ListActive and ListArchive, ManagedFiles does not parse ticket contents. It is intended for filesystem operations such as collision repair where unrelated malformed tickets should not block inventory.
func (*Store) MoveToActive ¶
MoveToActive moves path into TicketsDir and returns the new path.
MoveToActive preserves the source basename and refuses to overwrite an existing destination file. The move is performed atomically via os.Link + os.Remove to avoid a TOCTOU race.
func (*Store) MoveToArchive ¶
MoveToArchive moves path into ArchiveDir and returns the new path.
ArchiveDir is created if necessary. MoveToArchive refuses to overwrite an existing destination file with the same basename. The move is performed atomically via os.Link + os.Remove to avoid a TOCTOU race.
func (*Store) NextID ¶
NextID scans TicketsDir and ArchiveDir and returns the next available numeric ticket ID.
IDs are discovered from filenames matching the managed ticket convention [0-9]{4}-*.md. Files that do not match that convention are ignored. Returns 1 if no matching files exist.
func (*Store) ReadTicket ¶
ReadTicket reads path and parses it as a Clinban ticket.
The returned error wraps either the filesystem read error or the ticket parse error. ReadTicket does not run lint; callers that need schema validation should call package lint after a successful read.
func (*Store) Remove ¶ added in v0.2.0
Remove deletes the ticket file at path from disk.
The path must be an absolute path to an existing file. If the file cannot be removed, the error is wrapped with context identifying the filename.
func (*Store) RenameWithinDir ¶ added in v0.2.0
RenameWithinDir renames path to newBase in the same directory and returns the new full path.
The operation refuses to overwrite an existing destination and uses os.Link + os.Remove to match the collision behavior of ticket moves.
func (*Store) TicketPath ¶
TicketPath returns the canonical active path for id and slug.
The filename format is <id>-<slug>.md, with id rendered as a zero-padded four-digit decimal number.
func (*Store) WriteTicket ¶
WriteTicket serialises t and writes it to path using a same-directory temporary file followed by rename.
The temporary file is created in the target directory so the final rename is on the same filesystem. WriteTicket does not modify t; callers are responsible for setting system-owned fields such as Updated before calling.