processdoc

package
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 9, 2026 License: AGPL-3.0 Imports: 18 Imported by: 0

Documentation

Overview

Package processdoc serves process documentation (ADR-0143): a published BPMN process as a stored PDF plus the element prose it describes, its version history, and the revocable public link a reader without an account follows.

It is the first area carved out of the api server object under ADR-0147, and it is what a per-area service is meant to look like. Everything it needs is on Service and nothing else is reachable from here: its own store and version counters, the run loop that owns them, and three collaborators the rest of the server supplies — the rate limiter guarding the public route, a lookup for the deployment a document described, and the share-token minter.

The single-writer boundary is the runloop.Loop this service holds: every read and write of the store goes through it, and there is no other way from here to shared state (I3, ADR-0002). Design-time only — nothing here reaches the event log, the processor, or recovery.

Index

Constants

View Source
const PublicPath = "/public/process-docs/"

PublicPath is the prefix of the unauthenticated share URL. It lives in one place so the minted URL and the served route cannot drift.

Variables

This section is empty.

Functions

func NewID

func NewID() (string, error)

NewID mints a version id. 16 bytes of crypto randomness hex-encoded is filename-safe (so the id is its own store key) and collision-free in practice.

Types

type Code

type Code struct {
	// Label names the field the code came from, e.g. "Script" or "Condition".
	Label string `json:"label"`
	// Language is the code's language id (e.g. "powershell", "feel"), empty when
	// the field does not declare one.
	Language string `json:"language,omitempty"`
	// Source is the code itself, kept with its original whitespace so indentation
	// survives into the document.
	Source string `json:"source"`
}

Code is one code-bearing field of an element, snapshotted at publish time: a script task's job source (PowerShell/Python/JavaScript, ADR-0047), a FEEL condition or expression (ADR-0067), and the like. The document reproduces it verbatim so a reader can audit what a step actually runs, not merely what it is named — the prose says *what*, the code says *how*.

type Deployment

type Deployment struct {
	Key     uint64
	Version int32
}

Deployment is what a documentation record needs to know about the process version it documented: which deployment, and which version of it. Narrow on purpose — the service has no business with the rest of a deployment.

type Doc

type Doc struct {
	ID string `json:"id"`
	// ProcessID is the BPMN process id the document describes. It binds to the id,
	// not a deployment, because a process is documented whether or not it is
	// currently deployed.
	ProcessID   string `json:"processId"`
	ProcessName string `json:"processName,omitempty"`
	// Version is a per-processId counter, 1-based — the ADR-0128 layering above the
	// ADR-0019 per-process deployment version. It answers "which documented state of
	// this process is that?", not "which deployment".
	Version   int32  `json:"version"`
	Title     string `json:"title,omitempty"`
	Note      string `json:"note,omitempty"`
	CreatedAt int64  `json:"createdAt"`
	CreatedBy string `json:"createdBy,omitempty"`
	// DeploymentKey and DeploymentVersion record which deployment was live when the
	// document was produced, zero when the model was documented from a draft.
	DeploymentKey     uint64 `json:"deploymentKey,omitempty"`
	DeploymentVersion int32  `json:"deploymentVersion,omitempty"`
	PDFSize           int64  `json:"pdfSize"`
	// Elements is the documented element prose, snapshotted by value.
	Elements []Element `json:"elements,omitempty"`
	// XML is the BPMN source the document was produced from, so a reader of the
	// history can recover the exact model a version describes.
	XML string `json:"xml,omitempty"`
	// ShareToken is the opaque handle that serves this version's PDF without a
	// login (ADR-0029's mechanism). Empty means unshared, which is the default —
	// the artifact leaves the system only when someone says so.
	ShareToken string `json:"shareToken,omitempty"`
}

Doc is one published documentation version of a process: immutable metadata describing what was documented, with the PDF stored beside it.

type Element

type Element struct {
	ID   string `json:"id"`
	Type string `json:"type"` // the BPMN type, e.g. "bpmn:ServiceTask"
	Name string `json:"name,omitempty"`
	// Documentation is the element's <bpmn:documentation> text.
	Documentation string `json:"documentation,omitempty"`
	// Annotations are the <bpmn:textAnnotation> notes associated with this element,
	// in the order they were found. An annotation attached to nothing is documented
	// against the process itself rather than dropped.
	Annotations []string `json:"annotations,omitempty"`
	// Lane names the swimlane the element sits in, empty when the model has none
	// (ADR-0121).
	Lane string `json:"lane,omitempty"`
	// Code is the code-bearing fields of the element (scripts, FEEL expressions),
	// in the order a reader should meet them. Empty for the many elements that
	// carry no code.
	Code []Code `json:"code,omitempty"`
}

Element is one BPMN element as it was documented: the prose a reader needs about it, snapshotted at publish time so a later edit to the model cannot rewrite what an already-published version says.

type Service

type Service struct {

	// Limits are the installation's resource budgets. New sets them to
	// [limits.Default]; the server overwrites them with its own once it has read the
	// environment, so every ceiling in this service is the one operators configured
	// (ADR-0291).
	Limits limits.Limits
	// contains filtered or unexported fields
}

Service serves the documentation area. Build it with New.

func New

func New(loop *runloop.Loop, store *Store, allow func(clientIP string) bool,
	deployed func(processID string) (Deployment, bool), newToken func() (string, error)) *Service

