Commit graph

5 commits

Author SHA1 Message Date
jmcqueen
fa06538aa4 Workaround #1: cache Assets store lookups via personal PAT sync
The service account is silently filtered out of Object Type 109 (Store
Address / Hierarchy) despite having schema-level read on schema 68, so
every AQL against the store type returns total=0. Until that permission
is granted, resolve store numbers from a local cache populated by a
personal PAT (different auth path, different account, has the role).

- new: src/services/jira/assetsSyncClient.js — Basic-auth axios against
  api.atlassian.com/jsm/assets/workspace/{ws}/v1, credentials sourced
  from ASSETS_SYNC_EMAIL / ASSETS_SYNC_TOKEN (loaded from Keychain by
  bin/load-assets-sync-secret.sh so the PAT never touches .env)
- new: src/services/jira/storesCache.js — in-memory Map + on-disk JSON
  at data/stores.json (gitignored), atomic write, paginated full sync
  via AQL (objectTypeId=N), boot-time load + background refresh if
  stale, periodic setInterval every STORES_CACHE_REFRESH_HOURS
- new: bin/load-assets-sync-secret.sh — Keychain -> env var wrapper
  (security find-generic-password -s jira-assets-sync -a <email>)
- change: resolveStoreAssetReference now tries cache -> live PAT -> the
  existing service-account AQL, in that order; the fallback path is
  preserved so this cleanly deactivates once the permission on #1 is
  fixed. Error message names all three routes and points at the refresh
  endpoint.
- new admin routes: GET /api/wxccai/admin/storesCache/status,
  POST /api/wxccai/admin/storesCache/refresh
- app.js kicks off storesCache.init() after listen()
- config: STORES_CACHE_ENABLED / _PATH / _REFRESH_HOURS /
  _STALE_AFTER_HOURS / _PAGE_SIZE / _MAX_PAGES, plus intFromEnv /
  boolFromEnv helpers
- .gitignore adds data/; .env.example documents the new vars; README
  adds an "Admin" endpoints section and a "Stores cache" setup guide

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 10:18:28 -04:00
jmcqueen
b8f2eab4ab Refactor #6: split jiraService.js into services/jira/{client,issues,comments,attachments,jsmRequests,assets}
Pure move + one-way rewire, no logic changes. The old 1467-line
monolithic services/jiraService.js becomes a thin barrel that re-exports
the same public surface so both current consumers keep working unchanged:
  - src/routes/wxccRoutes.js: `import * as jiraService`
  - src/services/healthService.js: `import { jiraClient }`

New module layout (deps flow one-way, no cycles):
  client.js       — jiraClient, downloadClient, plainTextToAdf (foundational)
  issues.js       — fetch/search/status/update/transitions/close
  comments.js     — fetchPublicComments, addComment, postWebexSummaryComment
  attachments.js  — attachFileToJira, attachReadableTranscript
  assets.js       — AQL, resolveStoreAssetReference, probeAssetsForStore
  jsmRequests.js  — REQUEST_TYPE_MAP, createSSRequest, subtype helpers

Verified: barrel re-exports every original name (23 named + default with
same 17 members), REQUEST_TYPE_MAP still has 14 entries, jiraClient still
instantiates against the configured baseURL, and both consumers import
without errors under the real ES module loader.

New code should import from services/jira/* directly; the barrel is only
for backward compatibility with existing callers.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 16:36:21 -04:00
jmcqueen
312448f597 Fix #5: createSSRequest fails fast when storeNumber is missing
- New SUBTYPES_REQUIRING_STORE_NUMBER set (seeded with every current
  subType, all of which mark Store Number required in JSM). Adding a
  future subType that does NOT require Store Number is a one-line omit.
- createSSRequest now trims storeNumber (rejects whitespace-only) and
  throws a 400 with a clear message ("storeNumber is required for
  subType ...") before making any Jira API call.
- Validation errors now carry err.status = 400 so future non-route
  callers can distinguish client errors from Jira failures.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 16:30:13 -04:00
jmcqueen
c4a0a6934e Fix #4: remove global axios-retry side-effect; add dedicated downloadClient
- wxccRoutes.js no longer mutates the default axios instance, which was
  causing every bare axios call in the codebase (S3 downloads, Assets
  diagnostics) to inherit retries as a side-effect of route file load order.
- jiraService.js now defines a private downloadClient (own timeout, own
  retry policy) used by attachFileToJira and fetchAndConvertTranscript for
  fetching pre-signed S3 URLs.
- Assets AQL/GET remain bare axios calls; they're one-shot diagnostics
  and should not auto-retry.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 16:28:47 -04:00
jmcqueen
1070967870 Initial commit: Webex CC + Jira + xAI service
Core capabilities:
- Jira ticket lifecycle: status, update, comment, transitions, close
- JSM Store Support request creation with Assets object resolution
- Assets AQL diagnostic probe endpoint with schema/type introspection
- Webex transcript ingestion (audio + JSON + human-readable) with
  restricted-visibility summary comments
- Grok-powered single-ticket and open-tickets-by-reporter summaries

Repo hygiene:
- .gitignore covering .env, node_modules, logs, IDE dirs
- .env.example documenting every env var
- discover-ss-*.js scripts refactored to read credentials from .env
- README covering setup, endpoints, and the Assets scope-vs-role gotcha

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 15:23:20 -04:00