Invoke AccountingExporterService securely from Edge Function
epic-accounting-system-export-orchestration-task-007 — Wire the AccountingExporterService invocation into the Edge Function. Fetch accounting credentials from the server-side Accounting Credentials Vault (environment secrets / Vault API) — credentials must never be passed from or returned to the client. Pass orgId, dateRange, and userId to AccountingExporterService.triggerExport() and capture the ExportResult. Log all invocation details (user, org, timestamp, result status) to the audit log table using the service-role Supabase client.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 5 - 253 tasks
Can start after Tier 4 completes
Implementation Notes
Fetch credentials using `Deno.env.get('XLEDGER_API_KEY')` and `Deno.env.get('DYNAMICS_CLIENT_SECRET')` — these are injected as secrets in the Supabase project settings (not in .env files committed to source control). For multi-tenant credential isolation, prefix env var names with the orgId (e.g., XLEDGER_API_KEY_ORG_ABC) or use Supabase Vault with per-org secret names. The AccountingExporterService in this context runs within the Deno runtime — if it is a Dart service, it must be invoked via an HTTP call to a separate service; if it is TypeScript, import it directly. Audit log writes should use fire-and-forget pattern with a catch that logs to stderr (not to the response) to avoid blocking the response.
Use structured logging (JSON to stderr) for all operational events so they are queryable in Supabase logs.
Testing Requirements
Integration tests using Supabase Functions local test harness (see task-009 for full E2E suite). For this task, write focused integration tests: (1) successful Xledger invocation — assert audit log row created with status=SUCCESS; (2) successful Dynamics invocation — assert audit log row created with status=SUCCESS; (3) DuplicateExportException → 409 response + audit log row with status=REJECTED; (4) generic exception → 500 response + audit log row with status=FAILED; (5) assert credentials are not present in any response payload across all scenarios. Use a test Supabase project with seeded org and user data. Mock the external Xledger and Dynamics endpoints using a local HTTP stub server.
The Edge Function may exceed Supabase's execution time limit (default 150 seconds, but effectively constrained by the 10-second client SLA) when processing large batches of claims with complex chart-of-accounts mapping, causing the export to fail after partial processing.
Mitigation & Contingency
Mitigation: Implement the export pipeline with early termination on timeout and an in-progress export run status. Add a benchmark test in CI that runs the full pipeline against 500 claims and fails if it exceeds 8 seconds. Optimize the approved claims query with indexes on status, org_id, and date fields.
Contingency: If performance targets cannot be met synchronously, convert the Edge Function to an async job pattern: the function queues the export and returns a job ID immediately; the client polls a status endpoint and downloads the file when ready. This requires a job queue table and a polling UI state.
Supabase Vault access from the Edge Function may require specific service role key configuration that differs between staging and production environments, causing credential retrieval to fail silently and producing export runs that appear successful but have no valid accounting system target.
Mitigation & Contingency
Mitigation: Test Vault read access in the Edge Function in staging before implementing any business logic. Add an explicit credential validation step at Edge Function startup that fails fast with a clear error if Vault is unreachable or the secret is missing.
Contingency: If Vault access fails in production, fall back to environment variable-based credentials temporarily (never returned to client) while the Vault configuration is corrected. Alert on-call via a monitoring rule that fires if credential retrieval fails.
AccountingExporter Service may become tightly coupled to specific exporter implementations if the factory pattern is not implemented cleanly, making it difficult to add a third exporter in the future without modifying the orchestrator.
Mitigation & Contingency
Mitigation: Define an AccountingExporter abstract class with a strict interface contract before implementing any concrete class. Use a registry pattern (Map<orgType, AccountingExporter>) in the factory rather than conditionals. Code review should verify no concrete class is imported directly in the orchestrator.
Contingency: If tight coupling is discovered after implementation, refactor the factory before the Edge Function epic ships so the interface is stable before any external callers are wired in.