Documentation
¶
Overview ¶
Package legal is the paperwork your company needs, drafted, signed and filed.
The ORG-SCOPED legal-document surface (/v1/legal): a versioned, org-overridable library of standardized templates, a PURE merge-field generation engine that renders those templates from the org's own company/cap-table data, a KMS-sealed store for the generated documents, and the e-signature + filing seams that carry a document to execution — all on the shared audit plane.
THE BOUNDARY (a design invariant, enforced in the engine and the data model). Hanzo Legal MANAGES documents; it does NOT give legal advice, and it does NOT determine that a document is legally valid or sufficient. A generated document is a DRAFT rendered from the org's inputs; the legal determination belongs to the org's counsel. Formation and securities templates carry a mandatory counsel-review notice (CounselReview) that the engine prepends to every rendered document — the platform can never emit such a document without it. There is no "legally_valid" state in the model; a document is draft / out_for_signature / signed / voided, nothing more.
WHAT IT COMPOSES (DRY):
- text/template the PURE renderer (deterministic: no clock, no I/O — same inputs yield identical bytes, so a rendered contract is reproducible).
- cek encryption at rest for the document store (a rendered contract carries names + terms and is sealed on disk).
- the Esign / Filing seams (providers.go) — provider-agnostic, honest-stub default, config-driven real provider — mirroring the company formation seams.
- audit.Recorder the ONE tamper-evident trail (deps.Audit); every generate / sign / file action is recorded, referencing opaque document ids.
Index ¶
- Constants
- func MissingFields(t Template, data map[string]string) []string
- func Mount(app cloud.Router, deps cloud.Deps) error
- func Render(t Template, data map[string]string) ([]byte, error)
- func Shutdown() error
- func ValidateOverride(t Template) error
- type Category
- type DocStatus
- type Document
- type Esign
- type Field
- type Filer
- type Filing
- type FilingStatus
- type Signer
- type Store
- func (s *Store) Close() error
- func (s *Store) CreateDocument(ctx context.Context, d Document) error
- func (s *Store) CreateFiling(ctx context.Context, f Filing) error
- func (s *Store) GetDocument(ctx context.Context, org, id string) (Document, error)
- func (s *Store) ListDocuments(ctx context.Context, org string, limit int) ([]Document, error)
- func (s *Store) ListFilings(ctx context.Context, org string, limit int) ([]Filing, error)
- func (s *Store) ResolveCatalog(ctx context.Context, org string) ([]Template, error)
- func (s *Store) ResolveTemplate(ctx context.Context, org, templateID string) (Template, error)
- func (s *Store) SaveTemplateOverride(ctx context.Context, org string, t Template) (Template, error)
- func (s *Store) UpdateDocumentSign(ctx context.Context, org, id string, status DocStatus, provider, ref string, ...) error
- type Template
Constants ¶
const APIDisclaimer = "Hanzo Legal generates documents from your inputs and manages their lifecycle. " +
"It is document tooling, not legal advice, and does not determine that a document is legally valid — " +
"have your counsel review before execution."
APIDisclaimer rides on every generation/template response — the boundary made visible on the wire (distinct from CounselNotice, which is embedded IN the rendered document).
const CounselNotice = "> DRAFT — generated by Hanzo Legal from your inputs for review by your counsel. " +
"This is document tooling, not legal advice, and is not a determination that the document is " +
"legally valid or sufficient. Have your attorney review before execution.\n\n"
CounselNotice is prepended to every rendered document whose template is marked CounselReview (all formation and securities instruments). It is the boundary made visible on the document itself: a generated draft, for counsel review, not legal advice or a determination of validity.
Variables ¶
This section is empty.
Functions ¶
func MissingFields ¶
MissingFields returns the declared fields absent (or blank) in data, sorted. The engine fails closed on any missing field rather than rendering a blank into a legal document — a silent blank in a contract is a defect, not a convenience.
func Mount ¶
Mount wires /v1/legal/* and opens the sealed store under DataDir. The e-sign and filing seams default to the honest stubs; a real provider is a config-driven swap (the seams are provider-agnostic).
func Render ¶
Render executes a template against its merge data and returns the rendered document bytes. It fails closed on a missing required field (before AND during execution via missingkey=error). The CounselNotice is prepended whenever the template is CounselReview OR its category REQUIRES counsel review (formation/equity securities), so the boundary rides on the document itself — the engine cannot emit a securities-class document without it, regardless of how the flag was set.
func ValidateOverride ¶
ValidateOverride reports whether t is a storable override: its body PARSES and every merge field the body references is DECLARED in t.Fields. An undeclared reference is refused because the fail-closed missing-field check (MissingFields) only inspects DECLARED fields and missingkey=error only catches ABSENT keys — so an undeclared field passed as an empty string would otherwise render a silent blank into a legal document. Requiring body refs ⊆ declared fields makes MissingFields authoritative.
Types ¶
type Category ¶
type Category string
Category groups the template library by the corporate need it serves. Orthogonal to company formation (which generates the incorporation instruments from a Formation); Legal owns the general engine and the ongoing-operations catalog.
type DocStatus ¶
type DocStatus string
DocStatus is the lifecycle of a generated document. There is deliberately no "legally_valid" value — validity is counsel's determination, not the platform's.
const ( StatusDraft DocStatus = "draft" // generated, not yet sent for signature StatusOutForSig DocStatus = "out_for_signature" // an e-signature request is open StatusSigned DocStatus = "signed" // the e-signature provider reported completion StatusVoided DocStatus = "voided" // withdrawn before execution )
type Document ¶
type Document struct {
ID string `json:"id"`
Org string `json:"org"`
TemplateID string `json:"templateId"`
TemplateVersion int `json:"templateVersion"`
Category Category `json:"category"`
Title string `json:"title"`
ContentType string `json:"contentType"`
Body string `json:"body,omitempty"`
Status DocStatus `json:"status"`
EsignProvider string `json:"esignProvider,omitempty"`
EsignRef string `json:"esignRef,omitempty"`
CreatedAt int64 `json:"createdAt"`
UpdatedAt int64 `json:"updatedAt"`
SignedAt int64 `json:"signedAt,omitempty"`
}
Document is a generated legal document. Body is the rendered content — sealed at rest by the cek store, returned only to the owning org. It records which template version produced it (so a document is reproducible and auditable) and its signature lifecycle.
type Esign ¶
type Esign interface {
Name() string
Request(ctx context.Context, org, docID, title string, signers []Signer) (ref string, err error)
Status(ctx context.Context, org, ref string) (complete bool, err error)
}
Esign is the e-signature seam. Request opens a signature request over a document for the given signers and returns a provider reference; Status reports completion. A real provider (DocuSign, Dropbox Sign, or the in-house clients/esign bundle) implements this; stubEsign is the honest default.
type Field ¶
Field declares one merge field a template consumes: the key used in the template body ({{.key}}) and a human label. Every declared field is REQUIRED — the engine fails closed on a missing one rather than rendering a blank into a contract.
type Filer ¶
type Filer interface {
Name() string
Submit(ctx context.Context, org, jurisdiction string, docIDs []string) (FilingStatus, string, error)
}
Filer is the state/agency filing seam. Submit records a filing of the named documents; a real partner (Clerky, Firstbase, CSC) returns the state file number. stubFiler is the honest default: it records a "manual" status ("file through your registered agent") and fabricates no filing id.
type Filing ¶
type Filing struct {
ID string `json:"id"`
Org string `json:"org"`
DocumentIDs []string `json:"documentIds"`
Jurisdiction string `json:"jurisdiction,omitempty"`
Provider string `json:"provider"`
Status FilingStatus `json:"status"`
Note string `json:"note,omitempty"`
CreatedAt int64 `json:"createdAt"`
UpdatedAt int64 `json:"updatedAt"`
}
Filing tracks a state/agency filing of one or more generated documents. It is a TRACKING record: the platform does not file autonomously; the honest default state is "manual" (file through your registered agent) until a filing partner is wired.
type FilingStatus ¶
type FilingStatus string
FilingStatus mirrors the company formation filing seam: honest states, no fabricated filing id when no partner is wired.
const ( FilingManual FilingStatus = "manual" // no partner wired — file through a registered agent FilingSubmitted FilingStatus = "submitted" // a partner accepted the submission FilingFiled FilingStatus = "filed" // the state accepted the filing FilingRejected FilingStatus = "rejected" // the state/partner rejected it )
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store persists legal templates (org overrides), generated documents, and filings. ONE encrypted SQLite file — the deployment's own "legal" — because a rendered contract carries names and terms, so the body is sealed at rest. `org` scopes every table and every query. MaxOpenConns(1) serializes writes.
func (*Store) CreateDocument ¶
func (*Store) GetDocument ¶
func (*Store) ListDocuments ¶
func (*Store) ListFilings ¶
func (*Store) ResolveCatalog ¶
ResolveCatalog returns the org's active catalog: every built-in, with the org's overrides applied, plus any org-only templates.
func (*Store) ResolveTemplate ¶
ResolveTemplate returns the ACTIVE template for an org: its latest override if any, else the built-in. errNotFound when neither exists.
func (*Store) SaveTemplateOverride ¶
SaveTemplateOverride persists a new version of an org's template and returns it.
type Template ¶
type Template struct {
ID string `json:"id"`
Category Category `json:"category"`
Title string `json:"title"`
Version int `json:"version"`
Origin string `json:"origin"` // builtin | org
CounselReview bool `json:"counselReview"`
Fields []Field `json:"fields"`
Body string `json:"body"`
}
Template is one standardized document template. Body is a text/template source that references its Fields as {{.key}}. Version increments on each org override; a built-in has Version 1 and Origin "builtin". CounselReview marks the formation and securities instruments that must carry CounselNotice.