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
408 lines
13 KiB
JSON
408 lines
13 KiB
JSON
[
|
|
{
|
|
"id": "F001",
|
|
"description": "Create migration ee/server/migrations/<ts>_create_teams_notification_deliveries.cjs that defines the table with all PRD columns and primary key (tenant, delivery_id).",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Data Model > teams_notification_deliveries"
|
|
]
|
|
},
|
|
{
|
|
"id": "F002",
|
|
"description": "Add UNIQUE (tenant, idempotency_key) constraint to teams_notification_deliveries to enable ON CONFLICT DO NOTHING.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Data Model > teams_notification_deliveries",
|
|
"Flow A"
|
|
]
|
|
},
|
|
{
|
|
"id": "F003",
|
|
"description": "Add CHECK constraint enforcing teams_notification_deliveries.status IN ('skipped','sent','delivered','failed').",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Data Model > teams_notification_deliveries"
|
|
]
|
|
},
|
|
{
|
|
"id": "F004",
|
|
"description": "Add CHECK constraint enforcing teams_notification_deliveries.error_code is NULL or in the documented enum set.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Error code taxonomy"
|
|
]
|
|
},
|
|
{
|
|
"id": "F005",
|
|
"description": "Add indexes (tenant, internal_notification_id) and (tenant, status, created_at DESC) on teams_notification_deliveries.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Data Model > teams_notification_deliveries"
|
|
]
|
|
},
|
|
{
|
|
"id": "F006",
|
|
"description": "Declare teams_notification_deliveries as PARTITION BY RANGE (created_at); create child partitions for current month + next 2 months.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Retention Strategy"
|
|
]
|
|
},
|
|
{
|
|
"id": "F007",
|
|
"description": "Run create_distributed_table('teams_notification_deliveries','tenant', colocate_with => 'teams_integrations') when Citus is present; warn-and-skip otherwise.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Multi-Tenant / Citus Compliance"
|
|
]
|
|
},
|
|
{
|
|
"id": "F008",
|
|
"description": "Create PL/pgSQL function cleanup_teams_notification_deliveries(retention_interval) that drops partitions older than now() - retention_interval. Default 90 days.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Retention Strategy"
|
|
]
|
|
},
|
|
{
|
|
"id": "F009",
|
|
"description": "Create migration ee/server/migrations/<ts>_create_teams_audit_events.cjs with all PRD columns and PK (tenant, event_id).",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Data Model > teams_audit_events"
|
|
]
|
|
},
|
|
{
|
|
"id": "F010",
|
|
"description": "Add CHECK constraints enforcing teams_audit_events.surface IN ('bot','message_extension','quick_action','tab') and result_status IN ('success','failure').",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Data Model > teams_audit_events"
|
|
]
|
|
},
|
|
{
|
|
"id": "F011",
|
|
"description": "Add CHECK constraint enforcing teams_audit_events.action_id IN ('assign_ticket','add_note','reply_to_contact','log_time','approval_response','create_ticket_from_message','update_from_message').",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Data Model > teams_audit_events"
|
|
]
|
|
},
|
|
{
|
|
"id": "F012",
|
|
"description": "Add indexes (tenant, actor_user_id, created_at DESC) and (tenant, target_type, target_id) on teams_audit_events.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Data Model > teams_audit_events"
|
|
]
|
|
},
|
|
{
|
|
"id": "F013",
|
|
"description": "Run create_distributed_table on teams_audit_events colocated with teams_integrations.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Multi-Tenant / Citus Compliance"
|
|
]
|
|
},
|
|
{
|
|
"id": "F014",
|
|
"description": "Create PL/pgSQL function cleanup_teams_audit_events(retention_interval) (default 365 days). Audit table is NOT partitioned in this PR — function uses range delete.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Retention Strategy"
|
|
]
|
|
},
|
|
{
|
|
"id": "F015",
|
|
"description": "Create migration ee/server/migrations/<ts>_create_teams_conversation_references.cjs with PRD columns and PK (tenant, microsoft_user_id, conversation_id).",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Data Model > teams_conversation_references"
|
|
]
|
|
},
|
|
{
|
|
"id": "F016",
|
|
"description": "Run create_distributed_table on teams_conversation_references colocated with teams_integrations.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Multi-Tenant / Citus Compliance"
|
|
]
|
|
},
|
|
{
|
|
"id": "F017",
|
|
"description": "Implement writeTeamsDeliveryRow(input) helper in ee/packages/microsoft-teams/src/lib/notifications/teamsDeliveryRecorder.ts. Computes idempotency_key (SHA-256), inserts with ON CONFLICT DO NOTHING.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Flow A"
|
|
]
|
|
},
|
|
{
|
|
"id": "F018",
|
|
"description": "Instrument deliverTeamsNotificationImpl() to call writeTeamsDeliveryRow() on 'skipped' return path with appropriate skip reason mapped to error_code enum.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Flow A"
|
|
]
|
|
},
|
|
{
|
|
"id": "F019",
|
|
"description": "Instrument deliverTeamsNotificationImpl() to call writeTeamsDeliveryRow() on 'delivered' return path with provider_message_id.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Flow A"
|
|
]
|
|
},
|
|
{
|
|
"id": "F020",
|
|
"description": "Instrument deliverTeamsNotificationImpl() to call writeTeamsDeliveryRow() on 'failed' return path with error_code mapped to enum (graph_throttled, graph_unauthorized, etc.).",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Flow A",
|
|
"Error code taxonomy"
|
|
]
|
|
},
|
|
{
|
|
"id": "F021",
|
|
"description": "Map Graph HTTP status codes to error_code enum values: 401/403 -> graph_unauthorized; 404 -> graph_not_found; 429 -> graph_throttled; 5xx -> graph_server_error.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Error code taxonomy"
|
|
]
|
|
},
|
|
{
|
|
"id": "F022",
|
|
"description": "Map non-Graph skip reasons to error_code enum: missing addon -> addon_inactive; integration inactive -> integration_inactive; user not mapped -> user_not_mapped; missing package metadata -> package_misconfigured.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Error code taxonomy"
|
|
]
|
|
},
|
|
{
|
|
"id": "F023",
|
|
"description": "Capture provider_request_id from Graph response 'request-id' header when present and persist on delivery row.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Data Model > teams_notification_deliveries"
|
|
]
|
|
},
|
|
{
|
|
"id": "F024",
|
|
"description": "Truncate error_message to 1KB before persisting to prevent leaking long customer/Graph payloads.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Privacy / Security"
|
|
]
|
|
},
|
|
{
|
|
"id": "F025",
|
|
"description": "Implement writeTeamsAuditEvent(input) helper in ee/packages/microsoft-teams/src/lib/teams/actions/teamsAuditRecorder.ts. Computes payload_hash (SHA-256 of canonicalized JSON), inserts row.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Flow B",
|
|
"Privacy / Security"
|
|
]
|
|
},
|
|
{
|
|
"id": "F026",
|
|
"description": "Canonicalize action payload via stable JSON.stringify with sorted keys before hashing so retried invokes produce the same payload_hash.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Privacy / Security"
|
|
]
|
|
},
|
|
{
|
|
"id": "F027",
|
|
"description": "Instrument assign_ticket action in teamsActionRegistry.ts to call writeTeamsAuditEvent on success and on caught failure.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Flow B"
|
|
]
|
|
},
|
|
{
|
|
"id": "F028",
|
|
"description": "Instrument add_note action in teamsActionRegistry.ts to call writeTeamsAuditEvent on success and on caught failure.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Flow B"
|
|
]
|
|
},
|
|
{
|
|
"id": "F029",
|
|
"description": "Instrument reply_to_contact action in teamsActionRegistry.ts to call writeTeamsAuditEvent on success and on caught failure.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Flow B"
|
|
]
|
|
},
|
|
{
|
|
"id": "F030",
|
|
"description": "Instrument log_time action in teamsActionRegistry.ts to call writeTeamsAuditEvent on success and on caught failure.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Flow B"
|
|
]
|
|
},
|
|
{
|
|
"id": "F031",
|
|
"description": "Instrument approval_response action in teamsActionRegistry.ts to call writeTeamsAuditEvent on success and on caught failure.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Flow B"
|
|
]
|
|
},
|
|
{
|
|
"id": "F032",
|
|
"description": "Instrument create_ticket_from_message action in teamsActionRegistry.ts to call writeTeamsAuditEvent on success and on caught failure.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Flow B"
|
|
]
|
|
},
|
|
{
|
|
"id": "F033",
|
|
"description": "Instrument update_from_message action in teamsActionRegistry.ts to call writeTeamsAuditEvent on success and on caught failure.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Flow B"
|
|
]
|
|
},
|
|
{
|
|
"id": "F034",
|
|
"description": "Resolve actor_user_id (PSA user) and microsoft_user_id (aadObjectId) from Teams turn context at audit recording time.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Data Model > teams_audit_events"
|
|
]
|
|
},
|
|
{
|
|
"id": "F035",
|
|
"description": "Map each action's source (bot turn / compose extension / quick action task module) to the correct surface enum value when recording audit events.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Data Model > teams_audit_events"
|
|
]
|
|
},
|
|
{
|
|
"id": "F036",
|
|
"description": "Implement upsertTeamsConversationReference(turnContext) helper that writes/updates teams_conversation_references on every inbound bot activity.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Flow C"
|
|
]
|
|
},
|
|
{
|
|
"id": "F037",
|
|
"description": "Call upsertTeamsConversationReference from the bot adapter's activity handler entry point so all inbound activities trigger capture.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Flow C"
|
|
]
|
|
},
|
|
{
|
|
"id": "F038",
|
|
"description": "Implement listTeamsDeliveries server action in teamsObservabilityActions.ts using withAuth + hasPermission('teams_integration','read'). Supports status/category/since filters, cursor pagination, limit cap 200.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Flow D",
|
|
"API Surface"
|
|
]
|
|
},
|
|
{
|
|
"id": "F039",
|
|
"description": "Implement listTeamsAuditEvents server action in teamsObservabilityActions.ts using withAuth + hasPermission('teams_integration','read'). Supports surface/action_id/actor/result filters, cursor pagination.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Flow D",
|
|
"API Surface"
|
|
]
|
|
},
|
|
{
|
|
"id": "F040",
|
|
"description": "Cursor encoding: opaque base64 of (created_at, id) tuple so pagination is stable under inserts. Decode/validate cursor server-side; reject malformed.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"API Surface"
|
|
]
|
|
},
|
|
{
|
|
"id": "F041",
|
|
"description": "Add 'teams_integration:read' permission to permission seeder if absent. Verify by grepping existing permissions before adding.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Open Questions Q2"
|
|
]
|
|
},
|
|
{
|
|
"id": "F042",
|
|
"description": "CRITICAL: Add 'teams_notification_deliveries', 'teams_audit_events', 'teams_conversation_references' to TENANT_TABLES_DELETION_ORDER in ee/temporal-workflows/src/activities/tenant-deletion-activities.ts BEFORE 'teams_integrations' entry.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Tenant Deletion Integration"
|
|
]
|
|
},
|
|
{
|
|
"id": "F043",
|
|
"description": "Verify partitioned table deletion behavior: DELETE FROM teams_notification_deliveries WHERE tenant=? prunes across all partitions (tested in tenant-deletion activity).",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Tenant Deletion Integration"
|
|
]
|
|
},
|
|
{
|
|
"id": "F044",
|
|
"description": "Update Microsoft profile bindings comment block in tenant-deletion-activities.ts to reflect the three new tables.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Tenant Deletion Integration"
|
|
]
|
|
},
|
|
{
|
|
"id": "F045",
|
|
"description": "Rebuild @alga-psa/microsoft-teams package (tsup -> dist) so server picks up new exports and instrumentation.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Rollout / Migration"
|
|
]
|
|
},
|
|
{
|
|
"id": "F046",
|
|
"description": "Grep services/workflow-worker for imports of deliverTeamsNotificationImpl / teamsActionRegistry. If present, document worker rebuild requirement in plan deployment notes.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Risks"
|
|
]
|
|
},
|
|
{
|
|
"id": "F047",
|
|
"description": "Export TeamsDeliveryRow and TeamsAuditEventRow TypeScript types from the package public API surface for the server actions to consume.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"API Surface"
|
|
]
|
|
},
|
|
{
|
|
"id": "F048",
|
|
"description": "Document the new tables, instrumentation helpers, and tenant-deletion registration in a one-line CHANGELOG entry (internal — no marketing).",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Rollout / Migration"
|
|
]
|
|
},
|
|
{
|
|
"id": "F049",
|
|
"description": "Validate Citus partition + distribution interaction with a smoke query in the migration: SELECT count(*) FROM pg_dist_partition WHERE logicalrelid='teams_notification_deliveries'::regclass. Log result.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Risks"
|
|
]
|
|
},
|
|
{
|
|
"id": "F050",
|
|
"description": "Mirror migrations into ee/server/migrations/citus/ ONLY if there is Citus-specific divergence (e.g., distribution must happen outside a transaction). Otherwise keep single CE-compatible migration.",
|
|
"implemented": true,
|
|
"prdRefs": [
|
|
"Acceptance Criteria"
|
|
]
|
|
}
|
|
]
|