Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,38 @@

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/).

## [2.2.0] — 2026-07-20

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

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

> **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`.

### Changed

- **ObjectStack platform → 16.0.0-rc.1** across all 11 `@objectstack/*` packages (from `14.7`), pinned to the exact RC version.
- **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.)
- **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.

### Fixed

- **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.)

### Removed

- **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.

### Verified clean (no change needed)

The rest of the 15→16 enforce-or-remove surface did not touch this app, confirmed by source scan + a clean build:

- **Hook/action `ctx.session.tenantId` → `organizationId`** — no `tenantId` reads anywhere.
- **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).
- **Dashboard-widget `.strict()`** — the pivot's `rowField`/`columnField`/`valueField` live inside the `options: {}` escape hatch; widgets use the canonical `dataset`/`dimensions`/`values` shape.
- **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.
- **Approver types** already use the canonical `type: 'position'` (migrated in 2.1.0), not the now-removed `role` alias.

## [2.1.0] — 2026-07-14

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).
Expand Down
17 changes: 15 additions & 2 deletions objectstack.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default defineStack({
manifest: {
id: 'app.objectstack.hotcrm',
namespace: 'crm',
version: '2.1.0',
version: '2.2.0',
type: 'app',
name: 'HotCRM',
description: 'AI-Native CRM for the ObjectStack marketplace — Accounts, Contacts, Leads, Opportunities, Cases, Knowledge, Forecasts, Campaigns, Contracts.',
Expand All @@ -58,7 +58,20 @@ export default defineStack({
// actually fire autolaunched flows (record_change & schedule types). Without
// it the `automation` engine registers flows but nothing ever launches them.
// Schedule triggers run via the job service (in the always-on slate).
requires: ['ai', 'automation', 'triggers', 'analytics', 'auth', 'ui', 'approvals', 'sharing'],
//
// `ai` is deliberately NOT listed. ObjectStack 11.3.0 (ADR-0025 S2) removed
// `@objectstack/service-ai` from the open edition — the AI runtime now ships
// only in the closed cloud package, and the framework CLI does not depend on
// it. Under ObjectStack 16, `requires: ['ai']` is a *fail-fast* capability:
// the serve command hard-aborts boot when the package is absent, so keeping it
// here would break `objectstack start`/`dev` for this open-edition app (the AI
// block runs before every other capability resolves). The AI metadata is
// unaffected — the two agents + skills still validate, build 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. To run AI locally, declare `@objectstack/service-ai` (cloud) in
// package.json — its mere presence best-effort auto-loads it.
requires: ['automation', 'triggers', 'analytics', 'auth', 'ui', 'approvals', 'sharing'],

objects: Object.values(objects),
actions: Object.values(actions),
Expand Down
2 changes: 1 addition & 1 deletion objectstack.manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://schemas.objectstack.dev/template-manifest.json",
"name": "hotcrm",
"specVersion": "^14.0.0",
"specVersion": "^16.0.0-rc.1",
"manifestId": "app.objectstack.hotcrm",
"displayName": "HotCRM",
"description": "AI-Native CRM for the ObjectStack marketplace — Accounts, Contacts, Leads, Opportunities, Cases, Knowledge, Forecasts, Campaigns, and Contracts in one production-grade workspace.",
Expand Down
24 changes: 12 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hotcrm",
"version": "2.1.0",
"version": "2.2.0",
"description": "HotCRM - Production CRM built on ObjectStack",
"private": true,
"main": "./objectstack.config.ts",
Expand All @@ -26,17 +26,17 @@
},
"packageManager": "pnpm@10.33.0",
"dependencies": {
"@objectstack/account": "^14.7.0",
"@objectstack/cli": "^14.7.0",
"@objectstack/driver-memory": "^14.7.0",
"@objectstack/driver-sql": "^14.7.0",
"@objectstack/driver-sqlite-wasm": "^14.7.0",
"@objectstack/metadata": "^14.7.0",
"@objectstack/objectql": "^14.7.0",
"@objectstack/runtime": "^14.7.0",
"@objectstack/service-analytics": "^14.7.0",
"@objectstack/service-automation": "^14.7.0",
"@objectstack/spec": "^14.7.0"
"@objectstack/account": "16.0.0-rc.1",
"@objectstack/cli": "16.0.0-rc.1",
"@objectstack/driver-memory": "16.0.0-rc.1",
"@objectstack/driver-sql": "16.0.0-rc.1",
"@objectstack/driver-sqlite-wasm": "16.0.0-rc.1",
"@objectstack/metadata": "16.0.0-rc.1",
"@objectstack/objectql": "16.0.0-rc.1",
"@objectstack/runtime": "16.0.0-rc.1",
"@objectstack/service-analytics": "16.0.0-rc.1",
"@objectstack/service-automation": "16.0.0-rc.1",
"@objectstack/spec": "16.0.0-rc.1"
},
"optionalDependencies": {
"better-sqlite3": "^12.11.1"
Expand Down
Loading
Loading