Skip to content

Feature/269 confluence connector - #185

Merged
kiranfin merged 20 commits into
devfrom
feature/269-confluence-connector
Sep 8, 2026
Merged

kiranfin merged 20 commits into
devfrom
feature/269-confluence-connector

Conversation

@daniilperkin

@daniilperkin daniilperkin commented Aug 28, 2026 •

Copy link
Copy Markdown
Collaborator

Note

Merge & Review Sequence


Summary

This PR implements end-to-end frontend support for the Confluence Cloud Connector (#269), enabling software teams to integrate Confluence Cloud spaces into the SprintStart knowledge platform, view ingested page artifacts in the Knowledge Base, and trigger manual synchronization.


🚀 Key Features & Architectural Changes

1. Confluence REST API Client (src/services/sources/confluenceService.ts)

  • Implemented confluenceService covering all endpoints on /api/v1/confluence/projects/{projectId}/connections:
    • POST /connections - Create space connection with credentials & allow/denylists
    • GET /connections - List project-scoped connections
    • GET /connections/{connectionId} - Get single connection details
    • POST /connections/{connectionId}/update - Synchronize space content (returns ConfluenceIngestionResult)
    • PUT /connections/{connectionId}/schedule - Configure automatic synchronization schedule
  • Typed request/response models: CreateConfluenceConnectionRequest, ConfluenceConnectionDto, ConfluenceIngestionResult, ConfigureConfluenceScheduleRequest, and ScheduleSpec.

2. Connectors Settings (src/features/connectors/)

  • ConfluenceConnectStep.tsx: Form to configure base URL, numeric space ID, account email, and API token.
  • useConfluenceSync.ts: Reusable hook managing space sync lifecycle with granular toast notifications for COMPLETED, PARTIAL, and FAILED results.
  • ConnectorSourcesSection.tsx: Added accordion support for Confluence spaces with "Add space", "Sync now", and scope inclusion/exclusion toggles.

3. Data Ingestion & Source Monitoring (src/features/data-ingestion/, src/pages/DataIngestionPage.tsx)

  • Add Source Flow: Integrated Confluence into AddSourceModal.tsx alongside GitHub, Jira, and File Uploads.
  • Source Details Drawer: Added space metadata card (Space Name, Space Key, Base URL, Space ID) and "Update space" action in SourceDetailsPanel.tsx. The update action resolves the connection UUID via confluenceSpace.connectionId and delegates to the shared useConfluenceSync hook.
  • State & Data Mapping (data.ts): Implemented normalization helpers to convert Confluence connections into unified IngestionSource structures. Run-matching supports baseUrl|spaceId composite format, connection.id (matching repositoryId/sourceInstanceId), spaceId, and spaceKey.
  • Ingestion History & Labels: Added run filtering by Confluence connectionId (mapped to backend repositoryId query param) and registered composite baseUrl|spaceId references, space keys, and connection IDs in buildRunSourceLabels for clean display names.

4. Admin Project Creation Wizard (src/features/admin/)

Updated CreateProjectWizard.tsx, AddSourceFlow.tsx, and projectSourcesDraft.ts to support staging Confluence spaces during initial project onboarding. Deduplication is keyed on baseUrl + spaceId.

5. Knowledge Base & Document Viewer (src/features/knowledge-base/)

  • Rich Markdown Document Rendering: Updated shouldRenderAsMarkdown() in ArtifactViewerDrawer.tsx to detect Confluence page artifacts (sourceSystem: "CONFLUENCE" or a /wiki/spaces/ URL pattern) and render with ReactMarkdown, GFM tables, and .prose styling.
  • Formatted / Source Mode Switcher: Enabled view mode toggle for Confluence pages between rendered document view and raw Markdown source.
  • Type Unification & Iconography: Added ArtifactType = "PAGE" and SourceSystem = "CONFLUENCE", mapped BookOpen document icon in ArtifactList.tsx, and ensured coexistence with ORG_METADATA.

🔒 Security & Credential Hygiene

  • Token Handling: Atlassian API tokens are handled strictly through masked password fields with defensive clipboard safety.
  • Zero Client Persistence of Secrets: Secrets are forwarded directly to backend encryption endpoints and never stored in localStorage, sessionStorage, or client logs.

🗂️ Modified Files Summary

Area File Summary of Changes
API Client src/services/sources/confluenceService.ts Complete Confluence API client, request/response DTOs, and error wrappers
Connectors src/features/connectors/components/ConfluenceConnectStep.tsx Space connection form; numeric inputMode on Space ID field
Connectors src/features/connectors/components/useConfluenceSync.ts Shared sync hook with COMPLETED / PARTIAL / FAILED toasts
Connectors src/features/connectors/components/ConnectorSourcesSection.tsx Accordion section integration with "Add space" and "Sync now"
Data Ingestion src/features/data-ingestion/components/AddSourceModal.tsx Modal flow for Confluence source type
Data Ingestion src/features/data-ingestion/components/ConfluenceConnectStep.tsx Shared controlled form (wizard + modal); numeric inputMode on Space ID
Data Ingestion src/features/data-ingestion/components/SourceDetailsPanel.tsx Space metadata card; "Update space" action using confluenceSpace.connectionId
Data Ingestion src/features/data-ingestion/data.ts Source normalization helpers; composite run-matcher; run label resolution; nextSync from nextSyncAt
Data Ingestion src/pages/DataIngestionPage.tsx Confluence connection loading; run filter with connectionId; sync delegated to useConfluenceSync
Admin Wizard src/features/admin/components/CreateProjectWizard.tsx Multi-source draft staging for Confluence spaces
Admin Wizard src/features/admin/projectSourcesDraft.ts ConfluenceDraftSource type; isSameSource deduplication; connectOneDraftSource
Knowledge Base src/features/knowledge-base/types.ts PAGE artifact type; CONFLUENCE source system
Knowledge Base src/features/knowledge-base/components/ArtifactList.tsx BookOpen icon for Confluence page artifacts
Knowledge Base src/features/knowledge-base/components/ArtifactViewerDrawer.tsx Confluence markdown detection via sourceSystem/URL (not artifactType alone); Formatted/Source toggle
Unit Tests tests/unit/services/confluenceService.test.ts API service tests with MSW
Unit Tests tests/unit/features/connectors/ConfluenceConnectStep.test.tsx Connection form submit and cancel
Unit Tests tests/unit/features/data-ingestion/ConfluenceConnectStep.test.tsx Controlled form field behaviour
Unit Tests tests/unit/features/data-ingestion/data.test.ts Source system list; createConfluenceSource* helpers; run source label resolution
Unit Tests tests/unit/features/knowledge-base/components/ArtifactViewerDrawer.test.tsx Confluence markdown rendering; negative test: non-Confluence PAGE must not render as markdown
Test Setup tests/unit/setup/msw-handlers.ts Default handlers for POST /connections and POST .../update

🧪 Verification & Quality Assurance

Automated Checks

Check Tool / Command Status
Code Formatting prettier --check . ✅ Passed (0 issues)
Type Check & Build tsc -b && vite build ✅ Passed (0 errors)
Linting eslint . ✅ Passed (0 errors)
Unit Tests vitest run tests/unit/ ✅ Passed (42 test suites / 304 tests passed)
Accessibility vitest run tests/a11y/ ✅ Passed (52 test suites / 60 tests passed, 0 axe violations)

Manual Verification

  • Connection Flow: Connected a Confluence space from the Data Ingestion modal and verified automatic background ingestion.
  • Manual Sync (connector table): Triggered space sync via "Sync now" in connectors table — verified granular toast (X created, Y updated, Z unchanged).
  • Manual Sync (source drawer): Triggered space sync via "Update space" in side drawer — verified same granular toast format as connector table (both now use the shared useConfluenceSync hook).
  • Project Wizard: Staged and verified Confluence spaces during new project onboarding.
  • Viewer Drawer: Inspected ingested Confluence page artifacts — verified typography rendering, table support, and Formatted/Source switching.
  • Regression Testing: Confirmed existing artifact types (GitHub PRs/issues, Jira items, direct uploads, PDFs, ORG_METADATA) continue to render as expected.

📋 Definition of Done (DoD)

  • Full test suite passing (npm run try runs with 0 errors).
  • No regressions in accessibility (axe a11y tests passing).
  • Backend API alignment verified with MSW mocking.
  • Code review findings addressed and committed to branch.
  • Clean Git history ready for review.

⚠️ Known Limitations / Follow-up

  • Summarise button for Confluence pages: The AI Summarise action is currently visible for Confluence page artifacts. Whether the backend /knowledge/artifacts/{id}/summary endpoint supports CONFLUENCE source system has not been confirmed. If it does not, the button should be hidden in a follow-up PR.
  • configureSchedule UI: The schedule configuration endpoint is implemented in the service client but not yet exposed in the UI. Follow-up work required to wire up a schedule settings panel for Confluence connections.

💡 Reviewer Guidance: Please review with Claude Code and commit/push any fixes directly to this branch.

…page artifacts

- Extend ArtifactType with PAGE and SourceSystem with CONFLUENCE in knowledge-base types
- Update shouldRenderAsMarkdown in ArtifactViewerDrawer to treat Confluence page artifacts as markdown documents
- Enable Formatted / Source mode switching for Confluence page artifacts in ArtifactViewerDrawer
- Add BookOpen icon mapping for PAGE artifacts in ArtifactList
- Add unit tests verifying Confluence markdown rendering and Source view toggle
…ence-connector

# Conflicts:
#	src/features/knowledge-base/components/ArtifactList.tsx
#	src/features/knowledge-base/types.ts
Bug fixes
- Fix handleUpdateSource using source.sourceId (potentially a raw
  status-row ref string) instead of the actual connection UUID when
  triggering a Confluence sync from the source details drawer.
  Now resolves the connection ID via source.confluenceSpace.connectionId,
  which is always set from the ConfluenceConnectionDto on the matched
  connection. (issue #1)

- Fix canUpdate guard in SourceDetailsPanel for Confluence sources.
  Previously used Boolean(source.sourceId) which is always truthy even
  when sourceId holds a non-UUID ref string, allowing the Update space
  button to fire and silently 404. Now checks confluence?.connectionId
  so the button is only enabled when a real connection is present. (issue #1)

- Remove over-broad artifactType === 'PAGE' condition from
  shouldRenderAsMarkdown in ArtifactViewerDrawer. The sourceSystem check
  already handles all Confluence artifacts; the PAGE type alone would
  incorrectly force any future non-Confluence PAGE artifact into Markdown
  rendering. Added a regression test to guard against this. (issue #2)

Logic fixes
- Add baseUrl|spaceId composite format as the primary candidate in the
  run-matcher inside createConfluenceSourceFromConnection, matching the
  same format already used in the DataIngestionPage status-row lookup.
  Keeps spaceId/id/spaceKey fallbacks for backwards compatibility. (issue #4)

- Fix run filter options and buildRunSourceLabels to use
  confluenceSpace.connectionId as the Confluence source reference key,
  consistent with the connection UUID the sync endpoint expects. (issue #5)

- Populate nextSync from connection.nextSyncAt in both
  createConfluenceSourceFromInstance and createConfluenceSourceFromConnection
  instead of always returning 'Not available'. Falls back to 'Not scheduled'
  when no nextSyncAt is present. (issue #8)

Refactor / polish
- Replace the inline Confluence sync toast block in handleUpdateSource with
  a delegation to useConfluenceSync, unifying toast format (COMPLETED /
  PARTIAL / FAILED with per-page counts) across all sync entry points.
  Removes duplicate toast logic and aligns the drawer's Update space action
  with the connector table's Sync now action. (issue #9)

- Add inputMode='numeric' and pattern='[0-9]+' to the Space ID input in
  both ConfluenceConnectStep variants (data-ingestion and connectors).
  Surfaces a numeric keyboard on mobile and provides native browser
  validation feedback before a server round-trip. (issue #10)

- Add default MSW handlers for POST /confluence/projects/:id/connections
  and POST .../connections/:id/update to the global test handler list.
  Prevents unhandled request warnings in tests that incidentally trigger
  these endpoints. (issue #11)

- Add a TODO comment in ConnectorSourcesSection documenting that the
  source.id passed to syncConnection must be verified to be the same
  UUID namespace as ConfluenceConnectionDto.id from the connections
  endpoint before the comment can be removed. (issue #6)

Tests
- Add negative regression test in ArtifactViewerDrawer.test.tsx: a PAGE
  artifact from a non-Confluence source system must not be rendered as
  Markdown (guards the issue #2 fix).

All 302 unit tests and 60 a11y tests pass (npm run try exit 0).
…solution

- update buildRunQuery in DataIngestionPage to pass repositoryId for Confluence connections so the backend queries by sourceInstanceId UUID
- restrict sourceRef query param strictly to Jira instance URLs
- register Confluence composite references, space keys, and connection IDs in buildRunSourceLabels so getRunSourceLabel displays friendly space names instead of raw composite strings
- add repositoryId fallback matching to createConfluenceSourceFromConnection
- add unit test coverage for Confluence run source label resolution and instance mapping
@DavidLeuter

Copy link
Copy Markdown
Collaborator

Draft, so no approval — but here's a pass over the Confluence work itself (I reviewed 258e36d…9e9e9ba plus d0f847f and c847846, i.e. the branch's own commits, not the merged-in #183/#182 content).

confluenceService.ts is clean: typed DTOs, encodeURIComponent on every path segment, every exported function documented, plus service tests, MSW handlers and an a11y test. The previous review round clearly landed. Three things I'd resolve before this leaves draft.

1. The diff can't be reviewed in isolation

gh pr diff 185 against dev is 101 files, because the branch merges in feature/minor-upgrades (#183) and feature/293-KB-gh-org-lvl-data (#182). Anyone reviewing this ends up re-reading two other PRs.

Retarget the PR base to feature/293-KB-gh-org-lvl-data (the last branch merged in) — GitHub then shows only the ~31 Confluence files, and the base can be flipped back to dev once #183 and #182 land. Same applies to #184.

2. Three different "which run belongs to this space?" matchers, and they disagree

  • DataIngestionPage status lookup — baseUrl|spaceId OR spaceId OR connection.id (3-way)
  • createConfluenceSourceFromConnection — composite OR spaceId OR id OR spaceKey OR repositoryId (5-way)
  • buildRunSourceLabels — registers connectionId, composite, lowercased composite, spaceKey and bare spaceId as label keys

Two of those keys aren't unique. labels is a flat Map shared across all source systems, so registering a bare numeric spaceId ("123456") claims a very collidable global key; and with two Confluence spaces in one project, a run whose sourceId is a bare spaceKey/spaceId can attach to the wrong card. The fallback ladders are papering over an unpinned backend contract rather than encoding one.

Worth settling with the backend: for a Confluence IngestionRun, is the identity sourceId (composite baseUrl|spaceId) or repositoryId (connection UUID)? Then keep one match plus at most one documented legacy fallback. The TODO you already left in ConnectorSourcesSection — whether source.id is the same UUID namespace as ConfluenceConnectionDto.id — is the same open question, and it's exactly the class of bug d0f847f already had to fix twice (handleUpdateSource, canUpdate).

3. The artifact count means two different things depending on which builder ran

  • createConfluenceSourceFromInstance → artifacts: status.artifactCount (real total)
  • createConfluenceSourceFromConnection → artifacts: (latestRun?.ingestedCount ?? 0) + (latestRun?.updatedCount ?? 0), and the same expression assigned to totalArtifactCount

DataIngestionPage picks between them per connection depending on whether a status row matched, so the same space can show a different number on different loads — and after a run where every page was unchanged, a space with 400 indexed pages reads 0. At minimum don't call the last-run delta totalArtifactCount; better, fall back to null/"—" when there's no status row rather than to a number that looks authoritative.

4. Two components named ConfluenceConnectStep

src/features/connectors/components/ConfluenceConnectStep.tsx (177 lines) and src/features/data-ingestion/components/ConfluenceConnectStep.tsx (118 lines) render the same four fields with the same labels, the same placeholders (https://your-domain.atlassian.net, e.g. 123456) and the same hints. They differ only in the data-testid prefix and in who owns submit/state — and the doc comment on the data-ingestion one already claims it's "shared … so the Confluence connect experience is identical in both places", which is now only two thirds true.

The cost showed up immediately: d0f847f had to add inputMode="numeric" + pattern to both. One shared fields component (testid prefix as a prop) with two thin wrappers would end that. Same for the two identically-named test files.

Smaller

  • nextSync: "Not available" → "Not scheduled" from d0f847f is good, but SOURCE_META.CONFLUENCE.description and the schedule/autoUpdate fields on the DTO suggest scheduling is coming — is configureSchedule reachable from the UI yet, or is it API-only for now? Worth a line in the description either way.

Happy to look again once it's out of draft.

Reviewed with Claude Code.

- add atlassianService.ts (/api/v1/atlassian/credentials) and drop the credential functions from jiraService.ts
- rename the credential hook/components/access-registry entry from Jira to Atlassian
- update all consumers (JiraConnectStep, AddSourceModal, CreateProjectWizard, AddSourceFlow) to the new imports and types
- add spaceName and credentialName to ConfluenceConnectionDto and ConfluenceSpaceSourceDetails
- name Confluence source cards from spaceName, falling back to spaceKey then spaceId
- show the credential name in the Confluence source details drawer
- replace email/apiToken with credentialName in the Confluence connect request, draft, and both connect forms
- share one Atlassian credential list between the Jira and Confluence pickers in both source wizards
- surface a dedicated message when a picked credential was deleted before connecting
…ource cards

- add a base URL subtitle line to Confluence cards in SourceList, mirroring the Jira instance line
- rename formatJiraInstanceDomain to formatInstanceDomain since it now serves Jira and Confluence
- update the RunDetailsPanel call site to the new name
@kiranfin
kiranfin marked this pull request as ready for review September 8, 2026 06:41
- Bring the buddy page fresh visit button and its tests over from dev
- No conflicts, build and unit tests pass
- Drop the Confluence-only add and sync actions so the connector modal only toggles sources in and out of scope
- Delete the now-unused connectors ConfluenceConnectStep and its test
- Add remove-from-project for Confluence spaces via a new deleteConnection call
- Stop remapping a 404 on connect to a credential error, since the backend message already distinguishes unknown space from unknown credential
- Reject a non-numeric Confluence space ID while staging instead of failing at provisioning time
- Carry spaceName and credentialName onto Confluence sources built from a status row
@kiranfin
kiranfin merged commit 7b019c9 into dev Sep 8, 2026
4 checks passed
@kiranfin
kiranfin deleted the feature/269-confluence-connector branch September 12, 2026 11:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Story]: Confluence connector v0 (pages, page tree)

3 participants