AI Agents SDE Task Viewer
      • Context
      • Plan
      • Prd
  1. Home
  2. AgentSDE
  3. agent-core
  4. gh-545
  5. plan
  6. plan.md
plan.md(3.2 KB)· Apr 23, 2026· 2 min read
  • Summary
  • Files
  • Steps
  • Verification
  • Risks
  • Open Questions

Plan — BJ-5: atlassian_oauth_state persistence#

Summary#

Add a new atlassian_oauth_state table (via TypeORM entity, not a raw migration — see Risks) plus a AtlassianOauthStateRepo with get/upsert, so Atlassian OAuth tokens (which rotate on every refresh) can be persisted durably per (platform, tenantId).

Files#

FileActionPurpose
src/database/entities/atlassian-oauth-state.entity.tscreateTypeORM entity atlassian_oauth_state with unique (platform, tenantId)
src/database/entities/index.tsmodifyBarrel export the new entity
src/database/database.module.tsmodifyRegister entity in forRoot + forFeature arrays
src/atlassian/atlassian-oauth-state.repo.tscreate@Injectable() service wrapping Repository<Entity>; get + upsert
src/atlassian/atlassian-oauth-state.repo.spec.tscreateUnit tests against in-memory SQLite
src/atlassian/atlassian.module.tscreateNestJS module: TypeOrmModule.forFeature([Entity]) + exports repo
src/atlassian/index.tscreateBarrel: module, repo, entity

Steps#

  1. Create AtlassianOauthStateEntity with columns: id (pk generated uuid), platform (varchar), tenantId (varchar, column name tenant_id), accessToken (text, nullable), refreshToken (text, not null), expiresAt (datetime, nullable, column name expires_at), updatedAt (@UpdateDateColumn); @Unique(['platform', 'tenantId']).
  2. Export the entity from src/database/entities/index.ts and add it to both entity arrays in database.module.ts.
  3. Create AtlassianOauthStateRepo with get(platform, tenantId) → entity or null, and upsert(platform, tenantId, { accessToken, refreshToken, expiresAt }) using Repository.upsert(..., ['platform','tenantId']) fallback to find+save if driver lacks support.
  4. Create AtlassianModule registering TypeOrmModule.forFeature([AtlassianOauthStateEntity]), providing and exporting AtlassianOauthStateRepo.
  5. Add barrel src/atlassian/index.ts exporting module, repo, entity.
  6. Write atlassian-oauth-state.repo.spec.ts using NestJS Test.createTestingModule with DatabaseModule (NODE_ENV=test → :memory:) covering: insert via upsert, read via get, idempotent upsert on same key (no duplicate), nullable accessToken and expiresAt round-trip.

Verification#

  • npm run test passes; new spec green.
  • npm run lint zero warnings; npm run build clean (strict TS, no any).
  • Boot-time synchronize:true creates the atlassian_oauth_state table (confirmed by spec running against in-memory sqlite).

Risks#

  • Issue wording vs. repo reality: issue asks for a migration file + PG types (timestamptz, uuid). agent-core uses better-sqlite3 with synchronize:true and has no src/migrations/ directory. Plan delivers an entity (the de-facto "migration" here); types are mapped to SQLite equivalents (varchar/datetime). Behaviour and acceptance criteria are preserved.
  • Upsert portability: Repository.upsert works with better-sqlite3 ≥ 0.3 via ON CONFLICT DO UPDATE; spec covers the concurrent-key case explicitly.

Open Questions#

  • None blocking. PR targets rc/atlassian-integration per EPIC #539.
ContextPrd