# nexuscrm-app-packs

Official Salesforce-compatible CRM `L1` product shape and first-party connector
definitions for `NexusCRM`.

## Role

This repository is the source authority for official packs consumed by the
`official_repo:<pack-name>` install/verify contract in `NexusCRM`.

`NexusCRM` itself owns the `L0` runtime/control-plane substrate.
This repository owns the official `L1` pack payloads.
It also owns the Salesforce-compatible CRM dialect Go modules consumed by the
CRM distribution build:

- `dialects/dialect-sf-crm`
- `dialects/dialect-sf-crm-soql`
- `sfcrm/querycodec` — the stdlib-only, independently publishable owner of the
  CRM query language, route, pagination, and response grammar
- `sfcrm/wire` — the stdlib-only, independently publishable owner of reusable
  CRM HTTP error envelopes, error codes, and versioned route messages; the
  transitional dialect consumes it now and independent AppServices can consume
  its published module without importing the legacy dialect

Official connector packs such as `gmail-connected-mail-connector` and
`hubspot-crm-connector` author provider
profiles, handler configuration, capabilities, and route declarations here;
the generic connector runtime remains in the L0 `nexuscrm-connectors` module.

The only non-CRM issue-tracker artifact is the sealed CI fixture under
`tests/conformance/issue-tracker/`. It is not an installable pack, dialect,
frontend, product App, AppService, supported route, image, or deployment.

Phase 2A frontend relocation source manifests also live here so app-owned
frontend source can be supplied by app-packs revision instead of copied into
the platform repository.

The independently runnable CRM record-access AppService lives under
`appservices/sfcrm/`. It is currently a D1 test-stack component: it proves the
real L1 HTTP projection over the neutral Runtime capability but does not own or
receive the production CRM route until a separate atomic cutover is approved.

## Local Usage

Point `NexusCRM` at a checkout of this repository:

```bash
export NEXUSCRM_OFFICIAL_APP_PACKS_ROOT=/abs/path/to/nexuscrm-app-packs
```

Then install or verify the Salesforce-compatible CRM pack from the main repo
with the CRM distribution setup build. This pack declares CRM renderer host
primitives, so CRM pack validation/install must run with the same `crm` build
tag used by the CRM server:

```bash
cd /path/to/NexusCRM/backend
go run -tags crm ./cmd/setup validate-pack --source official_repo:salesforce-crm-standard
go run -tags crm ./cmd/setup install-pack --source official_repo:salesforce-crm-standard
go run -tags crm ./cmd/setup verify-pack salesforce-crm-standard
```

Run the pack-local guardrails before publishing changes:

```bash
npm --prefix frontend ci
npm --prefix frontend run check:frontend-app-package-build
npm --prefix frontend run check:frontend-app-package-build:self-test
python3 scripts/check_object_specs_reserved_fields.py salesforce-crm-standard salesforce-crm-standard-v66
python3 -m unittest discover tests
```

## Rollup maintenance HTTP contract

`POST /services/data/<version>/admin/recalculate-rollups/:object` is fenced to
the server process and app-pack state observed by the operator. The client must:

1. fetch `GET /health` and read `NexusCRM-Serving-Attestation`;
2. send that field value unchanged in
   `NexusCRM-If-Serving-Attestation` on every rollup-maintenance page.

