Imports were migrated to @hanzoai/tasks in social#2; these were the last
documentation-comment references to the retired Temporal brand tokens.
Reworded to the equivalent generic phrasing (legacy client shape,
durable-execution NestJS module, proxyActivities API) — meaning unchanged,
comment-only, compile-neutral. social now has zero go.temporal.io /
@temporalio / nestjs-temporal-core references.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
Replace @temporalio/* + nestjs-temporal-core with @hanzoai/tasks. Durable
workflow execution now runs on the ONE Hanzo Tasks engine embedded in cloud,
reached over its identity-gated ZAP listener (cloud.hanzo.svc:9999) and
authenticated with a Hanzo IAM client_credentials bearer (owner-scoped). No
upstream Temporal anywhere.
- libraries/.../temporal/tasks.ts: @hanzoai/tasks-backed NestJS integration —
@Activity/@ActivityMethod decorators, TemporalService facade
(client.getRawClient()/getWorkflowHandle(), terminateWorkflow()), IAM
client_credentials token source, getTemporalModule(). Connects a Client +
one Worker per task queue (main + per social integration), RegisterNamespace
on init.
- temporal.module.ts re-exports getTemporalModule; temporal.register.ts is a
no-op (search attrs need no pre-registration on Hanzo Tasks);
infinite.workflow.register.ts + health.controller.ts use @hanzoai/tasks;
backend main.ts drops the Temporal worker Runtime.install.
- temporal/workflow.ts: workflow-side barrel re-exporting @hanzoai/tasks with a
drop-in proxyActivities (unconstrained generic + cancellationType superset)
so proxyActivities<ActivityClass>() type-checks as it did under @temporalio.
- All 11 workflows + 4 activity classes + 2 signals ported; uses proxyActivities,
sleep, condition, defineSignal/setHandler (signal-to-running-wf), continueAsNew
(digest/sendEmail), startChild (post repeat), typed search attributes,
workflowIdConflictPolicy.
- @hanzoai/tasks vendored as a tarball (file: dep); TEMPORAL_ADDRESS scrubbed,
new TASKS_ADDRESS default cloud.hanzo.svc:9999 / TASKS_NAMESPACE default.
Orchestrator + backend build green (nest build, full typecheck).
slim images lack the openssl CLI; Prisma's platform detection guessed
openssl-1.1.x at runtime and the orchestrator boot-looped on a missing
query engine.
When a user signs in with Hanzo IAM for the first time, Postiz
auto-creates an Organization (per upstream auth.service.ts pattern).
We now rename that Organization to match the IAM `owner` claim (the
IAM org slug) so subsequent sign-ins from the same IAM org land in
the same Postiz Organization and the team membership grows organically.
Wiring:
- organization.repository.ts: add updateOrgName(orgId, name) — direct
Prisma update of organization.name.
- organization.service.ts: pass-through updateOrgName.
- hanzo-iam.provider.ts: inject OrganizationService in constructor;
implement postRegistration(providerToken, orgId) that GETs
${IAM_URL}/oauth/userinfo, extracts `owner` (fallback to
`preferred_username`), and calls updateOrgName.
postRegistration errors are silently swallowed (auth.service does the
same wrap) so registration never fails on federation glitches; user
just keeps the form-supplied company name.
Known limitation: "first writer wins" — two new users from the same
IAM org racing through registration both get separate Postiz orgs
named with the same slug. Merging duplicates + moving memberships is
a follow-up hardening task (not currently tracked).
Adds HanzoBillingService — a Postiz-shaped wrapper around
commerce.hanzo.ai/v1/billing/* that mirrors StripeService's public
method shape so billing.controller.ts injects unchanged.
Core flows wired against commerce.hanzo.ai:
- subscribe() → POST /v1/billing/subscriptions
- cancelSubscription() → POST /v1/billing/subscriptions/{id}/cancel
- setToCancel() → PATCH /v1/billing/subscriptions/{id} {cancelAtPeriodEnd:true}
- checkSubscription() → GET /v1/billing/subscriptions/{id}
- createBillingPortalLink() → https://billing.hanzo.ai (IAM-session portal)
- getCharges() → GET /v1/billing/transactions
- getPackages() → @hanzo/plans social-* tiers (no API hop)
- getCustomerByOrganizationId → IAM sub from org.paymentId
Legacy Postiz tier names map to Hanzo plan slugs (same table as pricing.ts):
FREE → social-free, STANDARD → social-pro, TEAM → social-team,
PRO → social-team-max, ULTIMATE → social-enterprise.
Discount surface (checkDiscount/applyDiscount/finishTrial) returns
no-op — Hanzo billing manages eligibility centrally via the portal.
Deferred (throws NotImplementedException — explicit follow-up):
- embedded payment form (Square Web SDK token flow needed on FE)
- lifetimeDeal (no lifetime SKU on commerce.hanzo.ai)
- prorate (mid-cycle credit math)
- refundCharges (refund API still being designed)
Webhook validateRequest/createSubscription/updateSubscription return
no-ops — commerce.hanzo.ai uses its own HMAC-signed webhook flow, not
Stripe's. Wiring the new webhook handler is tracked separately.
Module wiring: api.module.ts feature-flags { provide: StripeService,
useClass: HANZO_BILLING_ENABLED ? HanzoBillingService : StripeService }
so existing controllers keep injecting `StripeService` by token; the
actual class is swapped at boot. Per-class type laundered through
`as unknown as typeof StripeService` because the two classes share a
duck-typed interface but not a declared one — fixing properly = extract
an IBillingService interface (tracked).
Replaces the upstream Postiz hardcoded pricing tiers
(FREE/STANDARD/TEAM/PRO/ULTIMATE) with a runtime adapter over the
canonical @hanzo/plans social-* tiers.
Mapping:
- FREE → social-free ($0)
- STANDARD → social-pro ($29)
- TEAM → social-team ($39)
- PRO → social-team-max ($49)
- ULTIMATE → social-enterprise ($99)
Why @hanzo/plans (synchronous package import) rather than a runtime
fetch to pricing.hanzo.ai: the existing consumers (subscription.service,
permissions.service, integrations.controller, users.controller,
public.controller, impersonate.tsx) access pricing.FREE/PRO/etc.
synchronously at module scope. An async fetch would force every
consumer to await or initialize-once-then-throw-if-stale. The package
import gives us the same source of truth (pricing.hanzo.ai reads the
same JSON from @hanzo/plans) without a network dependency.
Adds @hanzo/plans@^1.1.2 to root package.json — pnpm install will
resolve it from the public npm registry on next build.
PricingInnerInterface shape preserved verbatim; downstream code
unchanged.