docs: capture exploration — PAX8 integration scope
Plant two seeds (PAX8 sync + Autotask mapping, general Pulse data assistant) and one research question (PAX8 company identifier alternatives to fuzzy name matching), surfaced while scoping a future PAX8 integration.
This commit is contained in:
parent
758b7e7f15
commit
4f7e9be059
5 changed files with 197 additions and 0 deletions
20
.planning/research/questions.md
Normal file
20
.planning/research/questions.md
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Research Questions
|
||||||
|
|
||||||
|
Open questions surfaced during exploration, not yet investigated. Pull into the
|
||||||
|
relevant phase's research step when picked up.
|
||||||
|
|
||||||
|
## RESEARCH-pax8-company-identifiers
|
||||||
|
|
||||||
|
**Raised:** 2026-07-10, during exploration of [[SEED-002]] (PAX8 Integration)
|
||||||
|
|
||||||
|
**Question:** Does the PAX8 API expose a stable identifier for companies beyond
|
||||||
|
name — a domain, external/tenant ID, or similar — that could serve as a more
|
||||||
|
reliable join key to Autotask companies than fuzzy name matching?
|
||||||
|
|
||||||
|
**Why it matters:** The PAX8 integration scope defaulted to "fuzzy name match at
|
||||||
|
sync time, flag unmatched/ambiguous for manual review" for mapping PAX8
|
||||||
|
companies to Autotask companies. That's a reasonable starting point, but if the
|
||||||
|
API exposes something like a primary domain, it would be materially more
|
||||||
|
reliable and worth using instead (or as a tiebreaker for ambiguous name
|
||||||
|
matches). Check the PAX8 API docs (`companies` endpoint) before committing to
|
||||||
|
fuzzy-name as the permanent strategy.
|
||||||
92
.planning/seeds/SEED-002-pax8-integration.md
Normal file
92
.planning/seeds/SEED-002-pax8-integration.md
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
---
|
||||||
|
id: SEED-002
|
||||||
|
status: dormant
|
||||||
|
planted: 2026-07-10
|
||||||
|
planted_during: v1.0 milestone (Pulse Mobile Shell Redesign), Phase 9.1 in flight
|
||||||
|
trigger_when: Whenever the developer is ready to start this as its own milestone — surface during the next /gsd-new-milestone scan
|
||||||
|
scope: Medium
|
||||||
|
---
|
||||||
|
|
||||||
|
# SEED-002: PAX8 Integration
|
||||||
|
|
||||||
|
A read-only integration syncing PAX8 (vendor licensing/distribution marketplace)
|
||||||
|
data into Pulse — companies, subscriptions, product catalog, and orders/invoices —
|
||||||
|
mapped to existing Autotask companies, surfaced on a new `/pax8` page.
|
||||||
|
|
||||||
|
## Why This Matters
|
||||||
|
|
||||||
|
Three overlapping needs, all satisfied by the same underlying data sync:
|
||||||
|
1. **Cost reconciliation** — compare what PAX8 bills per client/subscription
|
||||||
|
against what's actually provisioned or invoiced.
|
||||||
|
2. **License visibility** — see subscription/seat counts per company alongside
|
||||||
|
other Pulse company data.
|
||||||
|
3. **Autotask cost mapping** — tie PAX8 companies and subscription costs to
|
||||||
|
Autotask companies/contracts for margin/profitability reporting.
|
||||||
|
|
||||||
|
The developer already has a PAX8 client ID + client secret provisioned, so auth
|
||||||
|
setup is not a blocker — this seed is purely about scope/sequencing, not
|
||||||
|
credential access.
|
||||||
|
|
||||||
|
## When to Surface
|
||||||
|
|
||||||
|
**Trigger:** Whenever the developer wants to start this — not gated on any other
|
||||||
|
milestone closing, but naturally lands after the current Mobile Shell Redesign
|
||||||
|
wraps. Also surface if a future milestone's scope mentions: "PAX8", "license
|
||||||
|
reconciliation", "vendor subscription costs", "seat count audit", or "Autotask
|
||||||
|
contract margin".
|
||||||
|
|
||||||
|
## Scope Estimate
|
||||||
|
|
||||||
|
**Medium** — roughly 2–4 phases. New external client integration (auth, 4
|
||||||
|
entities), a sync service, a new migration, a company-matching pass with manual
|
||||||
|
review for exceptions, and one new UI page. Follows an existing, well-worn
|
||||||
|
pattern in this codebase (autotask-factory, veeam-sync-service, etc.) — no new
|
||||||
|
architectural concepts, just new surface area.
|
||||||
|
|
||||||
|
## Breadcrumbs
|
||||||
|
|
||||||
|
- Auth: PAX8 REST API at `https://api.pax8.com/v1`, OAuth2 client-credentials.
|
||||||
|
Client ID + secret already provisioned by the developer.
|
||||||
|
- Pattern to follow: `lib/services/<name>-client.ts` + `<name>-factory.ts`
|
||||||
|
(`is<Name>Configured()`) — see `lib/services/veeam-client.ts` /
|
||||||
|
`veeam-factory.ts` or `lib/services/msgraph-client.ts` / `msgraph-factory.ts`
|
||||||
|
for the shape.
|
||||||
|
- Sync pattern: `lib/services/entity-sync.ts` (Autotask) and
|
||||||
|
`lib/services/engagement-sync-service.ts` — incremental-if-supported, else
|
||||||
|
full upsert via `postgresClient.bulkUpsert()`.
|
||||||
|
- Env vars: `PAX8_*` (add to the integrations table in `CLAUDE.md` /
|
||||||
|
`INTEGRATIONS.md` once built).
|
||||||
|
- Scheduler: new `pax8-daily` schedule via `lib/services/sync-scheduler.ts`,
|
||||||
|
matching cadence of other integrations (see `engagement-daily`).
|
||||||
|
- Admin disable: wire into `/admin/integrations` (`integration_settings` table,
|
||||||
|
migration 081) like other integrations, so it can be toggled without a
|
||||||
|
container restart.
|
||||||
|
- UI: new top-level page (like `/engagement`) — company list, subscriptions,
|
||||||
|
cost breakdown. Not folded into the existing company detail modal.
|
||||||
|
- This is explicitly the first planned data source for [[SEED-003]] (General
|
||||||
|
Pulse Data Assistant) — build the Postgres schema with that eventual consumer
|
||||||
|
in mind (clean, well-typed tables; avoid PAX8-API-shaped blobs).
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
### Entities in scope (v1)
|
||||||
|
- Companies (join key to Autotask companies)
|
||||||
|
- Subscriptions (product, seat count, billing term — current state)
|
||||||
|
- Products/Catalog (SKUs, categories — needed to make subscriptions readable)
|
||||||
|
- Orders/Invoices (historical line items — needed for actual cost reconciliation,
|
||||||
|
not just current-state seats)
|
||||||
|
|
||||||
|
### Key design forks (decided during exploration)
|
||||||
|
- **Read-only** — no write-back to PAX8 (no seat adjustments, no orders) in v1.
|
||||||
|
- **Company matching: fuzzy name match at sync time** — auto-match by name
|
||||||
|
similarity, flag unmatched/ambiguous companies for manual review. See
|
||||||
|
[[RESEARCH-pax8-company-identifiers]] — worth checking whether PAX8 exposes a
|
||||||
|
more stable identifier (domain, external ID) before committing to fuzzy
|
||||||
|
matching as the permanent strategy.
|
||||||
|
- **New dedicated `/pax8` page**, not folded into company detail — daily sync
|
||||||
|
via the scheduler, not on-demand-only.
|
||||||
|
|
||||||
|
### Anti-goals
|
||||||
|
- Not building write access (seat changes, placing orders) in v1.
|
||||||
|
- Not building the chatbot/NL query layer here — that's [[SEED-003]], a
|
||||||
|
separate initiative that consumes this data once it exists.
|
||||||
85
.planning/seeds/SEED-003-general-pulse-data-assistant.md
Normal file
85
.planning/seeds/SEED-003-general-pulse-data-assistant.md
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
---
|
||||||
|
id: SEED-003
|
||||||
|
status: dormant
|
||||||
|
planted: 2026-07-10
|
||||||
|
planted_during: v1.0 milestone (Pulse Mobile Shell Redesign), Phase 9.1 in flight
|
||||||
|
trigger_when: After PAX8 (SEED-002) and ideally other core data sources are mirrored into Postgres — surface during the next /gsd-new-milestone scan
|
||||||
|
scope: Large
|
||||||
|
---
|
||||||
|
|
||||||
|
# SEED-003: General Pulse Data Assistant
|
||||||
|
|
||||||
|
A natural-language chatbot interface over Pulse's own data generally — tickets,
|
||||||
|
companies, engagement, finance, and PAX8 once it exists — not scoped to any
|
||||||
|
single integration.
|
||||||
|
|
||||||
|
## Why This Matters
|
||||||
|
|
||||||
|
Surfaced while scoping [[SEED-002]] (PAX8 integration): the developer wants
|
||||||
|
"the ability to ask questions through a chatbot style interface" as one of the
|
||||||
|
motivations for pulling PAX8 data in, but on reflection the real want is broader
|
||||||
|
than PAX8 — a general assistant that happens to need PAX8 (and other sources)
|
||||||
|
as data it can draw on, not a PAX8-specific bot.
|
||||||
|
|
||||||
|
This is a meaningfully different initiative from any single data integration:
|
||||||
|
it needs a query/tool-calling layer that can span multiple Postgres tables
|
||||||
|
safely, decide what's answerable, and present results — not just sync data
|
||||||
|
into a table.
|
||||||
|
|
||||||
|
## When to Surface
|
||||||
|
|
||||||
|
**Trigger:** After PAX8 data (SEED-002) — and ideally other core sources
|
||||||
|
(tickets, engagement, finance) — are mirrored into Postgres and stable. Also
|
||||||
|
surface if a future milestone's scope mentions: "chatbot", "natural language
|
||||||
|
query", "ask Pulse", "data assistant", or "LLM interface over dashboard data".
|
||||||
|
|
||||||
|
## Scope Estimate
|
||||||
|
|
||||||
|
**Large** — likely its own multi-phase milestone. Needs: query/tool-calling
|
||||||
|
architecture (what can the LLM call — raw SQL? scoped read helpers per domain?),
|
||||||
|
guardrails against unsafe/expensive queries, a chat UI surface (new page, or a
|
||||||
|
persistent widget across pages?), conversation state/history, and an answer
|
||||||
|
format that handles tabular results well (not just prose).
|
||||||
|
|
||||||
|
## Breadcrumbs
|
||||||
|
|
||||||
|
- Existing LLM plumbing to reuse rather than rebuild: `@anthropic-ai/sdk`
|
||||||
|
already wired for the AI Ticket Analyzer pipeline
|
||||||
|
(`lib/services/analyzer/pipeline.ts`, `lib/services/analyzer/stages/*.ts`),
|
||||||
|
plus `ai-triage-service.ts`. Provider is per-request (`anthropic` |
|
||||||
|
`openrouter`) — same pattern likely applies here.
|
||||||
|
- Analyzer's cost-ceiling guard (Stage 4 skipped above $2.00 estimated cost) is
|
||||||
|
a pattern worth mirroring for a chat interface that could otherwise run
|
||||||
|
unbounded queries/tokens per question.
|
||||||
|
- IT Glue data has a hard redaction requirement before hitting an LLM
|
||||||
|
(`lib/services/analyzer/itglue-search.ts`) — any assistant that can see IT
|
||||||
|
Glue-sourced data must route through the same redaction, not raw client
|
||||||
|
output.
|
||||||
|
- `postgresClient` singleton (`lib/services/postgres-client.ts`) is the only
|
||||||
|
DB access path — any tool-calling layer built for this assistant should call
|
||||||
|
through it, not open a second connection path.
|
||||||
|
- Data sources this assistant should eventually reach: tickets (Autotask sync),
|
||||||
|
companies, engagement snapshots (`engagement_snapshots`), finance/QBO data,
|
||||||
|
and PAX8 once [[SEED-002]] lands.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
### Key design forks (decide during brainstorming, not now)
|
||||||
|
- **Tool-calling over scoped read helpers vs. raw SQL generation** — raw
|
||||||
|
text-to-SQL is riskier (injection, runaway queries, schema drift); scoped
|
||||||
|
helpers per domain (e.g. `getCompanySubscriptionCosts(companyId)`) are safer
|
||||||
|
but need maintenance as new questions come up. Current lean: scoped helpers,
|
||||||
|
mirroring the analyzer's structured-stage-output philosophy.
|
||||||
|
- **Where it surfaces** — dedicated page vs. a persistent chat widget
|
||||||
|
available across desktop and mobile. Not decided.
|
||||||
|
- **Read-only vs. can it trigger actions** — e.g. could it kick off a sync, or
|
||||||
|
strictly answer questions? Current lean: read-only, at least for v1.
|
||||||
|
- **Conversation memory** — single-turn Q&A vs. multi-turn session with
|
||||||
|
history. Affects whether this needs new schema (a `chat_sessions` /
|
||||||
|
`chat_messages` table) beyond the query layer itself.
|
||||||
|
|
||||||
|
### Anti-goals
|
||||||
|
- Not a replacement for the existing dashboards/pages — a supplement for
|
||||||
|
ad-hoc questions those views don't answer directly.
|
||||||
|
- Not scoped to any single integration (started life as a "PAX8 chatbot" idea,
|
||||||
|
deliberately broadened).
|
||||||
Loading…
Add table
Add a link
Reference in a new issue