|
2 | 2 |
|
3 | 3 | All notable changes to HotCRM are documented in this file. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); HotCRM follows [Semantic Versioning](https://semver.org/). |
4 | 4 |
|
| 5 | +## [2.2.0] — 2026-07-20 |
| 6 | + |
| 7 | +Platform upgrade to ObjectStack **16.0.0-rc.1** — the 16 release-candidate line (from 14.7, skipping the entire 15.x line). Manifest `specVersion` now declares `^16.0.0-rc.1` (was `^14.0.0`); app version `2.2.0`. ObjectStack 16 finishes the ADR-0049 "enforce-or-remove" sweep (dead metadata props now fail loudly instead of parsing inert), converges the hook/action org identifier on `organizationId`, flips `.strict()` on dashboard-widget / view-form / page schemas, and — most consequentially for this app — makes the `ai` capability a **fail-fast hard requirement** resolved to the closed `@objectstack/service-ai` package. Built, validated, type-checked, unit-tested (17/17), and browser-verified against `@objectstack/* 16.0.0-rc.1` (boot → 38 plugins loaded → 17 flows / 15 trigger-bound → `/_console/` login renders at HTTP 200 with no boot or console errors). |
| 8 | + |
| 9 | +Upgrade migration was driven from the official release notes at <https://objectstack.ai/docs/releases/v16> (and `/v15`), cross-checked against the per-package `CHANGELOG.md`, per [`AGENTS.md`](AGENTS.md). |
| 10 | + |
| 11 | +> **Toolchain note:** install under Node **22** (the `.nvmrc` LTS pin). A transitive dep (`nanoid@6`) declares `engines.node` excluding odd-numbered releases, so `pnpm install` fails under Node 25 with `engine-strict=true`. |
| 12 | +
|
| 13 | +### Changed |
| 14 | + |
| 15 | +- **ObjectStack platform → 16.0.0-rc.1** across all 11 `@objectstack/*` packages (from `14.7`), pinned to the exact RC version. |
| 16 | +- **Dropped `ai` from the stack's `requires` ([objectstack.config.ts](objectstack.config.ts)).** ObjectStack 11.3.0 (ADR-0025 S2) removed `@objectstack/service-ai` from the open edition — the AI runtime ships only in the closed cloud package, whose latest open-registry version is `10.3.0`. Under 16, `requires: ['ai']` is a **fail-fast** capability: the serve command hard-aborts boot when the package is absent (the AI block runs before every other capability resolves), so `objectstack start`/`dev` for this open-edition app failed with `[AI] required but @objectstack/service-ai is not installed`. The AI **metadata is unaffected** — both agents + all skills still validate, compile into the artifact, and run wherever a runtime provides the `ai` tier (cloud's `objectos-runtime`). A local open-edition boot simply omits the AI service and hides its Console surface. (This was never caught before because the `verify` script boots nothing — `validate`/`typecheck`/`build`/`test` all resolve metadata only, not capability provider packages.) |
| 17 | +- **Removed the dead `visibility` field from both agents** ([sales-copilot](src/agents/sales-copilot.agent.ts), [service-copilot](src/agents/service-copilot.agent.ts)). ObjectStack 16 removes `AgentSchema.visibility` (ADR-0049 / ADR-0056 D8): it was never enforced — a `private`/`organization` value never restricted an agent — so a security-shaped field with no runtime consumer is a liability. `AgentSchema` is not `.strict()`, so it was being silently stripped; removed for honesty. Restrict agent access via the enforced `access`/`permissions` surfaces instead. |
| 18 | + |
| 19 | +### Fixed |
| 20 | + |
| 21 | +- **Dashboard date-range picker no longer crashes widgets on objects without the date field.** ObjectStack 15 (framework#2501, `GlobalFilterSchema.name` + `DashboardWidgetSchema.filterBindings`) wired dashboard-level filters — including the built-in `dateRange` picker (reserved filter name `dateRange`) — into **every widget's analytics query**. At 14.7 the picker didn't propagate; under 16 it injects its `field` into each widget's SQL. The Executive and CRM dashboards bind `dateRange` to `close_date`, which only exists on `crm_opportunity` — so every widget on `crm_account` / `crm_contact` / `crm_lead` / `crm_product` failed with `SqliteError: no such column: close_date` and rendered as an error card. Each affected widget now declares `filterBindings: { dateRange: false }` to opt out of the picker (they carry their own `created_at` / count semantics): 5 widgets on [executive.dashboard.ts](src/dashboards/executive.dashboard.ts) (`total_accounts`, `total_contacts`, `open_leads`, `new_accounts_by_month`, `accounts_by_industry`) and 1 on [crm.dashboard.ts](src/dashboards/crm.dashboard.ts) (`top_products`). The Sales dashboard (all-`opportunity_metrics`) and Service dashboard (`dateRange` bound to `created_date`, which `crm_case` has) needed no change. Browser-verified: all four dashboards load with live data and zero analytics/SQL errors. (This surfaces only when the dashboards are actually rendered against seeded data — `verify` builds the artifact but never queries it.) |
| 22 | + |
| 23 | +### Removed |
| 24 | + |
| 25 | +- **Dead dashboard header action buttons.** All four dashboards declared header `actions` (Export PDF, Schedule Email, Customize, New Opportunity/Deal/Lead/Case, Forecast, Reports, My Queue, SLA Report) that pointed at actions or routes which were never implemented — `export_dashboard_pdf` / `schedule_dashboard_email` / `customize_dashboard` / `create_opportunity` / `create_lead` / `create_case` are not defined actions, and the `url` targets (`/reports/forecast`, `/reports/sla`, `/reports`, `/objects/case?owner=current_user`) match no in-app view route. They rendered as buttons that did nothing when clicked. Removed the `header.actions` block from [executive](src/dashboards/executive.dashboard.ts), [sales](src/dashboards/sales.dashboard.ts), [crm](src/dashboards/crm.dashboard.ts), and [service](src/dashboards/service.dashboard.ts) dashboards (titles/descriptions kept), plus the now-orphaned action-label translations from all four locale bundles (`en`, `zh-CN`, `ja-JP`, `es-ES`). Pre-existing dead affordance, unrelated to the upgrade; re-add real, wired-up actions when those features exist. |
| 26 | + |
| 27 | +### Verified clean (no change needed) |
| 28 | + |
| 29 | +The rest of the 15→16 enforce-or-remove surface did not touch this app, confirmed by source scan + a clean build: |
| 30 | + |
| 31 | +- **Hook/action `ctx.session.tenantId` → `organizationId`** — no `tenantId` reads anywhere. |
| 32 | +- **Removed object props** (`versioning`/`softDelete`/`search`/`recordName`/`keyPrefix`/`tags`/`active`/`abstract`) and **field props** (`vectorConfig`/`fileAttachmentConfig`/`dependencies`/`columnName`/`index`/`referenceFilters`) — none authored (only historical comments). |
| 33 | +- **Dashboard-widget `.strict()`** — the pivot's `rowField`/`columnField`/`valueField` live inside the `options: {}` escape hatch; widgets use the canonical `dataset`/`dimensions`/`values` shape. |
| 34 | +- **Collapsed hook events** (18 → 8), **validation `events: ['delete']`**, **webhook `undelete`/`api` triggers**, **`aiStudio`/`aiSeat` capability aliases**, **feed contracts**, **formula date arithmetic** (now a build error), **`managedBy: 'system'` data-API lockdown**, **`ObjectOS*` → `Kernel*` class renames**, and the **tenancy config** removal — none present. |
| 35 | +- **Approver types** already use the canonical `type: 'position'` (migrated in 2.1.0), not the now-removed `role` alias. |
| 36 | + |
5 | 37 | ## [2.1.0] — 2026-07-14 |
6 | 38 |
|
7 | 39 | Platform upgrade to ObjectStack **14.7** — a major line bump (from 12/13). Manifest `specVersion` now declares `^14.0.0` (was `^12.0.0`); app version `2.1.0`. ObjectStack 14 completes the ADR-0090 permission-model vocabulary convergence and turns the object `enable.*` capability flags into real runtime gates. This release migrates HotCRM's metadata off every 14.0 breaking surface and hardens the seed + opportunity-lifecycle hook so a fresh-DB boot is completely clean. Built, validated, type-checked, linted (zero warnings), unit-tested (17/17), and browser-verified against `@objectstack/* ^14.7.0` (login → HotCRM app → Executive / Sales / Service / CRM Overview dashboards with live seeded data → Accounts / Opportunities / Cases lists → account record detail with grouped field sections; no boot errors, no post-login console errors). |
|
0 commit comments