You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Replace the Zapier → Google Drive → datatalks-mailchimp-backup flow with a DataOps-owned mailing-list export workflow. DataOps must request the export from the provider, poll asynchronous completion, copy the completed archive into retained private DataOps storage, record the run, and attach the resulting artifact to the configured recurring task/run when that task exists.
Mailchimp is the first provider, behind a provider-neutral interface. Its supported Marketing API v3 account-export operation must request the audiences stage. This is an account-level export containing all audiences, not a single-audience export; any configured audience value is only an operator-facing label unless a future provider supports narrower scope. Mailchimp allows one account export at a time and one completed export per 24-hour period, and completion can take minutes or longer. Scheduling, polling, persistence, storage, task attachment, idempotency, and operator presentation must remain provider-neutral.
Provide both authenticated API and portal paths:
GET /api/mailing-exports lists sanitized run/configuration status.
POST /api/mailing-exports/run manually starts or advances one configured export with a stable idempotency/run key.
An authenticated portal surface shows configured accounts, latest/history status, timestamps, task/artifact linkage, safe download action, retry/poll state, and actionable errors; an operator can trigger a manual run without constructing an API request.
The scheduled EventBridge invocation starts eligible runs and advances unfinished runs without violating provider rate limits.
Use the existing artifacts/task relationships and deployed CloudFormation stack. Persist stable metadata in DynamoDB and binary ZIP content in a dedicated retained, private, versioned S3 bucket. Downloads must go through an authenticated, short-lived controlled-download endpoint; never expose a raw s3:// URI as a browser link or persist/return the provider's signed download_url.
Acceptance Criteria
A provider-neutral connector contract separates request, status polling, and download behavior from scheduling, persistence, storage, task attachment, and portal/API presentation; adding a provider does not require changing those shared services.
The Mailchimp adapter uses Marketing API v3 account exports with include_stages: ["audiences"], accepts documented secret configuration, derives/validates the server prefix, handles export_id, finished, and download_url responses correctly, and describes the result as an account-level audiences export rather than a selected-audience export.
Each run records a deterministic ID/idempotency key, configuration ID, provider, account, scope label, run key, provider export ID, requested/pending/completed/failed status, requested/completed/updated timestamps, filename, content type/size where available, SHA-256 checksum, artifact ID, task/run linkage, and a safe error category/message. Provider secrets and signed URLs are never persisted.
Manual trigger and scheduled trigger share the same service and idempotency behavior. Repeating or concurrently delivering the same configuration + run key does not make duplicate provider requests, upload duplicate logical artifacts, or add duplicate task references; a completed key returns the existing durable result.
An unfinished provider export is polled on later scheduled/manual invocations until completion. A new daily run is not started while one is unfinished or within Mailchimp's 24-hour limit; provider “in progress”/rate-limit responses become a retriable pending/blocked state with the next useful operator action, not an opaque permanent failure.
On completion DataOps downloads the ZIP, calculates SHA-256, stores it under a deterministic key in the dedicated private S3 bucket, creates exactly one private system artifact, and attaches it to the configured recurring task/run if present. A missing/stale task link is reported without losing or duplicating the stored export.
The S3 resource is CloudFormation-managed, retained on stack replacement/deletion, versioned, encrypted at rest, blocks all public access, denies insecure transport, and has explicit incomplete-upload/retention lifecycle behavior. Lambda has only the required object and named-secret permissions.
Authenticated operators can list export history/status, manually run or advance a configured export, and download a completed archive through a short-lived controlled DataOps download path. Unauthenticated list, trigger, and download requests receive 401/403; API responses and portal markup never expose credential material, provider signed URLs, or raw S3 browser links.
The portal provides clear loading, no-config/empty, pending, completed, and failure states. It identifies account and export scope, requested/completed times, linked task/artifact, and whether the next action is wait, retry, fix authorization, or fix storage; manual controls prevent accidental repeat submissions and remain usable on a 390 px viewport.
Authorization, provider/API, provider timeout, provider concurrency/rate limit, download-integrity, storage, persistence, and task-link failures are recorded with actionable categories and sanitized operator copy. Logs contain stable run/config IDs and status transitions but no contacts, API keys, Authorization headers, secret payloads, or signed download URLs.
Connector/configuration/operator documentation explains provider extension, Mailchimp's account-level semantics and 24-hour constraint, secret format and least-privilege limitation (including that Mailchimp API keys are account-wide where applicable), schedule, idempotency key usage, retry/poll behavior, artifact/download path, and rollback/disable procedure. It contains placeholders only—no real account IDs, audience/contact data, secret names/ARNs tied to production, or exports.
[HUMAN] A credentialed AWS operator supplies the Mailchimp secret/configuration through the approved secret/deploy mechanism and verifies one real export reaches private DataOps storage and its intended recurring task without Zapier or Google Drive. Keep the issue open with human if all agent-verifiable work passes before this check.
Test Scenarios
Scenario: Successful manual export and controlled download
Given: an authenticated operator, one enabled Mailchimp configuration, a matching recurring task/run, and a provider fake that completes with a ZIP
When: the operator triggers the run in the portal and later downloads the completed result
Then: one provider request, one deterministic private object/artifact, one task reference, complete sanitized metadata, and one authenticated short-lived download are produced
Scenario: Delayed completion survives invocations
Given: Mailchimp accepts an export but does not return finished/download_url
When: later manual or scheduled invocations use the same run
Then: DataOps polls the saved provider export ID, keeps the run pending, and completes without requesting a second provider export
Scenario: Duplicate and concurrent delivery
Given: two invocations use the same configuration + run key, including overlapping execution
When: both attempt to process the export
Then: conditional persistence/locking makes only one logical provider request and final artifact/task reference; later repeats return the same completed run
Scenario: Mailchimp export limit
Given: an unfinished export or a provider response indicating another export/24-hour limit
When: the scheduler or operator tries again
Then: DataOps preserves the active run, does not create churn or a duplicate request, and shows when to wait/retry
Scenario: Failure before and after provider completion
Given: separate authorization, provider, timeout, malformed completion/no URL, checksum/download, S3, DynamoDB, and missing-task failures
When: the service handles each failure and an operator retries a retriable run
Then: status/category/copy are actionable and secret-safe, a completed provider job is reused where possible, and no orphan duplicate artifact/reference is created
Scenario: Authentication and privacy
Given: no valid portal/API session
When: list, manual-run, or download endpoints are called
Then: access is denied; with valid auth, returned JSON/logs/HTML contain neither secret values nor provider signed URLs and downloads expire
Scenario: Portal states and responsive layout
Given: no configurations, pending/completed runs, and each supported failure category
When: the mailing-export surface is rendered at desktop and 390 px widths
Then: empty/loading/status/action copy is understandable, controls are keyboard accessible, and there is no overlap or horizontal overflow
Scenario: Infrastructure policy
Given: the SAM/CloudFormation template
When: it is validated and inspected by automated tests
Then: private retained/versioned/encrypted storage, TLS-only access, lifecycle rules, schedule input, environment configuration, and least-privilege S3/Secrets Manager permissions are present
Required Verification
npm --prefix backend test
npm --prefix backend run typecheck
npm --prefix backend run build
npm --prefix backend run test:e2e (or a documented focused Playwright run followed by the full suite if shared-fixture contention requires isolation)
uv run pytest tests/infra/test_template.py
make sam-validate
Focused backend tests must cover the API routes, Mailchimp request/response contract, delayed completion, conditional concurrent idempotency, completed-run replay, 24-hour/in-progress handling, auth failure, provider/timeout/malformed response, signed-URL redaction, checksum/download failure, storage/persistence failure, missing task, and retry after each retriable failure.
Playwright must cover manual trigger plus loading, empty/no-config, pending, completed/download, and error states at desktop and 390 px. Tester captures screenshots under .tmp/screenshots/, reads each screenshot, and confirms no private export/account/contact data is posted publicly.
Tester verifies every acceptance checkbox and reports exact commands, exit codes, test counts, and screenshot paths in the issue comment.
Security and Privacy Boundaries
Mailing-list archives contain personal data. ZIP files, extracted content, provider responses, screenshots with live data, and diagnostic payloads stay in private S3 or gitignored .tmp/; they must never enter this public repository, issue body/comments, CI artifacts, fixtures, or logs.
Store credentials only through AWS Secrets Manager/deployed parameters or documented local environment placeholders. Never put secret values in task content, DynamoDB jobs/artifacts, source, docs, logs, error messages, or GitHub configuration.
Treat Mailchimp download_url as secret-equivalent. Use it only in memory long enough to download; never persist, log, echo, or return it.
Persist stable s3:// identity only as server-side metadata. Browser downloads require authenticated authorization and a short-lived presigned response/redirect.
Use synthetic archives and fake account/audience labels in automated tests and screenshots.
Dependencies
Existing authenticated portal/session routing, recurring tasks, artifacts/task references, DynamoDB tables, and GitHub Actions OIDC deployment are available.
Production enablement requires an out-of-band Mailchimp credential and configuration supplied by a credentialed AWS operator; implementation and synthetic verification do not depend on receiving it.
Official provider behavior: Mailchimp Account Exports and Get account export info; the API exports requested stages account-wide, builds asynchronously, exposes completed download URLs for a limited period, and enforces one export at a time/one per 24 hours.
Out of Scope
Migrating old Google Drive/S3 backups or deleting the current Zapier workflow/bucket before the human production check.
Exporting a single Mailchimp audience (the supported account-export audiences stage includes all audiences).
Importing/restoring contacts into Mailchimp, syncing individual contacts, campaign sending, newsletter scheduling, sponsor CRM, or marketing analytics.
Supporting a second provider in this issue; only the extension boundary and documentation are required.
Storing archives or operational details in DataTalksClub/dataops-knowledge, content/, or any public GitHub artifact.
Modifying ../dtc-operations, ../datatasks, or ../podcast-assistant.
Automate private Mailchimp account exports and attach them to recurring work
Status: pending
Tags:
enhancement,portal,frontend,backend,infra,data,P1Depends on: None
Blocks: None
Scope
Replace the Zapier → Google Drive →
datatalks-mailchimp-backupflow with a DataOps-owned mailing-list export workflow. DataOps must request the export from the provider, poll asynchronous completion, copy the completed archive into retained private DataOps storage, record the run, and attach the resulting artifact to the configured recurring task/run when that task exists.Mailchimp is the first provider, behind a provider-neutral interface. Its supported Marketing API v3 account-export operation must request the
audiencesstage. This is an account-level export containing all audiences, not a single-audience export; any configuredaudiencevalue is only an operator-facing label unless a future provider supports narrower scope. Mailchimp allows one account export at a time and one completed export per 24-hour period, and completion can take minutes or longer. Scheduling, polling, persistence, storage, task attachment, idempotency, and operator presentation must remain provider-neutral.Provide both authenticated API and portal paths:
GET /api/mailing-exportslists sanitized run/configuration status.POST /api/mailing-exports/runmanually starts or advances one configured export with a stable idempotency/run key.Use the existing artifacts/task relationships and deployed CloudFormation stack. Persist stable metadata in DynamoDB and binary ZIP content in a dedicated retained, private, versioned S3 bucket. Downloads must go through an authenticated, short-lived controlled-download endpoint; never expose a raw
s3://URI as a browser link or persist/return the provider's signeddownload_url.Acceptance Criteria
include_stages: ["audiences"], accepts documented secret configuration, derives/validates the server prefix, handlesexport_id,finished, anddownload_urlresponses correctly, and describes the result as an account-level audiences export rather than a selected-audience export.requested/pending/completed/failedstatus, requested/completed/updated timestamps, filename, content type/size where available, SHA-256 checksum, artifact ID, task/run linkage, and a safe error category/message. Provider secrets and signed URLs are never persisted.401/403; API responses and portal markup never expose credential material, provider signed URLs, or raw S3 browser links.humanif all agent-verifiable work passes before this check.Test Scenarios
Scenario: Successful manual export and controlled download
Given: an authenticated operator, one enabled Mailchimp configuration, a matching recurring task/run, and a provider fake that completes with a ZIP
When: the operator triggers the run in the portal and later downloads the completed result
Then: one provider request, one deterministic private object/artifact, one task reference, complete sanitized metadata, and one authenticated short-lived download are produced
Scenario: Delayed completion survives invocations
Given: Mailchimp accepts an export but does not return
finished/download_urlWhen: later manual or scheduled invocations use the same run
Then: DataOps polls the saved provider export ID, keeps the run pending, and completes without requesting a second provider export
Scenario: Duplicate and concurrent delivery
Given: two invocations use the same configuration + run key, including overlapping execution
When: both attempt to process the export
Then: conditional persistence/locking makes only one logical provider request and final artifact/task reference; later repeats return the same completed run
Scenario: Mailchimp export limit
Given: an unfinished export or a provider response indicating another export/24-hour limit
When: the scheduler or operator tries again
Then: DataOps preserves the active run, does not create churn or a duplicate request, and shows when to wait/retry
Scenario: Failure before and after provider completion
Given: separate authorization, provider, timeout, malformed completion/no URL, checksum/download, S3, DynamoDB, and missing-task failures
When: the service handles each failure and an operator retries a retriable run
Then: status/category/copy are actionable and secret-safe, a completed provider job is reused where possible, and no orphan duplicate artifact/reference is created
Scenario: Authentication and privacy
Given: no valid portal/API session
When: list, manual-run, or download endpoints are called
Then: access is denied; with valid auth, returned JSON/logs/HTML contain neither secret values nor provider signed URLs and downloads expire
Scenario: Portal states and responsive layout
Given: no configurations, pending/completed runs, and each supported failure category
When: the mailing-export surface is rendered at desktop and 390 px widths
Then: empty/loading/status/action copy is understandable, controls are keyboard accessible, and there is no overlap or horizontal overflow
Scenario: Infrastructure policy
Given: the SAM/CloudFormation template
When: it is validated and inspected by automated tests
Then: private retained/versioned/encrypted storage, TLS-only access, lifecycle rules, schedule input, environment configuration, and least-privilege S3/Secrets Manager permissions are present
Required Verification
npm --prefix backend testnpm --prefix backend run typechecknpm --prefix backend run buildnpm --prefix backend run test:e2e(or a documented focused Playwright run followed by the full suite if shared-fixture contention requires isolation)uv run pytest tests/infra/test_template.pymake sam-validate.tmp/screenshots/, reads each screenshot, and confirms no private export/account/contact data is posted publicly.Security and Privacy Boundaries
.tmp/; they must never enter this public repository, issue body/comments, CI artifacts, fixtures, or logs.download_urlas secret-equivalent. Use it only in memory long enough to download; never persist, log, echo, or return it.s3://identity only as server-side metadata. Browser downloads require authenticated authorization and a short-lived presigned response/redirect.Dependencies
Out of Scope
audiencesstage includes all audiences).DataTalksClub/dataops-knowledge,content/, or any public GitHub artifact.../dtc-operations,../datatasks, or../podcast-assistant.