New builds the documentation service over its own store directory. allow, deployed and newToken are the collaborators the server supplies; none of them may touch state the loop owns except when called from inside it (deployed is the only one that does, and the create path calls it on the loop).

func (*Service) HandleCreate

func (s *Service) HandleCreate(w http.ResponseWriter, r *http.Request)

HandleCreate records the next documentation version of a process (ADR-0143). Body: the produced PDF plus the element prose it describes.

func (*Service) HandleDelete

func (s *Service) HandleDelete(w http.ResponseWriter, r *http.Request)

HandleDelete prunes a version, taking its public URL with it. A missing version is not an error, so pruning is idempotent.

func (*Service) HandleGet

func (s *Service) HandleGet(w http.ResponseWriter, r *http.Request)

HandleGet returns one version in full: its metadata, the element prose, and the BPMN source it was produced from.

func (*Service) HandleGetPDF

func (s *Service) HandleGetPDF(w http.ResponseWriter, r *http.Request)

HandleGetPDF downloads a version's document.

func (*Service) HandleList

func (s *Service) HandleList(w http.ResponseWriter, r *http.Request)

HandleList returns one process's documentation history, newest version first.

func (*Service) HandlePrune

func (s *Service) HandlePrune(w http.ResponseWriter, r *http.Request)

HandlePrune applies a retention limit to a process's documentation history (ADR-0143's bounded-growth follow-up): it keeps the newest `keep` versions and deletes the older ones, PDF and all. Idempotent — pruning an already-short history removes nothing.

func (*Service) HandlePublic

func (s *Service) HandlePublic(w http.ResponseWriter, r *http.Request)

HandlePublic serves a shared version's PDF to a reader with no account. An unknown, malformed, or revoked token is one indistinguishable 404: the response must not reveal whether a document ever existed behind it.

func (*Service) HandleShare

func (s *Service) HandleShare(w http.ResponseWriter, r *http.Request)

HandleShare mints (or returns the existing) public link for one version. Idempotent by design: re-sharing must not rotate a URL that readers already hold.

func (*Service) HandleUnshare

func (s *Service) HandleUnshare(w http.ResponseWriter, r *http.Request)

HandleUnshare revokes a version's public link, killing the URL.

func (*Service) LoadVersions

func (s *Service) LoadVersions() error

LoadVersions rebuilds the per-process documentation counter from the durable records, so an export after a restart continues the sequence rather than restarting it at v1 and overwriting history. It runs before the loop serves traffic, so touching the map directly here respects the single-writer invariant.

type Store

type Store struct {
	*sidecar.Store[Doc]
}

Store is a durable store for process documentation versions (ADR-0143): one JSON record per version id under a single directory, each beside the PDF it describes. The PDF is why it wraps the shared store rather than being one — a version is two files, and both have to go together.

Every entry point rejects an id that is not bare hex before touching the filesystem. Ids here name their own files directly (they are already filename-safe), so that check is what keeps an id from escaping the directory.

func NewStore

func NewStore(dir string) (*Store, error)

NewStore opens (creating if needed) the process-docs directory. Versions list grouped by process, newest version first within each, tie-broken by id so the order is deterministic.

func (*Store) ByShareToken

func (s *Store) ByShareToken(shareToken string) (Doc, bool, error)

ByShareToken finds the version a public token addresses. An empty or unsafe token never matches, so the many unshared records — which carry no token — stay private.

func (*Store) Delete

func (s *Store) Delete(id string) error

Delete removes a version and its document. A missing file is not an error, so cleanup is idempotent; the PDF goes with the record, since neither is meaningful without the other. It shadows the embedded store's Delete so no caller can remove a record and leave its document orphaned.

func (*Store) ForProcess

func (s *Store) ForProcess(processID string) ([]Doc, error)

ForProcess returns one process's documentation history, newest version first.

func (*Store) Get

func (s *Store) Get(id string) (Doc, bool, error)

Get returns a version's record, or ok=false if there is none. An unsafe id is a clean miss rather than a filesystem lookup. It shadows the embedded store's Get deliberately: every caller goes through the guard.

func (*Store) PDF

func (s *Store) PDF(id string) ([]byte, error)

PDF returns a version's document bytes. An unknown or unsafe id is an error rather than an empty document, so a handler cannot serve a zero-byte PDF as if it were real.

func (*Store) PruneProcess

func (s *Store) PruneProcess(processID string, keep int) ([]string, error)

PruneProcess enforces a retention limit on one process's documentation history: it keeps the newest `keep` versions and deletes the rest, returning the ids it removed. It is the bounded-growth follow-up ADR-0143 flagged: every version keeps a PDF, so an unpruned archive grows without limit.

keep is clamped at zero — a negative limit would otherwise delete history it was asked to retain. keep >= the number of versions prunes nothing. Deleting the oldest is deliberate: history is answered newest-first, and the reason to prune is that ancient versions are the ones no longer worth their bytes.

func (*Store) Save

func (s *Store) Save(rec Doc, pdf []byte) error

Save writes a version durably: the PDF first, then the record. The order matters — a record is the thing readers discover, so it must never point at a document that is not yet on disk (I2).

func (*Store) SaveRecord

func (s *Store) SaveRecord(rec Doc) error

SaveRecord rewrites only the metadata sidecar, leaving the stored PDF alone. Minting or revoking a share token is such an update: the document is immutable, who may read it is not.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL