Documentation
¶
Overview ¶
Package ads mounts the Hanzo Cloud /v1/ads/* surface: a native-Go, per-org ad-campaign store on Base/SQLite. It is the NET-NEW ads domain built directly on the ONE cloud framework (zip/Fiber + cloud.Deps + per-org SQLite) — the same shape every other in-repo subsystem uses (clients/crm and clients/marketing are the twins), NOT a proxy to a standalone ads pod (there is none — ads.hanzo.ai is net-new).
The Campaign entity is the root of the ad hierarchy (campaign → ad sets → ads): a named campaign on an ad Platform (meta/google/tiktok/x), a lifecycle Status (draft/active/paused/completed), an Objective, and Budget/Spend in minor units (cents). The ad-set and ad legs of the hierarchy are follow-ups that hang off this seam; this is the reviewable domain + campaign CRUD they attach to.
Tenant isolation is enforced SERVER-SIDE on every request: the org is principal.Org(c) — 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/ads/summary per-org roll-up (total/active/budget/spend)
GET /v1/ads/campaigns list campaigns (?status=) -> {data:[…]}
POST /v1/ads/campaigns create a campaign -> Campaign (201)
GET /v1/ads/campaigns/:id campaign detail -> Campaign
PUT /v1/ads/campaigns/:id update a campaign -> Campaign
DELETE /v1/ads/campaigns/:id delete a campaign
serve.go auto-registers GET /v1/ads/health (this subsystem does not set OwnsHealth, so the generic always-ok liveness route serves it).
Index ¶
- func Mount(app *zip.App, deps cloud.Deps) error
- func Shutdown() error
- type Campaign
- type Store
- func (s *Store) Close() error
- func (s *Store) Counts(ctx context.Context, org string) (total, active int, budget, spend int64, err error)
- func (s *Store) CreateCampaign(ctx context.Context, c Campaign) (Campaign, error)
- func (s *Store) DeleteCampaign(ctx context.Context, org, id string) (bool, error)
- func (s *Store) GetCampaign(ctx context.Context, org, id string) (Campaign, error)
- func (s *Store) ListCampaigns(ctx context.Context, org, status string, limit int) ([]Campaign, error)
- func (s *Store) UpdateCampaign(ctx context.Context, c Campaign) (Campaign, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Campaign ¶
type Campaign struct {
ID string `json:"id"`
Org string `json:"-"`
Name string `json:"name"`
Platform string `json:"platform"`
Status string `json:"status"`
Objective string `json:"objective"`
Budget int64 `json:"budget"`
Spend int64 `json:"spend"`
CreatedAt int64 `json:"createdAt"`
UpdatedAt int64 `json:"updatedAt"`
}
Campaign is an org-scoped ad campaign — the root of the ad hierarchy (campaign → ad sets → ads; the ad-set/ad legs hang off this seam as follow-ups). Budget and Spend are minor units (cents). Platform is the ad network (meta/google/tiktok/x); Status is the lifecycle (draft/active/paused/completed) — both validated at the write layer against the fixed vocabularies in ads.go.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is the ads database. ONE SQLite file ({DataDir}/ads.db) holds every org's records; tenant isolation is the `org` column, enforced on EVERY query. This mirrors clients/crm exactly (the ONE storage pattern). MaxOpenConns(1) serializes writes against the single-writer file.
func (*Store) Counts ¶
func (s *Store) Counts(ctx context.Context, org string) (total, active int, budget, spend int64, err error)
Counts returns the per-org campaign roll-up: total campaigns, how many are active, and the summed budget + spend (cents) — a real, non-fabricated summary for the ads module's overview cards.