Both fields are RFC 9651 Item Structured Fields. Their bare item must be one
non-empty
[`String`](https://www.rfc-editor.org/rfc/rfc9651#section-3.3.3), and their
parameter section must be empty. The decoded String is opaque to the client.
These are application-specific fields, not representation validators: clients
must not send the value in `If-Match`, and intermediaries that transform or
compress the `/health` representation must not weaken or rewrite the
attestation field. Standard representation-validator fields do not substitute
for or alter this action-specific precondition; if present, they are ignored.

The maintenance route returns `428 Precondition Required` when the request
field is absent, `400 Bad Request` when it is repeated or is not exactly one
valid parameter-free Item carrying a non-empty String, and `412 Precondition
Failed` when the decoded opaque value does not match the current server state.
A `412` means the serving attestation does not identify the process and state
that handled the request. Do not continue the old cursor. Fetch through the
same routing affinity again; if `/health` still returns the same attestation,
the serving process has not converged with the active app-pack state and must be
restarted or allowed to converge. Only after health exposes an attestation that
the mutation accepts may the client restart the object scan from an empty
`afterId`.

The first immutable CRM AppRelease publication and its deterministic builder
live under `releases/io.nexuscrm.sfcrm/` and `tools/crm-app-release/`. The
AppRelease is a content-addressed metadata artifact for Catalog import; it does
not replace generic `pack.json`, authorize an AppInstallation, or create an
AppService/deployment.

For dialect source work, check this repository out under a NexusCRM checkout as
`NexusCRM/nexuscrm-app-packs`; the dialect modules intentionally replace
`github.com/nexuscrm/shared` to `../../../shared` so the platform contract used
by the product build is the same one compiled by NexusCRM CI and Docker:

```bash
cd /path/to/NexusCRM
git clone git@github.com:pingcap-inc/nexuscrm-app-packs.git nexuscrm-app-packs
cd nexuscrm-app-packs/dialects/dialect-sf-crm-soql
GOWORK=off go test ./...
cd ../dialect-sf-crm
GOWORK=off go test ./...
cd ../../sfcrm/querycodec
GOWORK=off go test ./...
cd ../wire
GOWORK=off go test ./...
```

## Layout

- `salesforce-crm-standard/`: current official Salesforce-compatible CRM pack
  and the provisional CRM frontend source home under
  `salesforce-crm-standard/frontend/`
- `salesforce-crm-standard-v66/`: reference/export-oriented CRM pack snapshot
- `gmail-connected-mail-connector/`: secret-free Gmail connected-mail provider
  and mail-delivery callout profile declarations
- `hubspot-crm-connector/`: generic HubSpot CRM connector pack; it declares
  callout profiles, webhook secret metadata, handler configs, and inbound
  routes only
- `dialects/`: source-owned Salesforce CRM product dialect modules
- `sfcrm/querycodec/`: single-owner CRM query codec shared by the transitional
  dialect and the independently runnable AppService
- `sfcrm/scim/`: single-owner SCIM 2.0 grammar and User mapping shared by the
  transitional compatibility surface and the independently runnable AppService
- `sfcrm/wire/`: single-owner reusable CRM HTTP wire codec consumed by the
  transitional dialect and intended for independently runnable AppServices
- `appservices/sfcrm/`: independently runnable CRM record-access projection;
  composes released L0 process and Runtime-client primitives
- `tests/conformance/issue-tracker/`: sealed CI-only non-CRM Runtime contract
  fixture; it is excluded from every product and release surface

Each pack directory is expected to contain its own `pack.json` and payload
tree.

## Rules

- Do not treat `NexusCRM/packs/` as official-pack authority.
- Official packs added here should be consumable through
  `official_repo:<pack-name>`.
- App frontend source under `*/frontend/` is supplied to NexusCRM by app-packs
  source revision. Generated platform artifacts such as `generated-api.ts`,
  `generated-schema.ts`, and `generated-error-codes.ts` must not be copied
  into this repository.
- App frontend source must import platform code only through the public host
  SDK surface declared by the platform repository.
- Tenant field mappings, tenant Flow bodies, tenant outbound sync policies, and
  tenant-named companion packs do not belong in this repository. Source those
  from the tenant overlay/distribution repository instead.
- Install seed intent belongs in L1 app-pack payload, not in NexusCRM L0
  shortcut hooks. The current Salesforce-compatible CRM policy is recorded in
  `salesforce-crm-standard/runbooks/install_seed_policy.md`.
- Do not add new non-product probes or fixtures here. The sealed issue-tracker
  fixture is a narrow serviceification conformance exception, not precedent
  for another product-shaped path and never a candidate for promotion.
