crm

package
v1.786.72 Latest Latest
Warning

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

Go to latest
Published: Jul 4, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package crm mounts the Hanzo Cloud /v1/crm/* surface: a native-Go, per-org CRM (companies, contacts, opportunities) on Base/SQLite. It is the first slice of the "collapse the business apps into the unified cloud binary" program (universe/docs/architecture/unified-backend-go.md) — a native-Go port of the Twenty CRM core model, NOT a proxy to a NestJS backend.

The three entities are faithful to Twenty's `company` / `person` / `opportunity` standard objects, with Twenty's composite fields (FULL_NAME, EMAILS, CURRENCY, LINKS, ADDRESS) flattened to scalar columns for SQLite.

Tenant isolation is enforced SERVER-SIDE on every request: the org is c.Org() — 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 tenant can never read or mutate another's data.

Surface (all org-scoped; /v1 only):

GET    /v1/crm/summary               per-org row counts (companies/contacts/opps)
GET    /v1/crm/companies             list companies                 -> {data:[…]}
POST   /v1/crm/companies             create a company               -> Company (201)
GET    /v1/crm/companies/:id         company detail                 -> Company
PUT    /v1/crm/companies/:id         update a company               -> Company
DELETE /v1/crm/companies/:id         delete a company (+ clear refs)
GET    /v1/crm/contacts              list contacts (?companyId=)     -> {data:[…]}
POST   /v1/crm/contacts             create a contact               -> Contact (201)
GET    /v1/crm/contacts/:id          contact detail                 -> Contact
PUT    /v1/crm/contacts/:id          update a contact               -> Contact
DELETE /v1/crm/contacts/:id          delete a contact (+ clear refs)
GET    /v1/crm/opportunities         list opportunities (?stage=)    -> {data:[…]}
POST   /v1/crm/opportunities        create an opportunity          -> Opportunity (201)
GET    /v1/crm/opportunities/:id     opportunity detail             -> Opportunity
PUT    /v1/crm/opportunities/:id     update an opportunity          -> Opportunity
DELETE /v1/crm/opportunities/:id     delete an opportunity

Order 131: binds /v1/crm/* before the AI subsystem's /v1/* catch-all (150). serve.go auto-registers GET /v1/crm/health.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Mount

func Mount(app *zip.App, deps cloud.Deps) error

Mount wires the crm surface onto app per HIP-0106.

func Shutdown

func Shutdown() error

Shutdown closes the crm store. Idempotent.

Types

type Company

type Company struct {
	ID         string `json:"id"`
	Org        string `json:"-"`
	Name       string `json:"name"`
	DomainName string `json:"domainName"`
	Employees  int64  `json:"employees"`
	City       string `json:"city"`
	Country    string `json:"country"`
	ARR        int64  `json:"arr"`
	Currency   string `json:"currency"`
	ICP        bool   `json:"idealCustomerProfile"`
	Linkedin   string `json:"linkedinLink"`
	XLink      string `json:"xLink"`
	CreatedAt  int64  `json:"createdAt"`
	UpdatedAt  int64  `json:"updatedAt"`
}

Company is an org-scoped account record, faithful to Twenty's `company` standard object (composites flattened to scalar columns for SQLite): ARR is minor units (cents) of Currency; ICP is the ideal-customer-profile flag.

type Contact

type Contact struct {
	ID        string `json:"id"`
	Org       string `json:"-"`
	FirstName string `json:"firstName"`
	LastName  string `json:"lastName"`
	Email     string `json:"email"`
	Phone     string `json:"phone"`
	JobTitle  string `json:"jobTitle"`
	City      string `json:"city"`
	CompanyID string `json:"companyId"`
	Linkedin  string `json:"linkedinLink"`
	XLink     string `json:"xLink"`
	CreatedAt int64  `json:"createdAt"`
	UpdatedAt int64  `json:"updatedAt"`
}

Contact is an org-scoped person record, faithful to Twenty's `person` standard object (FULL_NAME/EMAILS/PHONES composites flattened). CompanyID is an optional in-org relation to a Company.

type Opportunity

type Opportunity struct {
	ID             string `json:"id"`
	Org            string `json:"-"`
	Name           string `json:"name"`
	Amount         int64  `json:"amount"`
	Currency       string `json:"currency"`
	Stage          string `json:"stage"`
	CloseDate      int64  `json:"closeDate"`
	CompanyID      string `json:"companyId"`
	PointOfContact string `json:"pointOfContactId"`
	CreatedAt      int64  `json:"createdAt"`
	UpdatedAt      int64  `json:"updatedAt"`
}

Opportunity is an org-scoped deal record, faithful to Twenty's `opportunity` standard object. Amount is minor units (cents) of Currency; CloseDate is a unix second (0 == unset). Stage is validated against the default pipeline.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store is the CRM database. ONE SQLite file ({DataDir}/crm.db) holds every org's records; tenant isolation is the `org` column, enforced on EVERY query. This mirrors clients/prompts and clients/eval exactly (the ONE storage pattern). MaxOpenConns(1) serializes writes against the single-writer file.

func (*Store) Close

func (s *Store) Close() error

Close closes the underlying database. Idempotent-safe via sql.DB.

func (*Store) Counts

func (s *Store) Counts(ctx context.Context, org string) (companies, contacts, opps int, err error)

Counts returns per-org row counts across the three entities — a real, non-fabricated summary for the CRM module's overview cards.

func (*Store) CreateCompany

func (s *Store) CreateCompany(ctx context.Context, c Company) (Company, error)

func (*Store) CreateContact

func (s *Store) CreateContact(ctx context.Context, c Contact) (Contact, error)

func (*Store) CreateOpportunity

func (s *Store) CreateOpportunity(ctx context.Context, o Opportunity) (Opportunity, error)

func (*Store) DeleteCompany

func (s *Store) DeleteCompany(ctx context.Context, org, id string) (bool, error)

DeleteCompany removes a company and NULLs any dangling contact/opportunity refs to it within the same org (no orphaned foreign refs). One transaction.

func (*Store) DeleteContact

func (s *Store) DeleteContact(ctx context.Context, org, id string) (bool, error)

DeleteContact removes a contact and clears any opportunity point-of-contact refs to it within the org. One transaction.

func (*Store) DeleteOpportunity

func (s *Store) DeleteOpportunity(ctx context.Context, org, id string) (bool, error)

func (*Store) GetCompany

func (s *Store) GetCompany(ctx context.Context, org, id string) (Company, error)

func (*Store) GetContact

func (s *Store) GetContact(ctx context.Context, org, id string) (Contact, error)

func (*Store) GetOpportunity

func (s *Store) GetOpportunity(ctx context.Context, org, id string) (Opportunity, error)

func (*Store) ListCompanies

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

func (*Store) ListContacts

func (s *Store) ListContacts(ctx context.Context, org, companyID string, limit int) ([]Contact, error)

ListContacts lists the org's contacts, optionally filtered to one company (companyID=="" means all). Most-recently-updated first.

func (*Store) ListOpportunities

func (s *Store) ListOpportunities(ctx context.Context, org, stage string, limit int) ([]Opportunity, error)

ListOpportunities lists the org's opportunities, optionally filtered by stage (stage=="" means all). Most-recently-updated first.

func (*Store) UpdateCompany

func (s *Store) UpdateCompany(ctx context.Context, c Company) (Company, error)

func (*Store) UpdateContact

func (s *Store) UpdateContact(ctx context.Context, c Contact) (Contact, error)

func (*Store) UpdateOpportunity

func (s *Store) UpdateOpportunity(ctx context.Context, o Opportunity) (Opportunity, error)

Jump to

Keyboard shortcuts

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