docs(10): capture phase context
This commit is contained in:
parent
25edff0462
commit
98aed06f8f
2 changed files with 238 additions and 0 deletions
163
.planning/phases/10-pax8-client-auth-foundation/10-CONTEXT.md
Normal file
163
.planning/phases/10-pax8-client-auth-foundation/10-CONTEXT.md
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
# Phase 10: PAX8 Client & Auth Foundation - Context
|
||||
|
||||
**Gathered:** 2026-07-10
|
||||
**Status:** Ready for planning
|
||||
|
||||
<domain>
|
||||
## Phase Boundary
|
||||
|
||||
Pulse can authenticate to the PAX8 REST API (`api.pax8.com/v1`) via OAuth2
|
||||
client-credentials, and the Postgres schema for all PAX8 entities exists —
|
||||
companies, subscriptions, product catalog, orders/order-line-items, and a
|
||||
company-match review queue. No sync logic, no company-matching logic, no
|
||||
`/pax8` UI, and no scheduler wiring in this phase — those are Phase 11-14.
|
||||
This phase proves the auth + schema foundation only.
|
||||
|
||||
</domain>
|
||||
|
||||
<decisions>
|
||||
## Implementation Decisions
|
||||
|
||||
### Orders / Invoices Schema
|
||||
- **D-01:** Two-table design — `pax8_orders` (header: order id, company,
|
||||
order date, total, status) + `pax8_order_items` (line-item detail:
|
||||
`order_id` FK, product/SKU, quantity, unit price, line total). Matches
|
||||
PAX8's own order shape (an order has N line items) and avoids repeating
|
||||
order-level fields on every line.
|
||||
- **D-02:** No lookback-window bound. Sync (built in a later phase) pulls
|
||||
full order history PAX8's API returns on first sync — no "earliest
|
||||
synced" or window-config column needed in this phase's migration.
|
||||
- **D-03:** Both `pax8_orders` and `pax8_order_items` carry a `raw_payload
|
||||
JSONB` column alongside typed columns, as a safety net for PAX8 fields
|
||||
not yet modeled. Mirrors the `itglue-search.ts` precedent of not
|
||||
discarding API data even when only a subset is used today.
|
||||
- **D-04:** Monetary amounts use `NUMERIC(12,2)` + a `currency CHAR(3)
|
||||
DEFAULT 'USD'` column on both orders and line items — cheap insurance
|
||||
against a future non-USD client without requiring a schema migration
|
||||
later.
|
||||
|
||||
### Claude's Discretion
|
||||
The user chose to discuss only Orders/Invoices granularity. The following
|
||||
gray areas were surfaced but explicitly left to the planner/executor,
|
||||
default to the closest existing codebase pattern:
|
||||
|
||||
- **Company match/review table shape** — model on `device_link_review`
|
||||
(migration `080_device_xref_company_id.sql`): a conflicts/review queue
|
||||
with candidate match(es), confidence, `resolved_at`/`resolved_by_user_id`/
|
||||
`resolution_note`. Adapt field names for PAX8 companies →
|
||||
Autotask companies instead of device → CI matching. This table is
|
||||
created in this phase's migration but populated by Phase 12's matching
|
||||
logic — schema should anticipate that consumer without over-designing it.
|
||||
- **Product catalog scope** — no explicit decision; planner may choose
|
||||
full-catalog sync or lazy/referenced-only population. This is a Phase
|
||||
11 sync-service decision more than a Phase 10 schema decision — the
|
||||
`pax8_products` table shape should accommodate either without requiring
|
||||
a redesign (e.g., don't add a "referenced only" constraint at the schema
|
||||
level).
|
||||
- **Raw payload retention on other tables** — whether `pax8_companies`,
|
||||
`pax8_subscriptions`, and `pax8_products` also get a `raw_payload`
|
||||
JSONB column. Given D-03 established this pattern for orders, applying
|
||||
it consistently across all four PAX8 tables is a reasonable default
|
||||
unless the planner has a specific reason not to (e.g., a table is fully
|
||||
and confidently typed).
|
||||
|
||||
</decisions>
|
||||
|
||||
<canonical_refs>
|
||||
## Canonical References
|
||||
|
||||
**Downstream agents MUST read these before planning or implementing.**
|
||||
|
||||
### Project scope & requirements
|
||||
- `.planning/PROJECT.md` — Current Milestone: v2.0 PAX8 Integration section;
|
||||
states read-only scope, out-of-scope write access, and the SEED-003
|
||||
future-consumer design note ("build the Postgres schema with that eventual
|
||||
consumer in mind - clean, well-typed tables, avoid PAX8-API-shaped blobs")
|
||||
- `.planning/REQUIREMENTS.md` — PAX8-01, PAX8-02 (this phase's requirement
|
||||
IDs); also PAX8-03..14 for downstream-phase awareness of what this schema
|
||||
must support later
|
||||
- `.planning/seeds/SEED-002-pax8-integration.md` — original exploration:
|
||||
auth breadcrumbs (client ID/secret already provisioned), pattern
|
||||
breadcrumbs (`lib/services/<name>-client.ts` + `<name>-factory.ts`), entity
|
||||
list (companies/subscriptions/catalog/orders), and the "fuzzy name match
|
||||
at sync time, flag ambiguous for manual review" design fork
|
||||
- `.planning/research/questions.md` — `RESEARCH-pax8-company-identifiers`:
|
||||
open question on whether PAX8 exposes a stable identifier (domain,
|
||||
external ID) beyond company name — worth checking PAX8's `companies`
|
||||
endpoint response shape before Phase 12 commits fully to fuzzy name
|
||||
matching. Not blocking for this phase (schema should keep the door open:
|
||||
don't build the match table assuming name is the only comparable field).
|
||||
|
||||
### Existing patterns to follow
|
||||
- `lib/services/msgraph-client.ts` + `lib/services/msgraph-factory.ts` —
|
||||
closest existing OAuth2 client-credentials pattern (token endpoint POST,
|
||||
in-memory token + expiry cache, `is<Name>Configured()` + throw-if-missing).
|
||||
PAX8's auth client should follow this shape, not the Veeam API-key shape.
|
||||
- `lib/services/veeam-factory.ts` — canonical `is<Name>Configured()` +
|
||||
singleton + throw-with-clear-message-if-missing-creds pattern (same shape
|
||||
msgraph-factory.ts follows; both are valid reference points).
|
||||
- `migrations/080_device_xref_company_id.sql` (`device_link_review` table) —
|
||||
reference shape for the PAX8 company-match/review table (see Claude's
|
||||
Discretion above).
|
||||
- `migrations/081_integration_settings.sql` — integration toggle table;
|
||||
PAX8's toggle row is added in Phase 13, not this phase — do not seed it
|
||||
here.
|
||||
- `CLAUDE.md` "External integrations" table — env var prefix convention
|
||||
(`PAX8_*`); add PAX8 to this table and to `INTEGRATIONS.md` once the
|
||||
client exists.
|
||||
|
||||
</canonical_refs>
|
||||
|
||||
<code_context>
|
||||
## Existing Code Insights
|
||||
|
||||
### Reusable Assets
|
||||
- `lib/services/msgraph-client.ts` — direct template for OAuth2
|
||||
client-credentials token exchange (`getToken()` with expiry-aware
|
||||
in-memory caching), including the exact `fetch` + `URLSearchParams` shape
|
||||
to adapt for PAX8's token endpoint.
|
||||
- `lib/services/msgraph-factory.ts` — direct template for
|
||||
`isPax8Configured()` / `getPax8Client()` / `resetPax8Client()`.
|
||||
|
||||
### Established Patterns
|
||||
- Factory + `is<Name>Configured()` + throw-if-missing-creds is used
|
||||
uniformly across all ~15 existing integrations — no deviation expected
|
||||
here.
|
||||
- Migration numbering is sequential regardless of gaps; next number after
|
||||
`090_ticket_reconcile_schedule.sql` is `091`.
|
||||
- Match/review queues for ambiguous cross-system links use a dedicated
|
||||
table (`device_link_review`) rather than a status column on the primary
|
||||
entity table, keeping the "needs human review" concern separate from
|
||||
the synced data itself.
|
||||
|
||||
### Integration Points
|
||||
- New files: `lib/services/pax8-client.ts`, `lib/services/pax8-factory.ts`,
|
||||
`lib/types/pax8.ts` (types barrel, per `lib/types/<domain>.ts` convention),
|
||||
new migration `091_pax8_tables.sql` (or similar name).
|
||||
- No route/nav/UI integration in this phase (`UI hint: no` per ROADMAP.md).
|
||||
|
||||
</code_context>
|
||||
|
||||
<specifics>
|
||||
## Specific Ideas
|
||||
|
||||
No specific UI or behavioral references were given — this phase is schema
|
||||
and client plumbing only. The concrete decisions are the four Orders/
|
||||
Invoices schema points (D-01 through D-04) above.
|
||||
|
||||
</specifics>
|
||||
|
||||
<deferred>
|
||||
## Deferred Ideas
|
||||
|
||||
None — discussion stayed within phase scope. (Company matching logic,
|
||||
product catalog population strategy, the `/pax8` UI, and scheduler wiring
|
||||
are already sequenced into Phases 11-14 per ROADMAP.md and REQUIREMENTS.md
|
||||
— not deferred from this discussion, just out of this phase's boundary.)
|
||||
|
||||
</deferred>
|
||||
|
||||
---
|
||||
|
||||
*Phase: 10-pax8-client-auth-foundation*
|
||||
*Context gathered: 2026-07-10*
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
# Phase 10: PAX8 Client & Auth Foundation - Discussion Log
|
||||
|
||||
> **Audit trail only.** Do not use as input to planning, research, or execution agents.
|
||||
> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
|
||||
|
||||
**Date:** 2026-07-10
|
||||
**Phase:** 10-pax8-client-auth-foundation
|
||||
**Areas discussed:** Orders/invoices granularity
|
||||
|
||||
---
|
||||
|
||||
## Gray areas presented (multiSelect)
|
||||
|
||||
| Area | Description | Selected |
|
||||
|------|-------------|----------|
|
||||
| Match/review table shape | Model on `device_link_review` (candidate array + confidences) vs. simpler single-best-guess + status enum | |
|
||||
| Product catalog scope | Full PAX8 catalog vs. lazily populated from referenced subscriptions only | |
|
||||
| Orders/invoices granularity | Line-item grain with header+items tables vs. flat single table | ✓ |
|
||||
| Raw payload retention | JSONB safety-net column per row vs. fully typed columns only | |
|
||||
|
||||
**User selected:** Orders/invoices granularity only. The other three were left to the planner's discretion (see CONTEXT.md "Claude's Discretion").
|
||||
|
||||
---
|
||||
|
||||
## Orders/Invoices Granularity
|
||||
|
||||
### Q1 — Grain
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Two tables (header + line items) | `pax8_orders` (order id, company, order date, total, status) + `pax8_order_items` (order_id FK, product/SKU, quantity, unit price, line total). Matches PAX8's own order shape. | ✓ |
|
||||
| One flat table | `pax8_order_items` only, order-level fields repeated per line. Simpler queries, no natural home for order status/totals. | |
|
||||
|
||||
**User's choice:** Two tables (header + line items)
|
||||
|
||||
### Q2 — Backfill window
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Full history, no bound | Pull everything on first sync, no lookback-window column needed. | ✓ |
|
||||
| Bounded lookback window | e.g. last 24 months; requires a config value and sync logic to respect it. | |
|
||||
|
||||
**User's choice:** Full history, no bound
|
||||
|
||||
### Q3 — Raw JSON safety net
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Yes, keep raw_payload JSONB | Typed columns for used fields + raw_payload JSONB per row for anything not yet modeled. | ✓ |
|
||||
| No, typed columns only | Fully committed to normalized columns per PROJECT.md's "avoid PAX8-API-shaped blobs" guidance. | |
|
||||
|
||||
**User's choice:** Yes, keep raw_payload JSONB
|
||||
|
||||
### Q4 — Currency handling
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| NUMERIC amount + currency code column | `NUMERIC(12,2)` + `CHAR(3) DEFAULT 'USD'` on orders and line items. | ✓ |
|
||||
| USD-only, no currency column | `NUMERIC(12,2)` only, assume USD everywhere. | |
|
||||
|
||||
**User's choice:** NUMERIC amount + currency code column
|
||||
|
||||
**Notes:** No additional follow-up questions requested — user moved straight to wrap-up after the 4 questions.
|
||||
|
||||
---
|
||||
|
||||
## Claude's Discretion
|
||||
|
||||
- Company match/review table shape — follow `device_link_review` (migration 080) as the closest precedent, adapted for PAX8 company → Autotask company matching.
|
||||
- Product catalog scope (full vs. lazy/referenced-only) — deferred to Phase 11's sync-service design; schema should not preclude either approach.
|
||||
- Raw payload retention on `pax8_companies` / `pax8_subscriptions` / `pax8_products` — reasonable to apply the same JSONB safety-net pattern established for orders (D-03), for consistency, unless the planner has a specific reason not to.
|
||||
|
||||
## Deferred Ideas
|
||||
|
||||
None — discussion stayed within Phase 10's boundary. Company matching logic (Phase 12), product catalog population (Phase 11), the `/pax8` UI (Phase 14), and scheduler wiring (Phase 13) are already sequenced elsewhere in ROADMAP.md/REQUIREMENTS.md.
|
||||
Loading…
Add table
Add a link
Reference in a new issue