Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
46 KiB
46 KiB
Scratchpad — Calendar Sync Enterprise Migration and Microsoft Profile Explicit Bindings
- Plan slug:
calendar-sync-enterprise-migration-and-microsoft-profile-explicit-bindings - Created:
2026-03-09
What This Is
Follow-on implementation notes for moving calendar sync to EE-only ownership and finishing the Microsoft profile explicit-binding cleanup.
Decisions
- (2026-03-09) Calendar sync moves to EE end to end, including integration settings, user-profile calendar settings, OAuth callbacks, runtime services, webhook maintenance, and subscriber execution.
- (2026-03-09) Shared Microsoft profile storage remains shared infrastructure; this plan does not create a second EE-only Microsoft credential model.
- (2026-03-09) CE Microsoft profile UX should describe and bind only MSP SSO.
- (2026-03-09) EE Microsoft profile UX should expose MSP SSO plus email, calendar, and Teams consumers.
- (2026-03-09) Explicit consumer bindings are the source of truth; legacy compatibility/default-consumer wording should be removed from the target design.
- (2026-03-09) CE keeps only stub or wrapper entrypoints where route or import boundaries require them, following the existing Entra and Teams EE patterns.
- (2026-03-09) The Entra and Teams CE-stub plus EE-delegation pattern is the precedent for calendar route wrappers: stable shared URL,
501JSON in CE, dynamic EE delegation in enterprise. - (2026-03-09) Canonical unavailable copy for calendar HTTP stubs should be
Calendar sync is only available in Enterprise Edition.so CE fails clearly before any token exchange, provider write, or sync side effect. - (2026-03-09) One edition-aware consumer matrix should drive both UI visibility and action-layer enforcement: CE shows only
msp_sso; EE showsmsp_sso,email,calendar, andteams.
Discoveries / Constraints
- (2026-03-09)
packages/integrations/src/components/settings/integrations/IntegrationsSettingsPage.tsxcurrently renders Calendar as a shared category and rendersMicrosoftIntegrationSettingsdirectly underProviders. - (2026-03-09)
server/src/components/settings/profile/UserProfile.tsxcurrently renders aCalendartab throughCalendarIntegrationsSettings, so the EE move has to include profile settings, not just admin settings. - (2026-03-09) Shared calendar callback routes currently live at
server/src/app/api/auth/google/calendar/callback/route.tsandserver/src/app/api/auth/microsoft/calendar/callback/route.ts. - (2026-03-09) Shared calendar runtime code exists in both
server/src/services/calendar/*andpackages/integrations/src/services/calendar/*, so the extraction needs an ownership pass across settings, service exports, adapters, and maintenance jobs. - (2026-03-09)
packages/integrations/src/actions/integrations/microsoftActions.tsstill contains legacy compatibility semantics such asLEGACY_MICROSOFT_PROFILE_CONSUMERS, compatibility backfill logic, default-profile copy, and fallback-based consumer resolution. - (2026-03-09)
MicrosoftIntegrationSettings.tsxstill contains the legacy Microsoft consumers pane and default-compatibility copy even though the binding table and binding actions already exist. - (2026-03-09) The current binding table is shared at
server/migrations/20260307143000_create_microsoft_profile_consumer_bindings.cjs, and Teams already depends onselected_profile_idplus binding-aware resolution. - (2026-03-09) There are no screenshots checked into
ee/docsfor this plan folder or nearby migration docs, so the documentation cleanup for Calendar ownership is entirely text and runbook based. - (2026-03-09) Calendar public entry routes also include
server/src/app/api/calendar/webhooks/google/route.tsandserver/src/app/api/calendar/webhooks/microsoft/route.ts, so webhook maintenance has to follow the same CE stub or EE delegator rule as OAuth callbacks. - (2026-03-09) Shared auth/runtime precedent already exists for Microsoft consumers:
packages/auth/src/lib/sso/mspSsoResolution.tspackages/auth/src/lib/sso/teamsMicrosoftProviderResolution.tsee/server/src/lib/auth/teamsMicrosoftProviderResolution.ts
- (2026-03-09) Existing doc-contract precedent lives at
server/src/test/unit/docs/teamsEnterpriseOnlyMigrationPlan.contract.test.ts, which is the right pattern for validating this plan folder as it evolves. - (2026-03-09)
packages/integrations/src/actions/calendarActions.tswas converted into an edition-gated EE delegator layer. Shared action entrypoints no longer importCalendarProviderService,CalendarSyncService,CalendarWebhookMaintenanceService, or calendar adapters directly. - (2026-03-09) The new EE action implementation currently lives at
packages/ee/src/lib/actions/integrations/calendarActions.ts. It centralizes provider CRUD, manual sync, conflict resolution, sync status reads, and manual Microsoft webhook renewal behind the@enterprisealias boundary. - (2026-03-09)
server/src/lib/actions/calendarActions.tsnow exists as a stable server-side re-export of@alga-psa/integrations/actions/calendarActions, which keeps existing server imports/tests working while the shared package owns only the delegator boundary. - (2026-03-09) The initial action-delegator slice completed the CE CRUD-entrypoint cutover (
F074); later slices then moved subscriber registration and the concrete EE runtime service tree so the live calendar runtime no longer depends on sharedserver/src/services/calendar/*. - (2026-03-09)
server/src/lib/eventBus/subscribers/calendarSyncSubscriber.tsis now a CE no-op plus EE delegator. The concrete schedule-entry subscriber moved topackages/ee/src/lib/eventBus/subscribers/calendarSyncSubscriber.ts, so CE startup no longer loadsCalendarSyncServiceorCalendarProviderServicethrough subscriber registration. - (2026-03-09) Because callbacks, webhooks, maintenance jobs, action entrypoints, subscriber registration, and the concrete EE service tree now all terminate under EE-owned modules, shared calendar sync services/adapters no longer have a live CE runtime entrypoint and EE no longer executes through shared
server/src/services/calendar/*entrypoints. - (2026-03-09)
server/src/test/integration/calendar/scheduleAutoSync.integration.test.tsstill depends on a local PostgreSQL test instance at port5438; targeted validation for the subscriber slice therefore uses deterministic unit tests (calendarSyncSubscriber.delegator.test.tsandcalendarSyncSubscriber.ee.test.ts) instead of the DB-backed integration suite in this environment. - (2026-03-09) The concrete EE calendar runtime now lives under
packages/ee/src/lib/services/calendar/*. EE callbacks, webhook routes, maintenance jobs, subscriber registration, and action entrypoints all import that package-owned service tree through@enterprise/lib/services/calendar/*. - (2026-03-09) The EE runtime ownership contract now explicitly covers:
- webhook renewal and maintenance jobs through
packages/ee/src/lib/jobs/handlers/calendarWebhookMaintenanceHandler.tsandpackages/ee/src/lib/services/calendar/CalendarWebhookMaintenanceService.ts - provider secret handling through
packages/ee/src/lib/services/calendar/CalendarProviderService.ts - adapter selection and provider-type branching through
packages/ee/src/lib/services/calendar/CalendarSyncService.tsandpackages/ee/src/lib/services/calendar/CalendarWebhookProcessor.ts - background schedule-entry subscriber execution through
packages/ee/src/lib/eventBus/subscribers/calendarSyncSubscriber.ts
- webhook renewal and maintenance jobs through
Commands / Runbooks
- (2026-03-09) Scaffold plan:
python3 /Users/roberisaacs/.codex/skills/alga-plan/scripts/scaffold_plan.py "Calendar Sync Enterprise Migration and Microsoft Profile Explicit Bindings" --slug calendar-sync-enterprise-migration-and-microsoft-profile-explicit-bindings
- (2026-03-09) Validate plan:
python3 /Users/roberisaacs/.codex/skills/alga-plan/scripts/validate_plan.py ee/docs/plans/2026-03-09-calendar-sync-enterprise-migration-and-microsoft-profile-explicit-bindings
- (2026-03-09) Useful discovery queries:
rg -n "CalendarIntegrationsSettings|CalendarSyncService|CalendarProviderService|microsoft_profile_consumer_bindings|LEGACY_MICROSOFT_PROFILE_CONSUMERS|MicrosoftIntegrationSettings" packages server eerg -n "api/auth/.*/calendar/callback|teams|msp_sso" server packages ee
- (2026-03-09) Focused validation suites expected for this migration:
- settings/profile visibility tests for CE versus EE calendar entrypoints
- calendar callback and webhook wrapper tests for unavailable versus delegated behavior
- Microsoft profile UI contract tests for CE-only MSP SSO versus EE consumer visibility
- Microsoft binding action tests for edition visibility, tenant scoping, archive guards, and fallback removal
- ownership/package-boundary tests for shared wrapper imports versus EE runtime modules
- migration/documentation contract tests for shared binding schema and this plan folder
- (2026-03-09) Latest validator result:
python3 /Users/roberisaacs/.codex/skills/alga-plan/scripts/validate_plan.py ee/docs/plans/2026-03-09-calendar-sync-enterprise-migration-and-microsoft-profile-explicit-bindings- Result: valid (
216features,432tests)
- (2026-03-09) Focused implementation checks for the calendar visibility slice:
pnpm vitest run --coverage.enabled=false src/test/unit/components/integrations/IntegrationsSettingsPage.calendar.test.tsx src/test/unit/components/profile/UserProfile.calendar.contract.test.ts ../packages/integrations/src/lib/calendarAvailability.test.tspnpm vitest run --coverage.enabled=false src/test/unit/components/integrations/IntegrationsSettingsPage.teams.test.tsxpnpm exec tsc -p tsconfig.json --noEmit --pretty false
- (2026-03-09) Focused implementation checks for the calendar callback delegator slice:
pnpm vitest run --coverage.enabled=false src/test/unit/api/calendarCallbackRoutes.delegator.test.tspnpm exec tsc -p tsconfig.json --noEmit --pretty false
- (2026-03-09) Focused implementation checks for the calendar webhook delegator slice:
pnpm vitest run --coverage.enabled=false src/test/unit/api/calendarWebhookRoutes.delegator.test.ts src/test/unit/api/calendarCallbackRoutes.delegator.test.tspnpm exec tsc -p tsconfig.json --noEmit --pretty false
- (2026-03-09) Focused implementation checks for the calendar maintenance delegator slice:
pnpm vitest run --coverage.enabled=false src/test/unit/api/calendarCallbackRoutes.delegator.test.ts src/test/unit/api/calendarWebhookRoutes.delegator.test.ts src/test/unit/jobs/calendarWebhookMaintenanceHandler.delegator.test.tspnpm exec tsc -p tsconfig.json --noEmit --pretty false
- (2026-03-09) Focused implementation checks for the calendar action delegator slice:
pnpm vitest run --coverage.enabled=false src/test/unit/calendar/calendarActions.ee.contract.test.ts src/test/unit/calendar/calendarActions.sync.test.tspnpm exec tsc -p tsconfig.json --noEmit --pretty false
- (2026-03-09) Focused implementation checks for the calendar subscriber delegator slice:
pnpm vitest run --coverage.enabled=false src/test/unit/calendar/calendarSyncSubscriber.delegator.test.ts src/test/unit/calendar/calendarSyncSubscriber.ee.test.tspnpm exec tsc -p tsconfig.json --noEmit --pretty false
- (2026-03-09) Focused implementation checks for the EE runtime ownership slice:
pnpm vitest run --coverage.enabled=false src/test/unit/calendar/calendarActions.ceBoundary.test.ts src/test/unit/calendar/calendarActions.ee.contract.test.ts src/test/unit/calendar/calendarActions.sync.test.ts src/test/unit/calendar/calendarSyncSubscriber.delegator.test.ts src/test/unit/calendar/calendarSyncSubscriber.ee.test.ts src/test/unit/calendar/calendarRuntimeOwnership.contract.test.ts src/test/unit/api/calendarCallbackRoutes.delegator.test.ts src/test/unit/api/calendarWebhookRoutes.delegator.test.ts src/test/unit/jobs/calendarWebhookMaintenanceHandler.delegator.test.tspnpm exec tsc -p tsconfig.json --noEmit --pretty false
Links / References
- Prior Microsoft profile and Teams plan:
ee/docs/plans/2026-03-07-microsoft-teams-integration-v1/
- Prior Teams EE-boundary follow-on plan:
ee/docs/plans/2026-03-08-microsoft-teams-enterprise-only-migration/
- Current shared settings composition:
packages/integrations/src/components/settings/integrations/IntegrationsSettingsPage.tsx
- Current shared Microsoft profile UI:
packages/integrations/src/components/settings/integrations/MicrosoftIntegrationSettings.tsx
- Current shared Microsoft actions:
packages/integrations/src/actions/integrations/microsoftActions.ts
- Current shared profile page:
server/src/components/settings/profile/UserProfile.tsx
- Current shared calendar callback routes:
server/src/app/api/auth/google/calendar/callback/route.tsserver/src/app/api/auth/microsoft/calendar/callback/route.ts
- Current EE-owned calendar entrypoints after the first two migration slices:
packages/integrations/src/components/settings/integrations/CalendarEnterpriseIntegrationSettings.tsx@enterprise/components/settings/profile/CalendarProfileSettingsee/server/src/app/api/auth/google/calendar/callback/route.tsee/server/src/app/api/auth/microsoft/calendar/callback/route.ts
- Current shared calendar webhook routes:
server/src/app/api/calendar/webhooks/google/route.tsserver/src/app/api/calendar/webhooks/microsoft/route.ts
- Current shared Teams/Entra EE-boundary precedent:
server/src/app/api/teams/_ceStub.tsserver/src/app/api/teams/_eeDelegator.tsserver/src/app/api/integrations/entra/_ceStub.tsserver/src/test/unit/api/teamsRoutes.delegator.test.tsserver/src/test/unit/api/entraRoutes.delegator.test.ts
Open Questions
- (2026-03-09) If Outlook inbound email remains CE-supported long term, decide whether its explicit Microsoft binding should stay EE-only in provider UI or move to a consumer-owned CE surface later. The current plan assumes the Microsoft profile page itself shows only MSP SSO in CE.
Calendar EE Move Inventory
- Settings composition:
packages/integrations/src/components/settings/integrations/IntegrationsSettingsPage.tsxpackages/integrations/src/components/calendar/CalendarIntegrationsSettings.tsxpackages/integrations/src/components/calendar/index.ts
- User profile surface:
server/src/components/settings/profile/UserProfile.tsx
- Shared route wrappers that must become CE stubs or EE delegators:
server/src/app/api/auth/google/calendar/callback/route.tsserver/src/app/api/auth/microsoft/calendar/callback/route.tsserver/src/app/api/calendar/webhooks/google/route.tsserver/src/app/api/calendar/webhooks/microsoft/route.ts
- Calendar callback delegator helpers and EE-owned route files added for the second migration slice:
server/src/app/api/auth/calendar/_ceStub.tsserver/src/app/api/auth/calendar/_eeDelegator.tspackages/ee/src/app/api/auth/google/calendar/callback/route.tspackages/ee/src/app/api/auth/microsoft/calendar/callback/route.tsee/server/src/app/api/auth/google/calendar/callback/route.tsee/server/src/app/api/auth/microsoft/calendar/callback/route.ts
- Calendar webhook delegator helpers and EE-owned route files added for the third migration slice:
server/src/app/api/calendar/_ceStub.tsserver/src/app/api/calendar/_eeDelegator.tspackages/ee/src/app/api/calendar/webhooks/google/route.tspackages/ee/src/app/api/calendar/webhooks/microsoft/route.tsee/server/src/app/api/calendar/webhooks/google/route.tsee/server/src/app/api/calendar/webhooks/microsoft/route.ts
- Calendar maintenance handler boundary added for the fourth migration slice:
server/src/lib/jobs/handlers/calendarWebhookMaintenanceHandler.tspackages/ee/src/lib/jobs/handlers/calendarWebhookMaintenanceHandler.ts
- Calendar UI visibility and EE-entry helpers added for the first migration slice:
packages/integrations/src/lib/calendarAvailability.tspackages/integrations/src/components/settings/integrations/CalendarEnterpriseIntegrationSettings.tsxpackages/ee/src/components/settings/integrations/CalendarIntegrationsSettings.tsxee/server/src/components/settings/integrations/CalendarIntegrationsSettings.tsxpackages/ee/src/components/settings/profile/CalendarProfileSettings.tsxee/server/src/components/settings/profile/CalendarProfileSettings.tsx
- Shared runtime code that still owns live calendar behavior after the action delegator slice:
packages/integrations/src/services/calendar/CalendarProviderService.tspackages/integrations/src/services/calendar/CalendarSyncService.tspackages/integrations/src/services/calendar/CalendarWebhookProcessor.tspackages/integrations/src/services/calendar/CalendarWebhookMaintenanceService.tspackages/integrations/src/services/calendar/providers/GoogleCalendarAdapter.tspackages/integrations/src/services/calendar/providers/MicrosoftCalendarAdapter.tspackages/integrations/src/services/calendar/providers/base/BaseCalendarAdapter.ts
- Shared action boundary files added for the fifth migration slice:
packages/integrations/src/actions/calendarActions.tspackages/ee/src/lib/actions/integrations/calendarActions.tsserver/src/lib/actions/calendarActions.ts
- Shared subscriber boundary files added for the sixth migration slice:
server/src/lib/eventBus/subscribers/calendarSyncSubscriber.tspackages/ee/src/lib/eventBus/subscribers/calendarSyncSubscriber.ts
- EE-owned concrete runtime modules added for the seventh migration slice:
packages/ee/src/lib/services/calendar/CalendarProviderService.tspackages/ee/src/lib/services/calendar/CalendarSyncService.tspackages/ee/src/lib/services/calendar/CalendarWebhookMaintenanceService.tspackages/ee/src/lib/services/calendar/CalendarWebhookProcessor.tspackages/ee/src/lib/services/calendar/providers/GoogleCalendarAdapter.tspackages/ee/src/lib/services/calendar/providers/MicrosoftCalendarAdapter.tspackages/ee/src/lib/services/calendar/providers/base/BaseCalendarAdapter.tspackages/ee/src/lib/services/CalendarProviderService.tspackages/ee/src/lib/services/CalendarSyncService.ts
- Server runtime ownership hotspots that must stop executing in CE:
server/src/lib/eventBus/subscribers/calendarSyncSubscriber.tsserver/src/lib/jobs/handlers/calendarWebhookMaintenanceHandler.tsserver/src/services/CalendarProviderService.tsserver/src/services/CalendarSyncService.tsserver/src/services/calendar/CalendarProviderService.tsserver/src/services/calendar/CalendarSyncService.tsserver/src/services/calendar/CalendarWebhookMaintenanceService.tsserver/src/services/calendar/CalendarWebhookProcessor.ts
- Existing tests that should evolve with the EE cutover:
server/src/test/integration/calendar/manualSync.integration.test.tsserver/src/test/integration/calendar/scheduleAutoSync.integration.test.tsserver/src/test/integration/calendar/webhookProcessing.integration.test.tsserver/src/test/unit/calendar/calendarActions.sync.test.tsserver/src/test/unit/api/calendarCallbackRoutes.delegator.test.tsserver/src/test/unit/api/calendarWebhookRoutes.delegator.test.tsserver/src/test/unit/jobs/calendarWebhookMaintenanceHandler.delegator.test.ts
Microsoft Binding Cleanup Inventory
- Shared UI and contracts:
packages/integrations/src/components/settings/integrations/MicrosoftIntegrationSettings.tsxpackages/integrations/src/components/settings/integrations/MicrosoftIntegrationSettings.contract.test.tsx
- Shared action and helper layer:
packages/integrations/src/actions/integrations/microsoftActions.tspackages/integrations/src/actions/integrations/microsoftActions.test.tspackages/integrations/src/actions/integrations/mspSsoDomainActions.ts
- Shared auth/runtime consumers that must stay binding-driven:
packages/auth/src/lib/sso/mspSsoResolution.tspackages/auth/src/lib/sso/teamsMicrosoftProviderResolution.tsserver/src/app/api/auth/msp/sso/discover/route.tsserver/src/app/api/auth/msp/sso/resolve/route.tsee/server/src/lib/auth/teamsMicrosoftProviderResolution.ts
- Shared schema and migration coverage:
server/migrations/20260307143000_create_microsoft_profile_consumer_bindings.cjsserver/src/test/unit/migrations/microsoftConsumerBindingsMigration.test.ts
Unsupported Edge States / Manual Cleanup
- Tenants with an active Microsoft calendar provider but no explicit
calendarbinding should be backfilled or rebound during migration; the steady-state runtime should not silently fall back tois_default. - Tenants with archived Microsoft profiles still bound to active consumers should hit archive/delete guards until the binding is reassigned or cleared.
- If Outlook email temporarily retains fallback behavior, that fallback must stay isolated and documented as migration-only cleanup work instead of appearing in CE provider UX.
Review Checklists
- CE review checklist:
- No Calendar category remains visible in
Settings -> Integrations. - No Calendar tab remains visible in
Profile. - Calendar callback and webhook URLs fail clearly with enterprise-only behavior instead of partially executing.
- Microsoft profile UI shows only MSP SSO-oriented copy and one binding control.
- No Calendar category remains visible in
- EE review checklist:
- Calendar settings remain fully configurable from
Settings -> Integrations -> Calendar. - Profile
Calendartab remains functional. - Calendar callback and webhook URLs delegate to EE implementations and preserve current success/error behavior.
- Microsoft profile UI shows MSP SSO, Email, Calendar, and Teams consumer controls.
- Calendar settings remain fully configurable from
- Regression checklist:
- Teams EE cleanup remains intact; no shared Teams runtime is reintroduced.
- MSP SSO discovery and resolve flows still use shared Microsoft profile infrastructure.
- Email binding strategy is explicit and not left to compatibility-default assumptions.
- Archive/delete guards still block profiles that remain actively bound.
- Shared wrappers do not import EE files via raw filesystem-relative paths.
- Final acceptance checklist:
- CE has no live calendar UI or runtime behavior.
- EE retains complete calendar settings, profile, callback, webhook, and runtime behavior.
- Microsoft consumer selection is binding-driven and edition-aware.
- The legacy Microsoft consumers pane and default-compatibility wording are gone.
Working Log
- (2026-03-09) Strengthened the PRD with explicit continuation references to the 2026-03-07 Microsoft/Teams plan and the 2026-03-08 Teams EE-only migration plan.
- (2026-03-09) Added calendar and Microsoft edition-contract matrices, CE stub/EE delegation rules, stable route commitments, intentional deletions, and a final acceptance matrix.
- (2026-03-09) Expanded the scratchpad with file inventories, focused validation suites, unsupported-edge-state notes, and CE/EE/regression review checklists so the migration can proceed without reopening scope discovery.
- (2026-03-09) Implemented the first calendar UI ownership slice:
- added
calendarAvailability.tsas the shared edition-aware source for Calendar category/tab visibility and fallback resolution, - moved settings Calendar rendering behind
CalendarEnterpriseIntegrationSettings, - moved profile Calendar rendering behind
@enterprise/components/settings/profile/CalendarProfileSettings, - removed CE Calendar discovery from settings navigation and profile tabs while preserving EE deep-link behavior.
- added
- (2026-03-09) Updated the CE
packages/eeCalendar settings/profile stubs to return explicit enterprise-only messaging when those wrappers are imported directly, while keeping the normal CE navigation surfaces hidden. - (2026-03-09) Added focused tests for CE/EE Calendar visibility:
- helper tests for category/tab resolution,
IntegrationsSettingsPage.calendar.test.tsxfor CE hiding and EE visibility/provider copy,UserProfile.calendar.contract.test.tsfor the profile EE wrapper boundary.
- (2026-03-09) Implemented the calendar OAuth callback ownership slice:
- moved the live Google and Microsoft calendar callback handlers to
ee/server/src/app/api/auth/.../calendar/callback/route.ts, - replaced the shared callback files with CE stubs plus EE delegators,
- added
packages/eecallback stubs so CE builds remain import-safe, - kept the public callback URLs stable while removing live callback imports from shared route wrappers.
- moved the live Google and Microsoft calendar callback handlers to
- (2026-03-09) Added
calendarCallbackRoutes.delegator.test.tsto verify:- CE returns enterprise-only payloads,
- EE delegates the original
Requestobject to the EE route handlers, - shared callback wrappers no longer import
CalendarProviderService, adapters, or OAuth-state logic directly.
- (2026-03-09) Updated the written migration artifacts to treat Calendar as an EE-owned surface consistently:
- no checked-in screenshots needed refresh,
- the PRD/checklists describe Calendar as EE-only,
- the runbook references now point to the EE-owned settings/profile/callback entrypoints instead of a shared Calendar surface.
- (2026-03-09) Implemented the calendar webhook route ownership slice:
- moved the live Google and Microsoft webhook handlers to
ee/server/src/app/api/calendar/webhooks/.../route.ts, - replaced the shared webhook route files with CE stubs plus EE delegators,
- added
packages/eewebhook stubs so CE builds remain import-safe, - kept the public webhook URLs stable while removing shared re-exports of live webhook handlers.
- moved the live Google and Microsoft webhook handlers to
- (2026-03-09) Extended the route-contract tests to verify:
- CE webhook routes fail clearly with enterprise-only responses,
- EE webhook routes delegate GET/POST/OPTIONS to EE handlers,
- callback tests still cover CE unavailable behavior, EE delegation, and malformed callback input through the EE implementations.
- (2026-03-09) Confirmed middleware/auth handling has no calendar-callback-specific CE feature wiring:
- callback URLs still flow through the generic
/api/auth/*boundary, - webhook URLs remain explicitly unauthenticated for stable external delivery,
- the shared route files no longer advertise live calendar webhook codepaths as CE-owned behavior.
- callback URLs still flow through the generic
- (2026-03-09) Moved the calendar webhook maintenance job entrypoint behind an edition-safe wrapper:
- shared
server/src/lib/jobs/handlers/calendarWebhookMaintenanceHandler.tsnow no-ops in CE and lazy-loads the EE implementation, - live maintenance logic now resides in
packages/ee/src/lib/jobs/handlers/calendarWebhookMaintenanceHandler.ts, - focused tests verify CE no-op behavior, EE delegation, and removal of direct maintenance-service imports from the shared handler wrapper.
- shared
- (2026-03-09) The route runbook references now cover the full current EE ownership chain for calendar network entrypoints:
- callback wrappers delegate to
ee/server/src/app/api/auth/.../calendar/callback/route.ts, - webhook wrappers delegate to
ee/server/src/app/api/calendar/webhooks/.../route.ts, - maintenance job entrypoints delegate through
server/src/lib/jobs/handlers/calendarWebhookMaintenanceHandler.tsintopackages/ee/src/lib/jobs/handlers/calendarWebhookMaintenanceHandler.ts.
- callback wrappers delegate to
- (2026-03-09) Confirmed the Calendar settings UI boundary remains stable:
IntegrationsSettingsPage.tsxrendersCalendarEnterpriseIntegrationSettings,CalendarEnterpriseIntegrationSettings.tsxdynamically imports@enterprise/components/settings/integrations/CalendarIntegrationsSettings,- the shared settings composition no longer imports the concrete Calendar UI directly.
- (2026-03-09) Implemented the Microsoft explicit-binding UI and action cleanup slice:
- added
packages/integrations/src/lib/microsoftConsumerVisibility.tsas the edition-aware source of truth for which Microsoft consumers are visible in CE vs EE, - rewrote
packages/integrations/src/components/settings/integrations/MicrosoftIntegrationSettings.tsxto remove the legacy consumers pane, render one explicit binding row per visible consumer, and make CE copy MSP-SSO-only while EE copy covers MSP SSO, email, calendar, and Teams, - updated
packages/integrations/src/actions/integrations/microsoftActions.tsso CE rejects EE-only consumer binding writes, status payloads expose edition-appropriate redirect/scope metadata, andresolveMicrosoftProfileForConsumer()no longer falls back to the default profile when no explicit binding exists, - kept the legacy binding backfill helper in place for migration-safe rows, so the remaining fallback/backfill cleanup items stay open even though active resolution now uses binding rows.
- added
- (2026-03-09) Added focused Microsoft validation coverage:
packages/integrations/src/lib/microsoftConsumerVisibility.test.tscovers CE/EE consumer visibility contracts,packages/integrations/src/actions/integrations/microsoftConsumerBindings.test.tscovers CE write rejection, EE reassignment, archive/permission guards, and Teams explicit-binding resolution,packages/integrations/src/actions/integrations/microsoftActions.test.tscovers CE vs EE Microsoft status metadata shaping,packages/integrations/src/components/settings/integrations/MicrosoftIntegrationSettings.contract.test.tsxcovers the new explicit-binding UI, CE/EE copy differences, archived-profile filtering, and removal of the legacy compatibility pane/codepath.
- (2026-03-09) Microsoft slice validation commands:
cd server && pnpm vitest run --config vitest.config.ts ../packages/integrations/src/lib/microsoftConsumerVisibility.test.ts ../packages/integrations/src/actions/integrations/microsoftConsumerBindings.test.ts ../packages/integrations/src/actions/integrations/microsoftActions.test.ts ../packages/integrations/src/components/settings/integrations/MicrosoftIntegrationSettings.contract.test.tsx ../src/test/unit/components/integrations/TeamsIntegrationSettings.contract.test.tsxcd server && pnpm exec tsc -p tsconfig.json --noEmit --pretty false
- (2026-03-09) Tightened the binding UX contract so the placeholder option remains a no-op rather than an implicit clear:
MicrosoftIntegrationSettings.contract.test.tsxnow asserts that selecting the empty option does not issue a binding write,- this keeps the current product rule explicit: bindings can be reassigned from this surface, but not silently cleared.
- (2026-03-09) Teams rebinding now invalidates stale Teams install state from the Microsoft binding action itself:
setMicrosoftConsumerBinding()updatesteams_integrations.selected_profile_idwhen the Teams consumer is rebound,- active/installing Teams records are pushed back to
install_pendingand their package metadata, bot/app IDs, and last error are cleared, - the focused binding test also asserts unrelated Microsoft consumer bindings remain unchanged during that rebinding.
- (2026-03-09) Email and calendar rebinding remain on the “prompt reconnection” path in the Microsoft settings UI:
- the consumer descriptors now carry explicit reconnect warnings for Outlook email and Microsoft calendar,
MicrosoftIntegrationSettings.contract.test.tsxasserts those rebind toasts mention re-authorization so the operator-facing reconnection contract stays covered.
- (2026-03-09) Replaced the blanket Microsoft compatibility binding backfill with migration-scoped explicit binding materialization:
packages/integrations/src/actions/integrations/microsoftActions.tsno longer exportsresolveMicrosoftProfileForCompatibilityand no longer inventsemail/calendar/msp_ssobindings from the default profile on every read,- the action layer now materializes explicit binding rows only when legacy state proves a tenant needs them:
msp_ssofrom activemsp_sso_tenant_login_domains,emailfrom existingemail_providersrows withprovider_type = 'microsoft',calendarfrom existingcalendar_providersrows withprovider_type = 'microsoft',
listMicrosoftConsumerBindings()now returns visible consumers withprofileId: nullwhen no explicit binding or migration signal exists, andresolveMicrosoftProfileForConsumer()returnsnullin the same case instead of falling back to the default profile.
- (2026-03-09) Updated the focused Microsoft action tests to lock in the new migration-scoped binding behavior:
microsoftConsumerBindings.test.tsnow covers migration-triggered MSP SSO/email/calendar backfill signals plus the no-legacy-signal path where all migrated consumers remain explicitly unbound,microsoftActions.test.tsnow seeds login-domain/email/calendar legacy state only when asserting migrated consumer visibility, and verifies the public integrations action indexes expose the binding-driven API surface without the removed compatibility export.
- (2026-03-09) Remaining Microsoft runtime gap after this slice:
- active MSP SSO, Outlook email, and Microsoft calendar runtime credential readers still consume mirrored tenant secrets in their own packages/routes,
- the binding table now drives the shared Microsoft settings/action layer and migration materialization logic, but the next slice still has to cut those runtime credential lookups over to explicit binding resolution.
- (2026-03-09) Cut the remaining Microsoft runtime consumer resolution paths over to explicit bindings for email, calendar, and Teams:
- added
packages/integrations/src/lib/microsoftConsumerProfileResolution.tsas the shared binding-aware runtime resolver formsp_sso,email,calendar, andteams, - the resolver now materializes migration-safe
msp_sso,email, andcalendarbindings only from concrete legacy usage signals (msp_sso_tenant_login_domains,email_providers,calendar_providers) while failing closed for unsupported/no-signal cases, packages/integrations/src/actions/email-actions/oauthActions.ts,server/src/app/api/auth/microsoft/callback/route.ts, andserver/src/services/email/providers/MicrosoftGraphAdapter.tsnow resolve Microsoft email credentials from the bound profile instead of tenant/env fallbacks,packages/ee/src/lib/actions/integrations/calendarActions.ts,ee/server/src/app/api/auth/microsoft/calendar/callback/route.ts, andpackages/ee/src/lib/services/calendar/providers/MicrosoftCalendarAdapter.tsnow resolve Microsoft calendar credentials from the bound profile instead of tenant/env fallbacks,- replaced the leftover
packages/ee/src/lib/auth/teamsMicrosoftProviderResolution.tsstub with the real binding-aware Teams resolver so the shared Teams runtime wrapper no longer collapses tonot_configured.
- added
- (2026-03-09) Added focused runtime-resolution coverage for this slice:
packages/integrations/src/lib/microsoftConsumerProfileResolution.test.tscovers email binding resolution, calendar migration backfill, and invalid-profile failure modes,server/src/test/unit/microsoft/microsoftConsumerRuntimeResolution.contract.test.tsasserts the active email/calendar OAuth and token-refresh callers import the shared resolver and no longer reach for direct Microsoft env/tenant secrets,packages/auth/src/lib/sso/teamsMicrosoftProviderResolution.test.tsnow passes against the realpackages/eeTeams resolver instead of the old stub.
- (2026-03-09) Runtime-resolution validation commands:
cd server && pnpm vitest run --config vitest.config.ts ../packages/integrations/src/lib/microsoftConsumerProfileResolution.test.ts src/test/unit/microsoft/microsoftConsumerRuntimeResolution.contract.test.ts ../packages/auth/src/lib/sso/teamsMicrosoftProviderResolution.test.ts src/test/unit/lib/teams/teamsRuntimeOwnership.contract.test.ts ../packages/integrations/src/actions/integrations/microsoftConsumerBindings.test.tscd server && pnpm exec tsc -p tsconfig.json --noEmit --pretty false
- (2026-03-09) Cut the remaining MSP SSO Microsoft auth runtime off the legacy default-profile/tenant-secret path:
packages/auth/src/lib/sso/mspSsoResolution.tsnow checks Azure AD tenant readiness throughresolveMicrosoftConsumerProfileConfig(tenant, 'msp_sso')instead of directmicrosoft_client_*tenant secrets,packages/auth/src/lib/nextAuthOptions.tsnow hydrates request-scoped Azure AD OAuth credentials from the boundmsp_ssoMicrosoft profile when the resolver cookie selects a tenant source,- this leaves Google on its existing tenant/app secret path, but removes the last active Microsoft runtime consumer-resolution path that still bypassed explicit bindings.
- (2026-03-09) Added MSP SSO runtime regression coverage for the binding cutover:
packages/integrations/src/lib/microsoftConsumerProfileResolution.test.tsnow coversmsp_ssobinding backfill from active login domains plus the fail-closed path once no binding signal remains,packages/auth/src/lib/sso/mspSsoResolution.test.tsnow exercises Azure AD tenant readiness through the shared binding resolver rather than direct Microsoft tenant secret reads,packages/auth/src/lib/nextAuthOptions.mspContract.test.tsandserver/src/test/unit/microsoft/microsoftConsumerRuntimeResolution.contract.test.tsnow assert the shared auth runtime imports the binding-aware Microsoft resolver instead of direct tenant-secret lookups.
- (2026-03-09) MSP SSO binding-runtime validation commands:
cd server && pnpm vitest run --config vitest.config.ts ../packages/auth/src/lib/sso/mspSsoResolution.test.ts ../packages/auth/src/lib/nextAuthOptions.mspContract.test.ts ../packages/integrations/src/lib/microsoftConsumerProfileResolution.test.ts src/test/unit/microsoft/microsoftConsumerRuntimeResolution.contract.test.tscd server && pnpm exec tsc -p tsconfig.json --noEmit --pretty false
- (2026-03-09) Reduced the Microsoft
is_defaultflag back to profile-management metadata instead of a consumer-routing hint:packages/integrations/src/lib/microsoftConsumerProfileResolution.tsnow chooses migration backfill targets by matching the mirrored legacy Microsoft credentials to an active profile, or by using the only active profile when that choice is unambiguous,packages/integrations/src/actions/integrations/microsoftActions.tsnow reuses that candidate-selection helper for consumer binding materialization, so missing binding rows no longer attach to whichever profile happens to be marked default,- the binding UI still lets admins manage a default profile for profile CRUD and legacy secret mirroring, but the per-consumer binding rows no longer label a selected profile as the routing default.
- (2026-03-09) Added focused default-profile cleanup coverage:
packages/integrations/src/actions/integrations/microsoftActions.test.tsnow proves enterprise email binding backfill follows the mirrored legacy Microsoft credentials instead of theis_defaultflag and fails closed when no unique routing candidate remains,packages/integrations/src/components/settings/integrations/MicrosoftIntegrationSettings.contract.test.tsxnow asserts binding summaries stop rendering(default profile)as part of consumer routing copy.
- (2026-03-09) Default-profile cleanup validation commands:
cd server && pnpm vitest run --config vitest.config.ts ../packages/integrations/src/actions/integrations/microsoftActions.test.ts ../packages/integrations/src/components/settings/integrations/MicrosoftIntegrationSettings.contract.test.tsx ../packages/integrations/src/lib/microsoftConsumerProfileResolution.test.ts ../packages/auth/src/lib/sso/mspSsoResolution.test.ts ../packages/auth/src/lib/nextAuthOptions.mspContract.test.ts src/test/unit/microsoft/microsoftConsumerRuntimeResolution.contract.test.tscd server && pnpm exec tsc -p tsconfig.json --noEmit --pretty false
- (2026-03-09) Removed the last compatibility-default language from the shared Microsoft schema comments:
server/migrations/20260307120000_create_microsoft_profiles.cjsnow states thatis_defaultis profile-management metadata only,server/migrations/20260307143000_create_microsoft_profile_consumer_bindings.cjsnow states that each consumer chooses a profile through an explicit binding row,server/src/test/unit/microsoft/microsoftConsumerSchema.contract.test.tslocks in that wording so future migration edits do not reintroduce default-profile routing language.
- (2026-03-09) Default-profile cleanup follow-up:
packages/integrations/src/actions/integrations/microsoftActions.test.tsnow pins the CE status contract toNEXT_PUBLIC_EDITION=communityso the MSP SSO-only assertions remain deterministic regardless of the outer test environment.
- (2026-03-09) Closed the remaining migration-coverage and artifact-contract gaps:
- added
server/src/test/unit/calendar/calendarMigrationOwnership.contract.test.tsto lock in the fresh-install boundary where CE keeps shared Microsoft binding schema but omits EE calendar table-creation migrations, while EE adds the calendar migration set and concrete runtime entrypoints, - added
server/src/test/unit/docs/calendarMicrosoftMigrationPlan.contract.test.tsto keep the dated plan folder self-contained, cross-referenced, and aligned on CE/EE contracts, validation runbooks, and review/regression checklists, - expanded
packages/integrations/src/actions/integrations/microsoftConsumerBindings.test.tsso migration coverage now explicitly includes tenants with no Microsoft profiles, one active profile and no binding rows, active calendar-provider alignment, and archived-profile fail-closed behavior.
- added
- (2026-03-09) Final broad validation command for the remaining calendar and Microsoft plan items:
cd server && pnpm exec vitest run --coverage.enabled=false ../packages/integrations/src/lib/calendarAvailability.test.ts src/test/unit/components/integrations/IntegrationsSettingsPage.calendar.test.tsx src/test/unit/components/profile/UserProfile.calendar.contract.test.ts src/test/unit/api/calendarCallbackRoutes.delegator.test.ts src/test/unit/api/calendarWebhookRoutes.delegator.test.ts src/test/unit/jobs/calendarWebhookMaintenanceHandler.delegator.test.ts src/test/unit/calendar/calendarActions.ceBoundary.test.ts src/test/unit/calendar/calendarActions.ee.contract.test.ts src/test/unit/calendar/calendarActions.sync.test.ts src/test/unit/calendar/calendarSyncSubscriber.delegator.test.ts src/test/unit/calendar/calendarSyncSubscriber.ee.test.ts src/test/unit/calendar/calendarRuntimeOwnership.contract.test.ts src/test/unit/calendar/calendarMigrationOwnership.contract.test.ts ../packages/integrations/src/actions/integrations/microsoftConsumerBindings.test.ts ../packages/integrations/src/actions/integrations/microsoftActions.test.ts ../packages/integrations/src/lib/microsoftConsumerProfileResolution.test.ts src/test/unit/microsoft/microsoftConsumerRuntimeResolution.contract.test.ts src/test/unit/microsoft/microsoftConsumerSchema.contract.test.ts src/test/unit/docs/calendarMicrosoftMigrationPlan.contract.test.tscd server && pnpm exec tsc -p tsconfig.json --noEmit --pretty falsepython3 /Users/roberisaacs/.codex/skills/alga-plan/scripts/validate_plan.py ee/docs/plans/2026-03-09-calendar-sync-enterprise-migration-and-microsoft-profile-explicit-bindings
- (2026-03-09) Added the remaining migration-regression coverage for fresh installs, existing calendar rows, and explicit-binding edge cases:
server/src/test/unit/calendar/calendarActions.ceBoundary.test.tsnow proves fresh/community installs still fail closed for both provider listing and direct sync attempts even when a calendar provider id is supplied,server/src/test/unit/calendar/calendarActions.ee.contract.test.tsandserver/src/test/unit/calendar/calendarActions.sync.test.tsnow lock in that fresh enterprise installs and existing provider rows continue through the EE-owned action/service path,packages/integrations/src/actions/integrations/microsoftConsumerBindings.test.tsnow covers tenants with no Microsoft profiles, a single default profile plus legacy calendar usage, archived-profile binding guards, and invalid cross-tenant binding attempts,packages/integrations/src/lib/microsoftConsumerProfileResolution.test.tskeeps the archived/missing-credential runtime failure path explicit.
- (2026-03-09) Added cleanup contracts for the last remaining unchecked migration items:
server/src/test/unit/calendar/calendarRuntimeOwnership.contract.test.tsnow ties the shared Microsoft binding-schema wording to the EE-owned calendar runtime tree,server/src/test/unit/components/integrations/IntegrationsSettingsPage.calendar.test.tsxnow carries the explicit replacement coverage for the old CE-calendar-visible expectations.
- (2026-03-09) Migration-regression validation commands for the final unchecked calendar/binding items:
cd server && pnpm vitest run --config vitest.config.ts ../packages/integrations/src/actions/integrations/microsoftConsumerBindings.test.ts ../packages/integrations/src/lib/microsoftConsumerProfileResolution.test.ts src/test/unit/calendar/calendarActions.ceBoundary.test.ts src/test/unit/calendar/calendarActions.ee.contract.test.ts src/test/unit/calendar/calendarActions.sync.test.ts src/test/unit/calendar/calendarRuntimeOwnership.contract.test.ts src/test/unit/components/integrations/IntegrationsSettingsPage.calendar.test.tsxcd server && pnpm exec tsc -p tsconfig.json --noEmit --pretty false
- (2026-03-09) Added a dedicated plan-contract test for the migration artifacts themselves:
server/src/test/unit/docs/calendarSyncEnterpriseMigrationPlan.contract.test.tsnow locks the shared entrypoint/helper rules, calendar and Microsoft inventories, compatibility deletions, stable route commitments, CE-stub/EE-delegation documentation, the Microsoft CE/EE surface matrix, and the final acceptance matrix directly against the PRD and scratchpad.
- (2026-03-09) Plan-contract validation commands:
cd server && pnpm vitest run --config vitest.config.ts src/test/unit/docs/calendarSyncEnterpriseMigrationPlan.contract.test.tscd server && pnpm exec tsc -p tsconfig.json --noEmit --pretty false