Data Model: Tracker Publish Resource Routing

Feature: 048-tracker-publish-resource-routing Date: 2026-03-10

Entities

Tracker Snapshot Publish Payload (Extended)

The JSON payload sent by TrackerService.sync_publish() to POST /api/v1/connectors/trackers/snapshots/.

FieldTypeSourceNew?Description
providerstringTrackerProjectConfig.providerNoNormalized provider name (e.g., "jira", "linear")
workspacestringTrackerProjectConfig.workspaceNoProvider workspace/site identifier
external_resource_type`string \null`RESOURCE_ROUTING_MAP[provider][0]Yes
external_resource_id`string \null`credentials[credential_key]Yes
doctrine_modestringTrackerProjectConfig.doctrine_modeNoOwnership policy mode
doctrine_field_ownersobjectTrackerProjectConfig.doctrine_field_ownersNoPer-field ownership map
project_uuid`string \null`.kittify/config.yamlNo
project_slug`string \null`.kittify/config.yamlNo
issuesarrayTrackerSqliteStore.list_issues()NoIssue snapshot objects
mappingsarrayTrackerSqliteStore.list_mappings()NoWP-to-issue mapping records
checkpointobjectTrackerSqliteStore.get_checkpoint()NoSync checkpoint state

Resource Routing Map (Module Constant)

Static lookup table, not persisted. Lives in src/specify_cli/tracker/service.py.

Providerexternal_resource_typeCredential KeyExample external_resource_id
jira"jira_project"project_key"ACME"
linear"linear_team"team_id"abc-123-def"
(other)nullnull

Canonical Wire Values

These are stable contract strings — not display labels. Changing them requires a versioned migration.

Wire ValueProviderResource KindMaps to ADR Layer
"jira_project"JiraJira project (identified by project key)Layer 3: ServiceResourceMapping
"linear_team"LinearLinear team (identified by team ID)Layer 3: ServiceResourceMapping

Relationships

TrackerProjectConfig
  ├── provider ─────────────────┐
  └── workspace                 │
                                ▼
TrackerCredentialStore     RESOURCE_ROUTING_MAP
  └── get_provider(provider)    └── (resource_type, credential_key)
        │                              │
        ▼                              ▼
   credentials dict         _resolve_resource_routing()
        │                         │         │
        ▼                         ▼         ▼
   credential_key value     external_resource_type  external_resource_id

State Transitions

None — the new fields are stateless, derived at publish time from existing config and credentials.

Validation Rules

RuleDescription
Provider lookupIf provider not in RESOURCE_ROUTING_MAP, both fields are null
Credential key lookupIf credentials[key] is missing, None, or empty/whitespace-only, both fields are null
Atomic nullBoth fields are always null together or both populated — never one null and one populated
No mutationThe derivation function does not modify config, credentials, or any external state