Add CRM/support vendors to catalog
## Original requirement (verbatim, epic 13348)
Deep research all third party integrations in Lovable (Connect) and implement all of them.
Ensure the highest level of code reuse, abstract out any generic code across all integrations. Users need an easy way to connect. Documentation must be as detailed as in Lovable or better.
If something needs to be done on the partner website (e.g. register an app) and it can only be done by human create a follow up task per third party with exact step by step of what user needs to do). Mark it as user only task to set up but the runner will validate it was done correctly.
You can refactor anything to make working with creds more robust.
## Settled inputs
Full PRD and architecture: the epic's `prd` and `architecture` artifacts (Task 13348 BA, Task 13349 Architect). Section numbers below refer to them. They are settled: realize them, do not reopen them. Operator decisions O1–O6 and D1–D8 bind.
## This child's scope
Vendor wave W2 (CRM and support), architecture §8 and §9 row "C9 to C18". Vendors: HubSpot (exists), Salesforce, Pipedrive, Zoho CRM, Apollo.io, Clay, Attention, Gong, Zendesk.
Partner OAuth apps in this wave (need a human registration task, filed outside this child): Salesforce, Zoho CRM, Pipedrive, HubSpot, Zendesk.
Zendesk uses a tenant subdomain dialled through `vetted_addresses`.
For EACH vendor: one spec file `apps/api/app/integrations/vendors/<slug>.toml` on the §3.1 schema, a sanitised logo `logos/<slug>.svg`, full `[docs]` prose, a `[test]` (HTTP via HttpTestSpec, or `kind = "format"` only where listed above), `[auth.oauth.registration]` with exact numbered steps for each partner-app vendor, the slug appended to `EXPECTED.txt`, regenerated docs via `tools/integration_docs.py --write`, and one mocked Test unit test per vendor (pass case + a 401 case asserting the "<Vendor> rejected …" sentence).
Confirm each vendor's auth method and Test endpoint from the vendor's OWN docs before writing its file and record the source URL in `vendor_docs_url` (the §8 table is a starting point, not a fact). A vendor already in CREDENTIAL_TYPES sets `credential_type` to the existing slug and changes no existing field (AS3).
Vendors in both an API wave and W1-MCP (Linear, Notion, Granola, n8n, PostHog, Sentry) are ONE file: whichever child lands first writes the full spec and prose; the other adds its block (`[mcp]` or `[[auth]]`) to the same file, never a second slug.
Approach: data files only. If a vendor genuinely needs an engine change, make the smallest generic extension (never a vendor-specific route or React component) and say so in the PR.
Credentials & reach:
- `org/console/dev-login` (generic_login) on https://app.dev.jaah.ai — verified (credential_get succeeded on node shared-a1d14391; HTTPS GET answered 200; the row's own base_url names a retired host, use app.dev.jaah.ai)
- Live Test on dev for every other vendor — deferred: operator answer O6, "Unit tests only"
- OAuth round trip on dev with Jaah-owned apps — deferred: D8 (the human registration tasks' validation sections run it later)
- Unit tests, `./dc check quick`, `tools/check_context.py` — verified (no credential)
Out of scope (PRD §6, verbatim, plus what NOT to touch):
- No app-user connectors (per-end-user OAuth, connector gateway for published apps).
- No "Managed by Jaah" vendor keys or credit billing; no change to `apps/api/app/billing/`.
- No per-vendor API client libraries or MCP tool wrappers built by Jaah (except where the vendor's own hosted MCP server is the connector).
- No Lovable action-approval UI (allow once/always).
- No change to runner auth to model providers (`account_auth.py`, `Account` table) or to login/sign-in OAuth (`routes/login_oauth.py`).
- No change to NodeVault crypto semantics (`credential_crypto.py` encryption tiers) beyond what a refactor needs to keep behaviour identical.
- Do not break existing rows: every existing credential type and every existing row keeps working; migrations additive (two-release overlap rule).
- Supabase/project-backend and git-sync are not new work; Figma plugin/.fig upload out.
- Never write a credential value into a task, doc, log or PR.
- Do NOT file Tasks (no licence): the human-only OAuth registration tasks are filed outside this child.
Done means:
- AC3.1 Every vendor has a live "Test connection" calling a cheap read-only vendor endpoint; result + timestamp shown on the connection. — one tester unit test per vendor in this wave (mocked HTTP against the vendor's real Test endpoint) passes; dev live Test only for O6 roster vendors in this wave (deferred for others — O6).
- AC3.2 A vendor with no safe read-only endpoint is listed in the spec with the chosen alternative (format check) — no vendor silently lacks a test. — the C1 registry test passes with this wave's specs loaded.
- AC2.6 Validation errors are specific (which field, what the vendor answered). — each vendor's 401 unit test shows "<Vendor> rejected the … (401)".
- AC6.1 One reader page per vendor in `apps/docs`, at least Lovable's depth: what it enables for agents, prerequisites, step-by-step connect (OAuth and key paths, with where-to-find-it steps), scopes/permissions requested and why, test, scope (org/project/personal), MCP project linking (MCP vendors), manage/rotate/disconnect, limitations, troubleshooting, FAQ. — `tools/integration_docs.py --check` green for every vendor in this wave AND the reviewer reads two generated pages and confirms the steps name real vendor UI paths (no placeholder text, no "…", no empty section, >=2 troubleshooting entries, every key field has `help`). A page that only passes the headings check fails this child.
- AC2.1 count for this wave — the loaded slugs equal `EXPECTED.txt` (C1 test) and every vendor listed above is in it.
- AC8.1 for this wave: every shipped vendor is visible on dev with no feature flag left off — after merge+deploy, `GET /api/integrations` on app.dev.jaah.ai (signed in with `org/console/dev-login`) lists every slug of this wave, and the gallery shows them once the console gallery child has landed; live key-vendor Test on dev only where an O6 roster key exists (otherwise deferred — O6).
- R7 generator half for this wave: `tools/integration_docs.py --task-body <slug>` prints a complete body (developer-console URL, app name "Jaah", dev+prod redirect URIs, scopes and why, where to paste in the console, "Runner validation" section) for every partner-app vendor listed above; each output is uploaded with `artifact_upload` (`kind: "file"`, name `setup-<slug>.md`) so the human registration tasks can be filed from them by the epic's Finish stage; the report lists the uploaded names.
- AC1.5 `./dc check quick` green and `tools/check_context.py` green on this PR — the gate output cited in the PR body.
Outcome
Resolved merge-lane conflict on PR #7890 (took develop's MCP stored-client read pin, removed duplicate CONSUMERS key); quick gate green, 279 changed-area tests pass; re-queued at 4f0b1f6c5b. Memory: none applied.
Artifacts
- report-13370-rework.html
- report.html
- setup-zoho_crm.md
- setup-pipedrive.md
- setup-salesforce.md
- report.html
- report.html
- setup-pipedrive.md
- setup-zoho_crm.md
- setup-salesforce.md
- report.html
- merge-7883-resolution.patch
- report.html
- setup-salesforce.md
- setup-zoho_crm.md
- setup-pipedrive.md
- setup-salesforce.md
Activity
- Draft
- Ready
- Runner started
- Runner ended (done)
- Run
- Runner started
- Runner ended (done)
- Run
- Runner started
- Runner ended (done)
- Run
- Runner started
- Runner ended (done)
- Run
- Runner started
- Runner ended (done)