legal

package
v1.801.455 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

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

View Source
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).

View Source
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

func MissingFields(t Template, data map[string]string) []string

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

func Mount(app cloud.Router, deps cloud.Deps) error

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

func Render(t Template, data map[string]string) ([]byte, error)

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 Shutdown

func Shutdown() error

Shutdown closes the store. Idempotent.

func ValidateOverride

func ValidateOverride(t Template) error

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.

const (
	CategoryFormation Category = "formation" // IP assignment, 83(b) election, ...
	CategoryEquity    Category = "equity"    // SAFE, subscription, option grant, ...
	CategoryOps       Category = "ops"       // NDA, MSA, SOW, offer letter, ...
	CategorySales     Category = "sales"     // ToS, privacy policy, DPA, ...
)

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

type Field struct {
	Key   string `json:"key"`
	Label string `json:"label"`
}

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 Signer

type Signer struct {
	Name  string `json:"name"`
	Email string `json:"email"`
}

Signer is one e-signature recipient.

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) Close

func (s *Store) Close() error

func (*Store) CreateDocument

func (s *Store) CreateDocument(ctx context.Context, d Document) error

func (*Store) CreateFiling

func (s *Store) CreateFiling(ctx context.Context, f Filing) error

func (*Store) GetDocument

func (s *Store) GetDocument(ctx context.Context, org, id string) (Document, error)

func (*Store) ListDocuments

func (s *Store) ListDocuments(ctx context.Context, org string, limit int) ([]Document, error)

func (*Store) ListFilings

func (s *Store) ListFilings(ctx context.Context, org string, limit int) ([]Filing, error)

func (*Store) ResolveCatalog

func (s *Store) ResolveCatalog(ctx context.Context, org string) ([]Template, error)

ResolveCatalog returns the org's active catalog: every built-in, with the org's overrides applied, plus any org-only templates.

func (*Store) ResolveTemplate

func (s *Store) ResolveTemplate(ctx context.Context, org, templateID string) (Template, error)

ResolveTemplate returns the ACTIVE template for an org: its latest override if any, else the built-in. errNotFound when neither exists.

func (*Store) SaveTemplateOverride

func (s *Store) SaveTemplateOverride(ctx context.Context, org string, t Template) (Template, error)

SaveTemplateOverride persists a new version of an org's template and returns it.

func (*Store) UpdateDocumentSign

func (s *Store) UpdateDocumentSign(ctx context.Context, org, id string, status DocStatus, provider, ref string, updatedAt, signedAt int64) error

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.

func Builtins

func Builtins() []Template

Builtins returns a copy of the standardized library (stable order by id).

Jump to

Keyboard shortcuts

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