Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
72 KiB
Scratchpad — Microsoft Teams Integration V1
- Plan slug:
microsoft-teams-integration-v1 - Created:
2026-03-07
What This Is
Keep a lightweight, continuously-updated log of discoveries and decisions made while implementing this plan.
Prefer short bullets. Append new entries as you learn things, and also update earlier notes when a decision changes or an open question is resolved.
Decisions
- (2026-03-07) V1 scope is MSP users only; client-portal Teams experiences are out of scope.
- (2026-03-07) Teams will use the tenant-owned Microsoft provider configuration model rather than introducing a Teams-only credential store.
- (2026-03-07) Microsoft integration settings should expand from a singleton config into named Microsoft profiles.
- (2026-03-07) Teams will bind to one selected Microsoft profile at tenant admin setup time; end users do not choose a profile.
- (2026-03-07) Notification scope is simplified for v1: personal Teams activity-feed notifications only, no channel/chat routing.
- (2026-03-07) Bot scope is personal-first and command-first, not a general chatbot.
- (2026-03-07) Teams should be treated as one tenant integration with four surfaces, not four separate products.
- (2026-03-07) Shared command/action execution and shared notification payload generation should be reused across Teams surfaces to avoid duplicate implementations.
- (2026-03-07) Microsoft profile migration will be lazy and app-driven instead of a secret-provider-aware SQL migration: the first profile-aware read/write backfills a default profile from legacy tenant secrets and leaves legacy keys in place for compatibility.
- (2026-03-07) Default-profile compatibility will be maintained by mirroring the selected default profile back to legacy tenant secrets (
microsoft_client_id,microsoft_client_secret,microsoft_tenant_id) until consumer-binding work lands. - (2026-03-07) Profile secrets stay out of SQL. The database stores profile metadata plus a deterministic tenant secret reference (
microsoft_profile_<profile_id>_client_secret). - (2026-03-07) The Microsoft settings screen should become a profile manager in
Integrations -> Providers, with one card per profile and shared app-registration guidance rendered inline instead of a separate Teams-only credential editor. - (2026-03-07) Until explicit consumer-binding records ship, the UI will surface compatibility bindings by treating the active default profile as the current source for Email, Calendar, and MSP SSO.
- (2026-03-07) Teams registration guidance will be generated from deployment base URL plus profile client ID, including tab/bot/message-extension callback URLs and a derived Teams application ID URI (
api://<host>/teams/<clientId>). - (2026-03-07) The first Teams setup slice should live in
Integrations -> Providersnext to Microsoft profile management so admins can move between shared Microsoft credential setup and Teams setup without a separate navigation model. - (2026-03-07) Until the tenant-scoped Teams integration record exists, the Teams settings UI should be a guided readiness card: list Microsoft profiles already ready for Teams and route tenants with no eligible profile back to Microsoft profile management.
- (2026-03-07) Consumer bindings should be lazy and tenant-scoped like Microsoft profile backfill: legacy Microsoft consumers (
email,calendar,msp_sso) get compatibility binding rows on first binding-aware access, whileteamsremains explicit-only and never falls back silently. - (2026-03-07) Teams activity-feed handoffs should reuse existing PSA internal record URLs as the notification source of truth, then derive the Teams personal-tab destination from those URLs instead of introducing a second notification-only entity mapping format.
Discoveries / Constraints
- (2026-03-07)
packages/integrations/src/components/settings/integrations/MicrosoftIntegrationSettings.tsxalready anchors tenant-owned Microsoft config for Outlook inbound email, Outlook calendar, and MSP SSO; this is the right place to evolve toward named profiles. - (2026-03-07)
packages/auth/src/lib/nextAuthOptions.tsalready uses Azure AD / Microsoft OAuth and can resolve tenant-specific Microsoft credentials through MSP SSO resolution. - (2026-03-07)
packages/auth/src/lib/sso/mspSsoResolution.tsalready supports tenant-aware Microsoft provider discovery/resolution for MSP SSO. - (2026-03-07) Existing in-app notifications already store
linkand metadata, and UI components open specific PSA tickets/tasks/documents from those links. - (2026-03-07) Existing notification/deep-link infrastructure can be reused for Teams notification payloads instead of building a second record-linking system.
- (2026-03-07) Existing event/workflow infrastructure is a better trigger source for Teams notifications than adding a Teams-specific event bus.
- (2026-03-07) Existing extension iframe surfaces are useful precedent for embedded UI and auth forwarding, but they are not a native substitute for Teams bot/message-extension surfaces.
- (2026-03-07) Existing Microsoft integration flows for email, calendar, and Entra already establish tenant-secret and Graph API patterns that Teams can reuse.
- (2026-03-07) Teams package generation now persists
app_id,bot_id, and a summarizedpackage_metadatablob onteams_integrations, which keeps setup/status views tenant-local and avoids recomputing storage-less manifest state. - (2026-03-07) Rebinding Teams to a different Microsoft profile must clear persisted package metadata and reset non-
not_configuredinstall state back toinstall_pendingso stale package/install assumptions do not survive profile swaps. - (2026-03-07) The Teams setup UI now has a package handoff card that only enables generation for saved/non-
not_configuredsetups, which avoids generating install artifacts from unsaved or invalid profile selections. - (2026-03-07) Teams manifest generation and future action/notification deep links now share the same
TEAMS_PERSONAL_TAB_ENTITY_IDand Teams tab deep-link builder, which reduces drift between package declarations and runtime navigation targets. - (2026-03-07)
packages/auth/src/lib/nextAuthOptions.tsnow exposes a Teams-specificbuildTeamsAuthOptions(tenantId)entry point that resolves Microsoft credentials from the tenant-selected Teams profile and intentionally bypasses generic app/global Microsoft fallback for that surface. - (2026-03-07) There was no runtime
/teams/tabpage yet even though the generated Teams manifest already pointed the personal tab there. - (2026-03-07)
server/src/middleware.tsstill does not protect/teams/*, so the Teams tab route has to resolve auth state itself and redirect unauthenticated users into the existing MSP sign-in flow. - (2026-03-07) The auth package needed to export
resolveTeamsMicrosoftProviderConfigthroughpackages/auth/src/lib/sso/index.tsso new Teams server surfaces can reuse the tenant-selected Microsoft profile resolver without unsupported deep imports. - (2026-03-07) The Teams auth callback URIs surfaced in Microsoft profile guidance (
/api/teams/auth/callback/tab|bot|message-extension) were still missing, and/api/teams/auth/*would have been blocked by middleware API-key enforcement until explicitly exempted. - (2026-03-07) The existing SSO account-link registry already stores tenant-scoped Microsoft provider account IDs, so Teams user mapping can reuse
findOAuthAccountLink('microsoft', providerAccountId)plus theuserstable instead of introducing a separate Teams linkage table in the first identity slice. - (2026-03-07) Teams runtime entry points can receive a Microsoft/Teams tenant claim hint (
microsoftTenantId,teamsTenantId, ortid) even before richer Teams SDK bootstrap lands, so the shared auth resolver can reject requests whose Teams tenant context does not match the tenant-selected Microsoft profile. - (2026-03-07) Generated Teams personal-tab deep links already encode destination context as a
contextJSON payload, so the runtime/teams/tabentry point needs to understand that payload rather than only flat query params. - (2026-03-07) Teams tab and callback entry points were independently constructing MSP sign-in redirects; a shared Teams reauth URL helper is safer because it guarantees consistent callback preservation and gives Teams flows an explicit
teamsReauth=1marker instead of surfacing generic auth failures. - (2026-03-07) Teams entry points can arrive with
tenant=<slug>rather than a raw tenant UUID. The shared Teams auth resolver needs to translate tenant slugs to tenant IDs before enforcing same-tenant checks, otherwise valid vanity-host or slug-based deep links are rejected. - (2026-03-07) Teams auth state already re-resolves the selected Teams Microsoft profile on every request instead of caching profile identity in the session, so a Teams profile rebind can invalidate stale Microsoft-tenant assumptions immediately as long as the request still carries the old tenant hint.
- (2026-03-07) Existing Microsoft consumers still read the legacy tenant-secret keys directly. Introducing profiles without default-secret mirroring would break Outlook email, Outlook calendar, and MSP SSO compatibility.
- (2026-03-07)
packages/integrations/src/components/settings/integrations/IntegrationsSettingsPage.tsxalready gives the right long-term home for Microsoft profile management:Integrations -> Providers, not a new top-level settings tab. - (2026-03-07) The backend compatibility guard is sufficient for
F015/T029-T030: archiving the default profile is blocked until another profile is made default, which preserves the active compatibility binding. - (2026-03-07) The second slice is complete:
F019-F035andT037-T070pass with the profile manager UI, per-profile readiness/rendering, inline registration guidance, refresh, default switching, and archive confirmation. - (2026-03-07) There was no existing Teams admin settings surface in the repo;
packages/integrations/src/components/settings/integrations/IntegrationsSettingsPage.tsxProvidersis the right mount point for the first Teams setup card. - (2026-03-07) The shared
Buttoncomponent does not expose custom ids reliably in the jsdom contract harness, so the Teams settings contract test uses role/name queries for refresh actions. - (2026-03-07) The third slice is complete:
F036,F048,F056,F057,F058andT071,T072,T095,T096,T111,T112,T113,T114,T115,T116pass with a Providers-mounted Teams setup card, hash-based navigation between Microsoft profiles and Teams setup, and guided remediation when no eligible profile exists. - (2026-03-07)
server/migrations/20260307143000_create_microsoft_profile_consumer_bindings.cjsadds a tenant-scoped one-row-per-consumer binding table keyed by(tenant, consumer_type)with composite FK back tomicrosoft_profiles. - (2026-03-07)
packages/integrations/src/actions/integrations/microsoftActions.tsnow exposes binding-aware helpers/actions:listMicrosoftConsumerBindings,setMicrosoftConsumerBinding, andresolveMicrosoftProfileForConsumer. - (2026-03-07) The fourth slice is complete:
F037,F038,F039,F040,F041andT073,T074,T075,T076,T077,T078,T079,T080,T081,T082pass with a real Microsoft consumer-binding model, lazy compatibility binding backfill for legacy Microsoft consumers, and Teams explicit-binding resolution. - (2026-03-07)
server/migrations/20260307153000_create_teams_integrations.cjsadds the tenant-scoped Teams integration table keyed bytenant, linked to a selected Microsoft profile, and storing install status, enabled capabilities, notification categories, and allowed quick actions. - (2026-03-07)
packages/integrations/src/actions/integrations/teamsActions.tsnow exposesgetTeamsIntegrationStatusandsaveTeamsIntegrationSettingswith tenant-admin gating, client-user rejection, explicit selected-profile validation, and readiness checks before activation. - (2026-03-07) The fifth slice is complete:
F042,F043,F044,F045,F046,F047andT083,T084,T085,T086,T087,T088,T089,T090,T091,T092,T093,T094pass with a real Teams integration record plus guarded admin save/load actions. - (2026-03-07)
packages/integrations/src/components/settings/integrations/TeamsIntegrationSettings.tsxnow renders a real Teams setup form with explicit profile selection, readiness checklisting, selected-profile app-registration guidance, capability toggles, notification preferences, and activate/deactivate actions. - (2026-03-07) The sixth slice is complete:
F049,F050,F051,F052,F053,F054,F055andT097,T098,T099,T100,T101,T102,T103,T104,T105,T106,T107,T108,T109,T110pass with a saveable Teams setup workflow in the settings UI. - (2026-03-07)
packages/integrations/src/actions/integrations/teamsPackageActions.tsnow builds tenant-specific Teams app package metadata from the selected Teams profile, including manifest structure, personal tab/bot declarations, compose-extension commands, activity-feed activity types, webApplicationInfo, valid domains, and environment-aware base URLs. - (2026-03-07) The seventh slice is complete:
F059,F060,F061,F062,F063,F064,F065,F066,F067,F068,F069,F071andT117,T118,T119,T120,T121,T122,T123,T124,T125,T126,T127,T128,T129,T130,T131,T132,T133,T134,T135,T136,T137,T138,T141,T142pass with a generated Teams manifest/package model and guarded package-status retrieval.
Commands / Runbooks
- (2026-03-07) Scaffolded plan folder with:
python3 /Users/roberisaacs/.codex/skills/alga-plan/scripts/scaffold_plan.py "Microsoft Teams Integration V1" --slug microsoft-teams-integration-v1 - (2026-03-07) Backend verification commands:
cd server && npx vitest run --config vitest.config.ts ../packages/integrations/src/actions/integrations/microsoftActions.test.ts ../packages/integrations/src/actions/integrations/providerReadiness.test.tspnpm --dir packages/integrations typecheck
- (2026-03-07) UI verification commands:
cd server && npx vitest run --config vitest.config.ts ../packages/integrations/src/components/settings/integrations/MicrosoftIntegrationSettings.contract.test.tsxcd server && npx vitest run --config vitest.config.ts ../packages/integrations/src/actions/integrations/microsoftActions.test.ts ../packages/integrations/src/actions/integrations/providerReadiness.test.ts ../packages/integrations/src/components/settings/integrations/MicrosoftIntegrationSettings.contract.test.tsxcd server && npx vitest run --config vitest.config.ts ../packages/integrations/src/components/settings/integrations/TeamsIntegrationSettings.contract.test.tsx ../packages/integrations/src/components/settings/integrations/IntegrationsSettingsPage.providers.test.tscd server && npx vitest run --config vitest.config.ts ../packages/integrations/src/components/settings/integrations/MicrosoftIntegrationSettings.contract.test.tsx ../packages/integrations/src/components/settings/integrations/TeamsIntegrationSettings.contract.test.tsx ../packages/integrations/src/components/settings/integrations/IntegrationsSettingsPage.providers.test.tscd server && npx vitest run --config vitest.config.ts ../packages/integrations/src/actions/integrations/microsoftActions.test.ts ../packages/integrations/src/actions/integrations/microsoftConsumerBindings.test.ts ../server/src/test/unit/migrations/microsoftConsumerBindingsMigration.test.tscd server && npx vitest run --config vitest.config.ts ../packages/integrations/src/actions/integrations/teamsActions.test.ts ../server/src/test/unit/migrations/teamsIntegrationsMigration.test.tscd server && npx vitest run --config vitest.config.ts ../packages/integrations/src/components/settings/integrations/TeamsIntegrationSettings.contract.test.tsx ../packages/integrations/src/components/settings/integrations/IntegrationsSettingsPage.providers.test.tscd server && npx vitest run --config vitest.config.ts ../packages/integrations/src/actions/integrations/teamsPackageActions.test.ts
- (2026-03-07) Relevant local references:
packages/integrations/src/components/settings/integrations/MicrosoftIntegrationSettings.tsxpackages/integrations/src/components/settings/integrations/MicrosoftIntegrationSettings.contract.test.tsxpackages/integrations/src/components/settings/integrations/TeamsIntegrationSettings.tsxpackages/integrations/src/components/settings/integrations/TeamsIntegrationSettings.contract.test.tsxpackages/integrations/src/components/settings/integrations/IntegrationsSettingsPage.tsxpackages/integrations/src/components/settings/integrations/IntegrationsSettingsPage.providers.test.tspackages/integrations/src/actions/integrations/microsoftActions.tspackages/integrations/src/actions/integrations/microsoftConsumerBindings.test.tspackages/integrations/src/actions/integrations/providerReadiness.tspackages/integrations/src/actions/integrations/teamsActions.tspackages/integrations/src/actions/integrations/teamsActions.test.tspackages/integrations/src/actions/integrations/teamsPackageActions.tspackages/integrations/src/actions/integrations/teamsPackageActions.test.tspackages/auth/src/lib/nextAuthOptions.tspackages/auth/src/lib/sso/mspSsoResolution.tspackages/notifications/src/actions/internal-notification-actions/internalNotificationActions.tsserver/src/lib/utils/notificationLinkResolver.tsserver/src/lib/eventBus
- (2026-03-07) Verified Teams package metadata persistence and invalidation with:
pnpm --dir packages/integrations typecheckcd server && npx vitest run --config vitest.config.ts ../packages/integrations/src/actions/integrations/teamsActions.test.ts ../packages/integrations/src/actions/integrations/teamsPackageActions.test.ts ../server/src/test/unit/migrations/teamsPackageMetadataMigration.test.ts
- (2026-03-07) Verified Teams tab auth bootstrap with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/resolveTeamsTabAuthState.test.ts src/test/unit/app/teams/tab/page.test.tsxpnpm --dir packages/auth typecheck
- (2026-03-07) Verified Teams auth callback routes with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/resolveTeamsTabAuthState.test.ts src/test/unit/app/teams/tab/page.test.tsx src/app/api/teams/auth/callback/bot/route.test.ts src/app/api/teams/auth/callback/message-extension/route.test.ts
- (2026-03-07) Verified Teams linked-user resolution with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/resolveTeamsLinkedUser.test.ts src/test/unit/lib/teams/resolveTeamsTabAuthState.test.ts src/test/unit/app/teams/tab/page.test.tsx src/app/api/teams/auth/callback/bot/route.test.ts src/app/api/teams/auth/callback/message-extension/route.test.ts
- (2026-03-07) Verified Teams Microsoft-tenant mismatch rejection with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/resolveTeamsTabAuthState.test.ts src/test/unit/app/teams/tab/page.test.tsx src/app/api/teams/auth/callback/bot/route.test.ts src/app/api/teams/auth/callback/message-extension/route.test.ts src/test/unit/lib/teams/resolveTeamsLinkedUser.test.ts
- (2026-03-07) Verified Teams deep-link destination bootstrap with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/resolveTeamsTabDestination.test.ts src/test/unit/app/teams/tab/page.test.tsx src/test/unit/lib/teams/resolveTeamsTabAuthState.test.ts src/app/api/teams/auth/callback/bot/route.test.ts src/app/api/teams/auth/callback/message-extension/route.test.ts src/test/unit/lib/teams/resolveTeamsLinkedUser.test.ts
- (2026-03-07) Verified Teams-safe reauthentication redirects with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/buildTeamsReauthUrl.test.ts src/test/unit/lib/teams/resolveTeamsTabDestination.test.ts src/test/unit/app/teams/tab/page.test.tsx src/test/unit/lib/teams/resolveTeamsTabAuthState.test.ts src/app/api/teams/auth/callback/bot/route.test.ts src/app/api/teams/auth/callback/message-extension/route.test.ts src/test/unit/lib/teams/resolveTeamsLinkedUser.test.ts
- (2026-03-07) Verified Teams tenant-slug resolution with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/resolveTeamsTabAuthState.test.ts src/test/unit/app/teams/tab/page.test.tsx src/app/api/teams/auth/callback/bot/route.test.ts src/app/api/teams/auth/callback/message-extension/route.test.ts src/test/unit/lib/teams/buildTeamsReauthUrl.test.ts src/test/unit/lib/teams/resolveTeamsTabDestination.test.ts src/test/unit/lib/teams/resolveTeamsLinkedUser.test.ts
- (2026-03-07) Verified Teams profile-rebind invalidation with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/resolveTeamsTabAuthState.test.ts
- (2026-03-07) Verified Teams tab destination access gating and state distinction with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/app/teams/tab/page.test.tsx src/app/api/teams/auth/callback/bot/route.test.ts src/test/unit/lib/teams/resolveTeamsTabAccessState.test.ts src/test/unit/lib/teams/resolveTeamsTabAuthState.test.ts
- (2026-03-07) Verified Teams selected-profile precedence over broad Microsoft env credentials with:
cd packages/auth && npx vitest run --config vitest.config.ts src/lib/sso/teamsMicrosoftProviderResolution.test.ts
- (2026-03-07) Verified Teams-safe auth remediation copy with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/resolveTeamsTabAuthState.test.ts
- (2026-03-07) Verified Teams personal-tab default landing and fallback routing with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/app/teams/tab/page.test.tsx src/test/unit/lib/teams/resolveTeamsTabDestination.test.ts
- (2026-03-07) Verified Teams activity-feed notification deep-link routing with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/resolveTeamsTabDestination.test.ts src/test/unit/app/teams/tab/page.test.tsxcd server && npx vitest run --config vitest.config.ts ../packages/integrations/src/actions/integrations/teamsPackageActions.test.tspnpm --dir packages/integrations typecheck
Progress Log
- (2026-03-07) Completed
F070by adding a migration forteams_integrations.app_id,bot_id, andpackage_metadata, and by persisting generated Teams package metadata inpackages/integrations/src/actions/integrations/teamsPackageActions.ts. - (2026-03-07) Completed
F072by clearing stored Teams package metadata and resetting install readiness toinstall_pendingwhen the selected Teams Microsoft profile changes inpackages/integrations/src/actions/integrations/teamsActions.ts. - (2026-03-07) Completed
T139,T140,T143, andT144with focused migration and action-layer tests covering package metadata storage and stale-profile invalidation behavior. - (2026-03-07) Completed
F073by adding a Teams package handoff panel inpackages/integrations/src/components/settings/integrations/TeamsIntegrationSettings.tsxthat prepares tenant package metadata and downloads a manifest JSON snapshot for admin install handoff. - (2026-03-07) Completed
T145andT146with UI contract coverage for successful package handoff generation/download and recoverable package-generation failures. - (2026-03-07) Completed
F074by adding shared Teams personal-tab deep-link builders and template targets inpackages/integrations/src/actions/integrations/teamsPackageActions.ts, keeping package declarations aligned with future notification/action destinations. - (2026-03-07) Completed
T147andT148with package-action tests covering deep-link template generation and prerequisite guard behavior. - (2026-03-07) Completed
F075by addingpackages/auth/src/lib/sso/teamsMicrosoftProviderResolution.tsand wiringbuildTeamsAuthOptions(tenantId)inpackages/auth/src/lib/nextAuthOptions.tsso Teams-specific auth can use the selected Teams Microsoft profile instead of broad fallback credentials. - (2026-03-07) Completed
T149andT150with focused resolver tests plus a NextAuth contract test covering the Teams-specific auth-options entry point. - (2026-03-07) Completed
F076by addingserver/src/lib/teams/resolveTeamsTabAuthState.tsplus the first runtime/teams/tabpage inserver/src/app/teams/tab/page.tsx, which resolves MSP tenant/user context, redirects unauthenticated users to/auth/msp/signin, and renders Teams-safe remediation for non-ready tenants. - (2026-03-07) Completed
T151andT152with focused Teams-tab auth-state tests inserver/src/test/unit/lib/teams/resolveTeamsTabAuthState.test.tsand page-wiring coverage inserver/src/test/unit/app/teams/tab/page.test.tsx. - (2026-03-07) Completed
F077andF078by adding shared Teams auth callback handling inserver/src/lib/teams/handleTeamsAuthCallback.tsplus concrete/api/teams/auth/callback/botand/api/teams/auth/callback/message-extensionroutes that resolve tenant/MSP user context from the existing Teams auth-state resolver and return Teams-safe popup payloads. - (2026-03-07) Added
/api/teams/auth/to the middleware API-key skip list so Teams browser-based auth callbacks can complete without being rejected as generic API traffic. - (2026-03-07) Completed
T153,T154,T155, andT156with route-level tests covering ready callback payloads, unauthenticated redirect behavior, and safe rejected-access payloads for both bot and message-extension surfaces. - (2026-03-07) Completed
F079,F080,F081, andF082via the shared Teams auth-state resolver: only internal MSP users can proceed, client users are rejected explicitly, the resolver prefersgetSessionWithRevocationCheck()with the existing auth fallback path, and missing/not-ready Teams profiles return remediation-safenot_configuredorinvalid_profilestates. - (2026-03-07) Completed
T157,T158,T159,T160,T161,T162,T163, andT164by extending the Teams auth-state unit coverage to assert MSP-only acceptance, client-user rejection, revocation-checked session reuse, and admin-readable not-configured/invalid-profile failures. - (2026-03-07) Completed
F083by addingserver/src/lib/teams/resolveTeamsLinkedUser.ts, which resolves a tenant-scoped Microsoft provider account link back to the matching internal PSA user and rejects missing, cross-tenant, or client-user mappings safely. - (2026-03-07) Completed
T165andT166with focused coverage inserver/src/test/unit/lib/teams/resolveTeamsLinkedUser.test.tsfor linked-user resolution plus missing-identity, cross-tenant, and client-user rejection paths. - (2026-03-07) Completed
F084by extendingserver/src/lib/teams/resolveTeamsTabAuthState.tsto compare incoming Teams Microsoft-tenant hints against the tenant-selected Teams Microsoft profile and reject mismatches centrally. - (2026-03-07) Completed
T167andT168by extending Teams auth-state, tab-page, and auth-callback tests to cover matching tenant claims and wrong-Microsoft-tenant rejection behavior. - (2026-03-07) Completed
F085by addingserver/src/lib/teams/resolveTeamsTabDestination.tsand wiring/teams/tabto bootstrap destinations from Teamscontextpayloads while preserving the exact deep-link payload through MSP sign-in redirects. - (2026-03-07) Completed
T169andT170with focused destination-parser coverage and Teams-tab page tests covering deep-link bootstrap plus safe rejection/redirect behavior for protected deep-link entries. - (2026-03-07) Completed
F086by addingserver/src/lib/teams/buildTeamsReauthUrl.tsand routing both Teams tab and Teams auth callbacks through the same explicit Teams-safe MSP reauthentication path. - (2026-03-07) Completed
T171andT172with focused reauth URL helper coverage plus tab/bot callback tests asserting expired or invalid Teams sessions redirect to Teams-safe reauth URLs instead of leaking raw auth failures. - (2026-03-07) Completed
F087by extendingserver/src/lib/teams/resolveTeamsTabAuthState.tsto resolve tenant slugs viagetTenantIdBySlugbefore comparing Teams entry-point tenant hints to the authenticated MSP tenant. - (2026-03-07) Completed
T173andT174with Teams auth-state, Teams tab page, and bot callback tests covering slug-based tenant resolution on vanity-host-style entry points plus safe rejection when the slug resolves to the wrong tenant. - (2026-03-07) Completed
F088by verifying thatserver/src/lib/teams/resolveTeamsTabAuthState.tsre-reads Teams profile binding state per request, so stale Microsoft-tenant assumptions are rejected immediately after a Teams profile rebind. - (2026-03-07) Completed
T175andT176with a focused Teams auth-state regression test that simulates a tenant profile rebind between requests and asserts the old Teams Microsoft tenant hint is rejected on the next request. - (2026-03-07) Completed
F089by addingserver/src/lib/teams/resolveTeamsTabAccessState.tsand wiringserver/src/app/teams/tab/page.tsxthrough it so a ready Teams SSO session still has to pass existing PSA permission checks plus tenant-scoped entity lookup before ticket, project-task, contact, time-entry, or approval destinations are treated as accessible. - (2026-03-07) Completed
T177andT178with focused access-resolver and Teams-tab page tests covering allowed destination access, permission-denied short-circuiting, tenant-scoped not-found handling, and Teams-safe fallback rendering after authentication succeeds. - (2026-03-07) Completed
F090by verifying the existingpackages/auth/src/lib/sso/teamsMicrosoftProviderResolution.tsimplementation already resolves Teams auth exclusively from the tenant-selected Teams Microsoft profile instead of broad app/global Microsoft environment credentials. - (2026-03-07) Completed
T179andT180with explicit resolver regression tests asserting Teams ignores broad Microsoft env credentials both when a valid selected profile exists and when Teams setup/profile state is missing or invalid. - (2026-03-07) Completed
F091by verifying the Teams tab page and Teams bot auth callback keepunauthenticated,forbidden, andnot_configuredoutcomes distinct at the surface boundary instead of collapsing them into one generic failure path. - (2026-03-07) Completed
T181andT182with surface-level tests covering not-configured Teams tab rendering and not-configured bot auth callback payloads alongside the existing unauthenticated redirect and forbidden-access cases. - (2026-03-07) Completed
F092by verifying the shared Teams auth-state resolver only returns human-readable remediation copy that remains safe to surface inside Teams tab/callback UI constraints. - (2026-03-07) Completed
T183andT184with a focused auth-state test asserting unauthenticated, client-user, and invalid-profile failures use safe remediation text and avoid raw OAuth/provider jargon. - (2026-03-07) Completed
F093by verifying the existing/teams/tabroute acts as the Teams personal-tab entry point for PSA and can render a ready default destination without additional Teams context. - (2026-03-07) Completed
T185andT187with a Teams-tab page test asserting the default ready state renders themy_workdestination for the personal-tab entry path. - (2026-03-07) Completed
F094by verifying the default Teams tab destination model already resolves tomy_work, which matches the intended PSA technician landing surface for the personal tab. - (2026-03-07) Completed
T186andT188with destination-parser coverage asserting unsupported or malformed Teams context falls back safely tomy_workinstead of failing open. - (2026-03-07) Completed
F095,F096,F097,F098, andF099by expanding the Teams tab destination model and page shell so ticket, project-task, approval, time-entry, and contact deep links all render explicit entity context, with contact links carrying optional client context from Teams message-driven entry points. - (2026-03-07) Completed
T189throughT200with parser and page coverage for valid ticket/project-task/approval/time-entry/contact deep links plus guard coverage for incomplete context payloads falling back safely tomy_work. - (2026-03-07) Completed
F100by changing destination copy from generic bootstrap text to entity-specific titles and summaries so the initial Teams tab load visibly confirms the intended PSA entity. - (2026-03-07) Completed
F101by changing post-auth record-access failures from a dead-end error card into a safemy_workfallback shell with explanatory messaging about the unavailable requested destination. - (2026-03-07) Completed
T201andT202with page tests asserting unavailable ticket/project-task/approval/time-entry/contact links land on themy_workfallback shell and preserve the requested-destination context in user-facing remediation copy. - (2026-03-07) Completed
F102by adding a shared Teams full-PSA URL builder and surfacing anOpen in full PSAhandoff from the tab shell for ticket, project-task, approval, time-entry, and contact destinations, including fallback states that still preserve the originally requested record URL. - (2026-03-07) Completed
T203andT204with a focused URL-builder test plus page assertions covering visible full-PSA handoff links for entity destinations and omission of that link for the defaultmy_worklanding. - (2026-03-07) Completed
F103by reconciling the plan with the existing access-state gate: the Teams tab only renders a destination after PSA permission checks and tenant-scoped entity resolution succeed, and otherwise falls back safely instead of rendering unauthorized content. - (2026-03-07) Completed
T205andT206against the existingresolveTeamsTabAccessStatehappy/guard coverage and the tab-page fallback tests that already exercise authorization-preserving behavior for ready versus unavailable destinations. - (2026-03-07) Completed
F104by replacing the ready-state Teams record shell with a same-origin iframe of the existing PSA record route when an authorized entity destination is available, so the tab now reuses PSA screens/components instead of keeping a parallel Teams-only detail view. - (2026-03-07) Completed
T207andT208with page assertions proving authorized entity destinations render an embedded PSA route while fallback states intentionally suppress that embed and stay on the safe Teams shell. - (2026-03-07) Completed
F105by keeping the embedded PSA composition on same-origin internal MSP routes that inherit the authenticated MSP session and tenant-scoped host context, avoiding any second auth callback or token-bearing bootstrap channel inside the iframe URL. - (2026-03-07) Completed
T209andT210with URL-builder tests asserting embedded PSA routes remain relative/msp/...paths without callback/token parameters plus fallback-shell tests that suppress the embed when the requested destination is unavailable. - (2026-03-07) Completed
F106by teaching Teams personal-tab routing and Teams deep-link helpers to derive supported tab destinations from existing PSA notification URLs (/msp/tickets/...,/msp/projects/...?...,/msp/time-sheet-approvals?...,/msp/time-entry?...,/msp/contacts/...) so activity-feed handoffs can target the exact tab destination without a second notification-specific mapping layer. - (2026-03-07) Completed
T211andT212with unit and page coverage for notification-link destination parsing, Teams deep-link generation from PSA URLs, and safe my-work fallback when a notification targets an unsupported or unavailable record.server/migrations/20260307120000_create_microsoft_profiles.cjsserver/migrations/20260307143000_create_microsoft_profile_consumer_bindings.cjsserver/migrations/20260307153000_create_teams_integrations.cjsserver/src/test/unit/migrations/microsoftConsumerBindingsMigration.test.tsserver/src/test/unit/migrations/teamsIntegrationsMigration.test.ts
- (2026-03-07) The focused vitest slice still emits pre-existing React
act(...)warnings fromMicrosoftIntegrationSettings.contract.test.tsx; the tests pass, but the harness remains noisy. - (2026-03-07) The Teams setup contract tests currently emit similar non-blocking React
act(...)warnings while asserting async save flows; the tests pass, but the harness remains noisy. - (2026-03-07)
npx vitest run --config vitest.config.ts src/test/unit/app/teams/tab/page.test.tsx src/test/unit/lib/teams/resolveTeamsTabDestination.test.ts - (2026-03-07)
npx vitest run --config vitest.config.ts src/test/unit/app/teams/tab/page.test.tsx src/test/unit/lib/teams/resolveTeamsTabDestination.test.ts src/test/unit/lib/teams/buildTeamsFullPsaUrl.test.ts - (2026-03-07)
npx vitest run --config vitest.config.ts src/test/unit/app/teams/tab/page.test.tsx - (2026-03-07)
npx vitest run --config vitest.config.ts src/test/unit/app/teams/tab/page.test.tsx src/test/unit/lib/teams/buildTeamsFullPsaUrl.test.ts - (2026-03-07) Verified bot-result, message-extension-result, cold-start tab, and escalation-path behavior with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/resolveTeamsTabAccessState.test.ts src/test/unit/lib/teams/resolveTeamsTabDestination.test.ts src/test/unit/app/teams/tab/page.test.tsx ../packages/integrations/src/actions/integrations/teamsPackageActions.test.tspnpm --dir packages/integrations typecheckpnpm --dir server exec tsc -p tsconfig.json --noEmit --pretty false
- (2026-03-07) Running multiple coverage-enabled Vitest commands in parallel can race on
server/coverage/.tmp; rerun sequentially for a clean green verification slice. - (2026-03-07) Next unchecked feature after this slice is
F111(Shared Teams action registry exists for bot commands, message-extension actions, and card/dialog submits).
Links / References
- Microsoft Teams docs used during investigation:
- Tabs overview:
https://learn.microsoft.com/en-us/microsoftteams/platform/tabs/what-are-tabs - Tab SSO overview:
https://learn.microsoft.com/en-us/microsoftteams/platform/tabs/how-to/authentication/tab-sso-overview - Tab SSO manifest:
https://learn.microsoft.com/en-us/microsoftteams/platform/tabs/how-to/authentication/tab-sso-manifest - Bot SSO overview:
https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/bot-sso-overview - Bot SSO manifest:
https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/bot-sso-manifest - Activity feed notifications:
https://learn.microsoft.com/en-us/microsoftteams/platform/tabs/send-activity-feed-notification - Deep links:
https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/build-and-test/deep-links - Search commands:
https://learn.microsoft.com/en-us/microsoftteams/platform/messaging-extensions/how-to/search-commands/define-search-command - Action commands:
https://learn.microsoft.com/en-us/microsoftteams/platform/messaging-extensions/how-to/action-commands/define-action-command - Dialogs / task modules:
https://learn.microsoft.com/en-us/microsoftteams/platform/task-modules-and-cards/task-modules/invoking-task-modules
- Tabs overview:
- Existing related plans:
ee/docs/plans/2026-02-23-msp-tenant-first-sso-provider-resolutionee/docs/plans/2026-02-20-entra-integration-phase-1
Open Questions
- Do existing Microsoft consumers beyond Teams need explicit per-consumer profile selection UX in v1, or is a default-binding compatibility path sufficient initially?
- How much approval behavior belongs in Teams quick actions versus deep-linking into the tab?
- What exact tenant-by-tenant Teams app packaging and distribution flow should be used across local/dev/staging/prod?
Additional Discoveries / Constraints
- (2026-03-07) The existing Teams tab runtime already understood direct
contextand notification-style PSA URLs; bot and message-extension result handoff only needed explicit surface-specific link aliases plus stable deep-link builders, not a new tab route. - (2026-03-07) The personal tab shell is a good place to surface invoking-surface context (
bot,message_extension,notification) because it confirms why the user landed on a record without changing destination authorization semantics. - (2026-03-07) The project-task Teams access check should stay local to Teams and use
ProjectService.getTasks(projectId, context)for project/task consistency instead of widening the sharedIProjectTaskinterface with aproject_idfield that ripples through unrelated project-editing call sites. - (2026-03-07) The smallest reusable Teams action-layer pattern in this repo is a typed registry plus normalized DTO/result unions in
server/src/lib/teams/actions, not the heavier workflow runtime registry; that keeps bot, message-extension, and quick-action semantics aligned with the existing Teams auth/setup code. - (2026-03-07) Teams action results can derive Teams-tab links from existing PSA record URLs by flowing through
buildTeamsFullPsaUrlfirst and only then calling the Teams package deep-link builders, which keeps the PSA route as the source of truth. - (2026-03-07) The first idempotency slice for Teams actions is process-local and keyed by
tenant + user + action + idempotencyKey; that is enough to prevent duplicate mutation execution within the current app process while keeping the action layer free of new persistence until a later concurrency hardening pass is justified. - (2026-03-07) The first Teams bot transport can stay SDK-free: a Next.js route can accept Bot Framework-style activity JSON, resolve tenant/user context locally, and map shared Teams action results into simple hero-card responses without introducing
botbuilder. - (2026-03-07) Bot requests need a tenant-resolution helper separate from browser SSO because webhook activities arrive without a PSA session; the tenant can be resolved from an explicit query hint first and then from the selected Teams profile's Microsoft tenant ID.
- (2026-03-07) Bot follow-up shortcuts should be filtered through
listAvailableTeamsActions(...)so ticket result cards only advertise tenant-enabled actions and stay aligned with central Teams capability gating. - (2026-03-07) The smallest useful bot mutation syntax is
assign ticket <ticket-id> to <assignee>withto meas the default fallback andadd note <ticket-id>: <note>for note entry; both shapes keep parsing deterministic without introducing multi-step bot state. - (2026-03-07) Resolving a non-self assignee from the bot should require
user:readpermission and only match active internal PSA users by exact user ID, email, username, or full name so Teams assignment stays tenant-scoped and predictable. - (2026-03-07) Pending-approval lookup needs to mirror the existing Manager Approval dashboard scope logic instead of
TimeSheetService.list(...), because the service layer does not currently apply manager / reports-to visibility for time-sheet approvals. - (2026-03-07) The current time-sheet approval model supports
approveandrequest_changes, not a distinct reject mutation, so the Teams bot treatsreject approval ...as a user-friendly alias for the sharedrequest_changesaction. - (2026-03-07) The first Teams message-extension slice can stay SDK-free like the bot transport: a Next.js invoke route can accept
composeExtension/querypayloads directly and reuse tenant/user resolution plus the shared Teams action layer for result cards. - (2026-03-07) Approval lookup needed a reusable helper outside the action registry so both bot approvals and message-extension search can share the same manager/reports-to visibility rules and optional query filtering.
- (2026-03-07) The smallest safe v1 message-extension search surface is one
searchRecordscommand forcomposeandcommandBoxcontexts that aggregates tickets, tasks, contacts, and approvals into sharedopen_recordhero cards. - (2026-03-07) The first message-context action slice can reuse the same message-extension route by handling
composeExtension/fetchTaskandcomposeExtension/submitAction, returning Teams-safe task responses without introducing a second webhook surface. - (2026-03-07) The current message-action transport is intentionally a handoff foundation: it preserves Teams-authenticated message context and shows a task-module preview while later slices add actual message-to-ticket and message-to-update mutations.
- (2026-03-07) Teams message-extension pagination can use native
queryOptions.skip/countwindowing instead of a custom continuation token; for the merged multi-entity result set, fetching up toskip + countper entity and slicing centrally is sufficient for the first paged slice. - (2026-03-07) The cleanest way to surface message-extension quick actions is to reuse
listAvailableTeamsActions(...)per search hit and append only currently available mutation titles to the sharedopen_recordcard summary, which keeps result cards aligned with tenant allowed-action settings without introducing premature action buttons. - (2026-03-07) The first inline Teams message-to-ticket slice can stay inside
teamsMessageExtensionHandler.tsas long as it still reuses the shared ticket model for creation, tenant default board/status/priority configuration, and sharedopen_recordlink mapping for confirmation. - (2026-03-07) Storing Teams message provenance plus the submit idempotency key in
tickets.attributesis the smallest migration-free way to satisfy message-source auditability and duplicate-submit replay for Teams message actions. - (2026-03-07) The first message-to-update slice can stay in
server/src/lib/teams/messageExtension/teamsMessageExtensionHandler.tsas long as ticket mutations still flow through the shared Teams action registry and project-task updates fail safely into a Teams-tab handoff instead of inventing a second task-specific mutation path. - (2026-03-07) Ticket message-to-update provenance is simplest when stored on the created
comments.metadatapayload, so the sharedTicketService.addComment(...)contract now needs to accept optional metadata for both internal notes and customer-visible replies. - (2026-03-07) A generic
Continue in Teams tabaction can be attached to message-action task modules wheneverteams_integrationsalready hasappIdpluspackageMetadata.baseUrl; if those install artifacts are missing, the task flow should remain functional without the handoff button. - (2026-03-07)
createTicketFromMessageandupdateFromMessagetask-module UIs can stay inteamsMessageExtensionHandler.ts, but their submit paths should route through dedicated registry actions (create_ticket_from_message,update_from_message) so message-driven workflows share the same idempotency, permission, and result-link plumbing as the rest of Teams. - (2026-03-07) The cleanest Teams notification slice is a second delivery channel hanging off
packages/notifications/src/realtime/internalNotificationBroadcaster.ts, so existing internal notification producers and workflow-triggered notification rows do not need Teams-specific fanout logic. - (2026-03-07) Teams activity-feed delivery can reuse the existing
internal_notifications.linkPSA URL by converting it withbuildTeamsPersonalTabDeepLinkFromPsaUrl(...); no notification-specific destination mapping table is needed. - (2026-03-07) Category routing for Teams notifications is easiest to derive from the notification row itself: template names cover assignment/customer-reply/SLA, while approval requests can be recognized from approval-style PSA links.
- (2026-03-07) Delivering personal Teams activity-feed notifications requires the Teams app manifest to request the
TeamsActivity.Send.Userapplication RSC permission in addition to the existing activity declaration.
Progress Log
-
(2026-03-07) Completed
F107andF108by teachingserver/src/lib/teams/resolveTeamsTabDestination.tsto resolvebotResultLinkandmessageExtensionResultLinkentries, adding explicit entry-source handling inserver/src/app/teams/tab/page.tsx, and exposing surface-specific Teams deep-link helpers inpackages/integrations/src/actions/integrations/teamsPackageActions.ts. -
(2026-03-07) Completed
F109by refining the not-configured Teams tab copy so cold-start tenants get a setup-specific heading and remediation message instead of a generic unavailable state. -
(2026-03-07) Completed
F110by making the tab shell explicitly describe theOpen in full PSAhandoff as the escalation path when a workflow needs more context than Teams cards or quick actions provide. -
(2026-03-07) Completed
T213,T214,T215, andT216with destination-parser, page-shell, and deep-link-builder coverage for bot-result and message-extension-result tab handoff plus safe fallback behavior. -
(2026-03-07) Completed
T217,T218,T219, andT220with page-shell coverage for graceful cold-start setup messaging and explicit full-PSA escalation copy. -
(2026-03-07) Fixed two pre-existing server TypeScript blockers encountered during verification by narrowing
normalizeTenantClaimto acceptundefinedinserver/src/lib/teams/resolveTeamsTabAuthState.tsand by keeping the project-task Teams access check local inserver/src/lib/teams/resolveTeamsTabAccessState.tsinstead of widening shared project-task interfaces. -
(2026-03-07) Completed
F111throughF126by addingserver/src/lib/teams/actions/teamsActionRegistry.ts, which centralizes Teams action definitions, input normalization, target resolution, permission/capability gating, result mapping, allowed-action metadata, and idempotent mutation replay for shared bot/message-extension/quick-action execution. -
(2026-03-07) Completed
T221throughT252withserver/src/test/unit/lib/teams/actions/teamsActionRegistry.test.ts, covering registry metadata, input normalization, ticket/task/contact/approval/time-entry resolution, permission guards, consistent validation errors, invoking-surface metadata, PSA-first deep-link generation, idempotent mutation replay, partial-failure remediation, capability gating, and service reuse for time entry and approval mutations. -
(2026-03-07) Exported
getTeamsIntegrationExecutionState(tenant)frompackages/integrations/src/actions/integrations/teamsActions.tsso future Teams route handlers can read install status, enabled capabilities, allowed actions, app id, and package metadata without duplicating Teams integration row mapping. -
(2026-03-07) Completed
F127throughF134by adding an SDK-free Teams bot transport inserver/src/app/api/teams/bot/messages/route.tsandserver/src/lib/teams/bot/teamsBotHandler.ts, plusserver/src/lib/teams/resolveTeamsTenantContext.tsfor tenant selection from Teams webhook context. The handler enforces personal-scope-only behavior, resolves linked MSP users, renders help/unsupported guidance, parses supported bot commands, and filters follow-up shortcuts through tenant allowed-action state. -
(2026-03-07) Completed
F135,F136, andF137by wiring the botmy ticketscommand through the shared Teams action layer and rendering summary cards with ticket number/title/status-style summaries plus Teams-tab and full-PSA links. -
(2026-03-07) Completed
F138andF139by wiringticket <id>through the shared Teams action layer, enriching open-record summaries with entity-specific detail, and returning clear recoverable not-found/permission failures inside bot-safe cards. -
(2026-03-07) Completed
T253throughT278withserver/src/test/unit/lib/teams/bot/teamsBotHandler.test.tsandserver/src/app/api/teams/bot/messages/route.test.ts, covering route presence, invalid JSON handling, welcome/help responses, unsupported-command recovery, personal-scope-only enforcement, allowed-action filtering, shared entity-reference parsing,my ticketscards/deep links, andticket <id>success/error behavior. -
(2026-03-07) Verified shared Teams action-layer execution with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/actions/teamsActionRegistry.test.tspnpm --dir server exec tsc -p tsconfig.json --noEmit --pretty falsepnpm --dir packages/integrations typecheck
-
(2026-03-07) Verified Teams bot foundation and lookup commands with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/bot/teamsBotHandler.test.ts src/app/api/teams/bot/messages/route.test.ts src/test/unit/lib/teams/actions/teamsActionRegistry.test.tspnpm --dir server exec tsc -p tsconfig.json --noEmit --pretty false
-
(2026-03-07) Verified Teams bot mutation commands with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/bot/teamsBotHandler.test.ts src/app/api/teams/bot/messages/route.test.ts src/test/unit/lib/teams/actions/teamsActionRegistry.test.tspnpm --dir server exec tsc -p tsconfig.json --noEmit --pretty false
-
(2026-03-07) Verified Teams bot approval commands with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/actions/teamsActionRegistry.test.ts src/test/unit/lib/teams/bot/teamsBotHandler.test.tspnpm --dir server exec tsc -p tsconfig.json --noEmit --pretty false
-
(2026-03-07) Verified Teams message-extension search with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/actions/teamsActionRegistry.test.ts src/test/unit/lib/teams/messageExtension/teamsMessageExtensionHandler.test.ts src/app/api/teams/message-extension/query/route.test.tspnpm --dir server exec tsc -p tsconfig.json --noEmit --pretty false
-
(2026-03-07) Verified Teams message-extension action transport and focused command definitions with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/messageExtension/teamsMessageExtensionHandler.test.ts src/app/api/teams/message-extension/query/route.test.ts ../packages/integrations/src/actions/integrations/teamsPackageActions.test.tspnpm --dir server exec tsc -p tsconfig.json --noEmit --pretty falsepnpm --dir packages/integrations typecheck
-
(2026-03-07) Verified Teams message-extension pagination with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/messageExtension/teamsMessageExtensionHandler.test.tspnpm --dir server exec tsc -p tsconfig.json --noEmit --pretty false
-
(2026-03-07) Verified Teams message-extension quick-action surfacing with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/messageExtension/teamsMessageExtensionHandler.test.tspnpm --dir server exec tsc -p tsconfig.json --noEmit --pretty false
-
(2026-03-07) Verified Teams message-extension shared surface metadata and PSA-first search access patterns with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/messageExtension/teamsMessageExtensionHandler.test.tspnpm --dir server exec tsc -p tsconfig.json --noEmit --pretty false
-
(2026-03-07) Verified Teams message-to-ticket task-card creation, inline submit, message metadata persistence, and duplicate-submit replay with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/messageExtension/teamsMessageExtensionHandler.test.tspnpm --dir server exec tsc -p tsconfig.json --noEmit --pretty false
-
(2026-03-07) Completed
F140,F141,F142, andF143by teachingserver/src/lib/teams/bot/teamsBotHandler.tsto parseassign ticketcommands, defaultassign ticket <ticket-id>to self-assignment, resolve other assignees from active internal users with explicituser:readgating, and return the shared action result with an assignee-specific success summary plus Teams-tab/full-PSA links. -
(2026-03-07) Completed
F144,F145, andF146by teaching the same bot handler to parseadd note <ticket-id>: <note>, preserve ticket context when the note body is missing, execute the sharedadd_noteTeams action, and return the saved-note confirmation with follow-up deep links. -
(2026-03-07) Completed
F147,F148, andF149by extending the bot handler withreply to contact <ticket-id>: <reply>, preserving ticket context when only the ticket reference is present, executing the sharedreply_to_contactaction, and returning the customer-reply confirmation with Teams-tab/full-PSA links. -
(2026-03-07) Completed
F150,F151, andF152by extending the bot handler withlog time ticket|task <id> <duration>: <note>, parsing minute/hour durations into the sharedlog_timeaction input, defaulting the time entry to the trailing duration ending now, and supporting both ticket and project-task targets with the same shared mutation path. -
(2026-03-07) Completed
T279throughT286with focused bot-handler tests covering assignment success, assignee lookup, missing-ticket validation, user-read permission failures during assignee resolution, and safe not-found mutation results for bot action handoff. -
(2026-03-07) Completed
T287throughT292with bot-handler tests covering note-command parsing, missing-note remediation that preserves ticket context, sharedadd_noteexecution, and successful follow-up link rendering after note creation. -
(2026-03-07) Completed
T293throughT298with bot-handler tests covering reply-command parsing, missing-reply remediation, sharedreply_to_contactexecution, and successful follow-up link rendering after a customer-visible reply is created. -
(2026-03-07) Completed
T299throughT304with bot-handler tests covering missing work-item/duration remediation, shared ticket/tasklog_timeexecution, duration-and-note normalization, and follow-up link rendering after Teams time entry creation. -
(2026-03-07) Completed
F153by adding a sharedmy_approvalsTeams action plus bot support formy approvals, reusing the Manager Approval dashboard scope rules so the bot lists only approval items the signed-in approver can review. -
(2026-03-07) Completed
F154by extending the bot parser/UX withapprove approval <id>andrequest changes/reject approval <id>: <comment>commands that execute the sharedapproval_responseaction and return Teams-tab/full-PSA follow-up links. -
(2026-03-07) Completed
T305andT306with registry + bot coverage for pending-approval lookup, permission failures, approval summaries, and approval-result shortcut rendering. -
(2026-03-07) Completed
T307andT308with bot-handler coverage for approval approval/request-changes execution plus missing-reference and missing-comment remediation. -
(2026-03-07) Completed
F155,F156,F157,F158,F159, andF160by adding the SDK-free Teams message-extension route inserver/src/app/api/teams/message-extension/query/route.tsplusserver/src/lib/teams/messageExtension/teamsMessageExtensionHandler.ts, which resolves tenant and linked-user context, acceptssearchRecordsqueries from compose/command-box contexts, and returns ticket/task/contact/approval hero-card results through the sharedopen_recordTeams action mapping. -
(2026-03-07) Completed
T309throughT320withserver/src/app/api/teams/message-extension/query/route.test.tsandserver/src/test/unit/lib/teams/messageExtension/teamsMessageExtensionHandler.test.ts, covering route delegation, invalid JSON handling, tenant/user-gated search aggregation, permission-based suppression, empty-state recovery, and compose/command-box context enforcement. -
(2026-03-07) Completed
F161by extendingserver/src/lib/teams/messageExtension/teamsMessageExtensionHandler.tsto acceptcomposeExtension/fetchTaskandcomposeExtension/submitActionrequests forcreateTicketFromMessageandupdateFromMessage, returning Teams-safe task-module and task-message responses from message context. -
(2026-03-07) Completed
F162,F163,F165,F166,F168,F169,F171,F172,F173,F174,F175, andF176by tightening the message-extension transport around tenant-scoped/user-scoped search execution, compact shared-result card rendering, Teams-tab/full-PSA deep links, inactive-tenant remediation, focused command definitions, and sharedopen_recordresult mapping. -
(2026-03-07) Completed
T321throughT352with focused handler/package coverage for message-context action requests, tenant/user resolution, permission-scoped search behavior, compact result cards, deep-link buttons, inactive-tenant remediation, focused command definitions, and shared result mapping. -
(2026-03-07) Completed
F164by teachingserver/src/lib/teams/messageExtension/teamsMessageExtensionHandler.tsto honor TeamsqueryOptions.skip/countsearch windows and validate pagination input before returning a paged attachment list. -
(2026-03-07) Completed
T327andT328with handler coverage for paged ticket result windows plus recoverable invalid-pagination messaging. -
(2026-03-07) Completed
F167andF170by extending message-extension search cards to append tenant-allowed mutation titles fromlistAvailableTeamsActions(...), so search results surface only currently supported quick actions for the current entity and tenant. -
(2026-03-07) Completed
T333,T334,T339, andT340with handler coverage for available-action summaries plus suppression of unavailable tenant-disabled actions. -
(2026-03-07) Completed
F177andF178by asserting message-extension search continues to invoke the shared Teams action layer withsurface: 'message_extension'while reusing existing PSA ticket, contact, task, and approval access paths instead of introducing a Teams-only index. -
(2026-03-07) Completed
T353,T354,T355, andT356with handler coverage for shared invoking-surface metadata plus explicit assertions againstTicketService.search,ContactService.search, tenant task queries, andlistPendingApprovalsForTeams(...). -
(2026-03-07) Completed
F179,F180, andF181by extendingserver/src/lib/teams/messageExtension/teamsMessageExtensionHandler.tssocreateTicketFromMessagenow returns a real adaptive-card task form with captured message subject/body context, tenant-backed board/status/client/contact choices, and default-backed ticket field handling for inline ticket creation. -
(2026-03-07) Completed
F182,F183, andF184by executing inline ticket creation through the shared ticket model, storing Teams source-message/idempotency metadata intickets.attributes, replaying duplicate submits safely by that idempotency key, and reusing sharedopen_recordresult links for post-create Teams-tab/full-PSA confirmation. -
(2026-03-07) Completed
T357throughT368with handler coverage for create-ticket task-card rendering, permission/setup guards, inline ticket creation, source-metadata persistence, confirmation deep links, invalid input recovery, and duplicate-submit replay. -
(2026-03-07) Completed
F185,F186,F187,F188, andF189by extendingserver/src/lib/teams/messageExtension/teamsMessageExtensionHandler.tssoupdateFromMessagenow opens a real adaptive-card task form, accepts ticket/project-task targets, routes ticket note/reply mutations through the shared Teams action registry, and persists Teams message provenance intocomments.metadata. -
(2026-03-07) Completed
F190,F191,F192,F193,F194, andF195by returning shared Teams-tab/full-PSA confirmation links after successful update actions, preserving permission/setup failures as recoverable task responses, prefilling update content from the selected Teams message, and offering explicit Teams-tab handoff paths for richer create/update workflows. -
(2026-03-07) Completed
T369throughT390with message-extension handler coverage for update task-card rendering, ticket/task targeting, internal-note and customer-reply execution, provenance metadata flow, recoverable validation/permission failures, and richer Teams-tab handoff behavior. -
(2026-03-07) Verified Teams message-to-update task-card rendering, shared ticket mutations, provenance metadata flow, and Teams-tab handoff behavior with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/messageExtension/teamsMessageExtensionHandler.test.tscd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/actions/teamsActionRegistry.test.tspnpm --dir server exec tsc -p tsconfig.json --noEmit --pretty false
-
(2026-03-07) Completed
F196by moving both message-driven submit paths onto dedicated shared registry actions inserver/src/lib/teams/actions/teamsActionRegistry.ts, leaving the message-extension handler responsible only for task-module UI, field prefilling, and final task-response rendering. -
(2026-03-07) Completed
T391andT392with handler coverage provingcreateTicketFromMessageandupdateFromMessagesubmits delegate to the shared action layer and still surface recoverable Teams-safe failures when the shared action rejects the request. -
(2026-03-07) Verified shared message-driven action delegation with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/messageExtension/teamsMessageExtensionHandler.test.ts src/test/unit/lib/teams/actions/teamsActionRegistry.test.tspnpm --dir server exec tsc -p tsconfig.json --noEmit --pretty false
-
(2026-03-07) The shared quick-action slice can stay transport-thin:
server/src/lib/teams/quickActions/teamsQuickActionHandler.tsowns adaptive-card/task-module rendering and submit handling, while the route only parses JSON and delegates into the shared Teams action registry plusopen_recordhandoff links. -
(2026-03-07) Completed
F197throughF210by addingserver/src/lib/teams/quickActions/teamsQuickActionHandler.tsandserver/src/app/api/teams/quick-actions/route.ts, which render minimal adaptive-card/task-module forms for assign-ticket, add-note, reply-to-contact, log-time, and approval-response flows; prefill from Teams message/entity context; validate required inputs before submit; execute the shared Teams action layer on submit; return Teams-safe success/error/cancel responses; suppress unavailable actions centrally; and hand users off to the Teams tab when the richer record workflow is the safer path. -
(2026-03-07) Completed
T393throughT420withserver/src/app/api/teams/quick-actions/route.test.tsandserver/src/test/unit/lib/teams/quickActions/teamsQuickActionHandler.test.ts, covering route delegation, invalid JSON handling, per-action form rendering, contextual prefills, tenant/user/action gating, shared-action submission, success and recoverable failure responses, cancel/dismiss behavior, allowed-action visibility, and Teams-tab handoff for unavailable or too-complex quick actions. -
(2026-03-07) Verified Teams quick-action adaptive-card flows with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/lib/teams/quickActions/teamsQuickActionHandler.test.ts src/app/api/teams/quick-actions/route.test.tspnpm --dir server exec tsc -p tsconfig.json --noEmit --pretty false
-
(2026-03-07) Verified Teams notification delivery channel, Graph payload mapping, and manifest permission handoff with:
cd server && npx vitest run --config vitest.config.ts src/test/unit/internal-notifications/teamsNotificationDelivery.test.ts src/test/unit/internal-notifications/internalNotificationBroadcaster.test.ts ../packages/integrations/src/actions/integrations/teamsPackageActions.test.tspnpm --dir packages/notifications typecheckpnpm --dir server exec tsc -p tsconfig.json --noEmit --pretty false
-
(2026-03-07) Next unchecked feature after this slice is
F231(Permissions: only authorized tenant admins can manage Microsoft profiles and Teams setup). -
(2026-03-07) Completed
F211throughF230by addingpackages/notifications/src/realtime/teamsNotificationDelivery.tsand refactoringpackages/notifications/src/realtime/internalNotificationBroadcaster.tsso every internal notification can attempt an independent Teams activity-feed delivery path alongside Redis in-app delivery, gated by active Teams setup, personal-notification capability/category settings, linked Microsoft accounts, and tenant-selected Teams profile credentials. -
(2026-03-07) Completed
T421throughT460withserver/src/test/unit/internal-notifications/teamsNotificationDelivery.test.ts,server/src/test/unit/internal-notifications/internalNotificationBroadcaster.test.ts, and updatedpackages/integrations/src/actions/integrations/teamsPackageActions.test.ts, covering category classification, Teams deep-link reuse, recipient linkage, sent/delivered/failed workflow events, safe suppression on disabled/missing prerequisites, channel independence from Redis delivery, and the required Teams manifest permission for activity-feed sends. -
(2026-03-07) Archiving a Microsoft profile only checked the default-profile compatibility guard. It did not yet block the case where Teams explicitly selected a non-default profile, and there was no backend delete action for applying the same guard to deletions.
-
(2026-03-07) Completed
F231throughF248by adding binding-aware Microsoft profile lifecycle guards inpackages/integrations/src/actions/integrations/microsoftActions.ts, exporting a newdeleteMicrosoftProfileaction, and re-verifying the existing Teams surface authorization/fallback behavior that was already present across Teams tab, bot, message extension, quick-action, and profile-compatibility code. -
(2026-03-07) Completed
T461throughT496with updated integrations action tests plus re-verification of the existing Teams surface suites, covering tenant-admin gating for Microsoft/Teams settings, cross-surface authorization enforcement, mutation denial for read-only users, tenant-scoped search/lookup behavior, legacy Microsoft compatibility APIs/bindings, Teams-profile rebind safety, Teams-selected profile archive/delete guards, client-user rejection, guided not-configured remediation, inactive-integration action suppression, and tenant allowed-action enforcement across bot and message extension. -
(2026-03-07) Verified Teams permission/compatibility/fallback regression coverage with:
cd server && npx vitest run --config vitest.config.ts ../packages/integrations/src/actions/integrations/microsoftActions.test.ts ../packages/integrations/src/actions/integrations/microsoftConsumerBindings.test.ts ../packages/integrations/src/actions/integrations/teamsActions.test.ts src/test/unit/lib/teams/actions/teamsActionRegistry.test.ts src/test/unit/lib/teams/resolveTeamsTabAccessState.test.ts src/test/unit/lib/teams/resolveTeamsTabAuthState.test.ts src/test/unit/lib/teams/bot/teamsBotHandler.test.ts src/test/unit/lib/teams/messageExtension/teamsMessageExtensionHandler.test.ts src/test/unit/lib/teams/quickActions/teamsQuickActionHandler.test.tspnpm --dir server exec tsc -p tsconfig.json --noEmit --pretty falsepnpm --dir packages/integrations typecheck
-
(2026-03-07) Completed
T497throughT516by re-verifying the existing focused suites that already exercise the end-to-end acceptance paths for migration compatibility, Teams package identity, SSO tab entry, notification deep-link routing, bot lookup/mutation/approval commands, message-extension search and message-driven actions, quick-action submit flows, Teams notification delivery/suppression, and cross-surface unauthorized/client-user rejection. -
(2026-03-07) Verified Teams acceptance-scenario coverage with:
cd server && npx vitest run --config vitest.config.ts ../packages/integrations/src/actions/integrations/microsoftActions.test.ts ../packages/integrations/src/actions/integrations/microsoftConsumerBindings.test.ts ../packages/integrations/src/actions/integrations/teamsActions.test.ts ../packages/integrations/src/actions/integrations/teamsPackageActions.test.ts src/test/unit/lib/teams/resolveTeamsTabAuthState.test.ts src/test/unit/lib/teams/resolveTeamsTabAccessState.test.ts src/test/unit/lib/teams/resolveTeamsTabDestination.test.ts src/test/unit/app/teams/tab/page.test.tsx src/test/unit/lib/teams/actions/teamsActionRegistry.test.ts src/test/unit/lib/teams/bot/teamsBotHandler.test.ts src/app/api/teams/bot/messages/route.test.ts src/test/unit/lib/teams/messageExtension/teamsMessageExtensionHandler.test.ts src/app/api/teams/message-extension/query/route.test.ts src/test/unit/lib/teams/quickActions/teamsQuickActionHandler.test.ts src/app/api/teams/quick-actions/route.test.ts src/test/unit/internal-notifications/teamsNotificationDelivery.test.ts src/test/unit/internal-notifications/internalNotificationBroadcaster.test.tspnpm --dir server exec tsc -p tsconfig.json --noEmit --pretty falsepnpm --dir packages/integrations typecheckpnpm --dir packages/notifications typecheck
-
(2026-03-07) No unchecked feature or test items remain in the Microsoft Teams Integration V1 plan.