# Adobe Sign → DocuSign Migrator A Python toolkit + web UI for migrating library templates from Adobe Sign (Acrobat Sign) to DocuSign. It downloads templates via the Adobe Sign API, converts them to DocuSign format, and uploads them via the DocuSign API — either from the command line or through a browser-based UI. --- ## What it does 1. **Authenticates** with Adobe Sign via OAuth (one-time browser flow, tokens saved to `.env`) 2. **Downloads** templates — PDF, metadata, and form field definitions 3. **Converts** each template to a DocuSign `envelopeTemplate` JSON, mapping all field types, coordinates, recipient roles, and conditional field logic 4. **Authenticates** with DocuSign via JWT grant (one-time browser consent, then fully automated) 5. **Uploads** the converted template to DocuSign via the REST API --- ## Prerequisites - Python 3.10+ - An Adobe Sign OAuth app (EU2 shard) with scopes: `library_read:self library_write:self user_read:self` - A DocuSign developer account with an integration key and RSA keypair --- ## Setup **1. Install Python dependencies:** ```bash pip install -r requirements.txt ``` **2. Create a `.env` file** in the project root (never commit this): ```bash cp .env-sample .env ``` Then fill in your credentials. See [.env-sample](.env-sample) for the full list of variables with descriptions. Use `account-d.docusign.com` and `https://demo.docusign.net/restapi` for sandbox; for production replace with `account.docusign.com` and your account's base URL (e.g. `https://na3.docusign.net/restapi`). **3. Authenticate with Adobe Sign** (one-time): ```bash python3 src/adobe_auth.py ``` Opens a browser. After authorizing, paste the redirect URL back into the terminal. Tokens are saved to `.env` and auto-refreshed on subsequent runs. **4. Grant consent for DocuSign** (one-time per user): ```bash python3 src/docusign_auth.py --consent ``` Opens a browser for the DocuSign OAuth consent screen. After approving, paste the redirect URL back into the terminal. This grants the `impersonation` scope required for JWT grant. After this runs once, all subsequent API calls use JWT automatically — no further browser interaction needed. --- ## Running a migration **List available templates in Adobe Sign:** ```bash python3 src/download_templates.py list ``` **Download templates:** ```bash python3 src/download_templates.py download # all templates python3 src/download_templates.py download "Template Name" # one specific template ``` Downloads to `downloads/__/` — one folder per template containing `metadata.json`, `form_fields.json`, `documents.json`, and the PDF. **Convert a downloaded template to DocuSign format:** ```bash python3 src/compose_docusign_template.py ``` Writes DocuSign template JSONs to `migration-output//docusign-template.json`. **Upload to DocuSign (upsert by default):** ```bash python3 src/upload_docusign_template.py --file migration-output//docusign-template.json ``` If a DocuSign template with the same name already exists, the most recently modified one is updated (PUT). To always create a new template instead: ```bash python3 src/upload_docusign_template.py --file --force-create ``` **Or run the full pipeline end-to-end:** ```bash python3 src/migrate_template.py --list # show available templates python3 src/migrate_template.py --template "Template Name" # download → convert → upload python3 src/migrate_template.py --template "Template Name" --skip-upload # convert only ``` If multiple templates share the same name, the most recently modified one is used. --- --- ## Web UI The web UI provides a browser-based interface for connecting both platforms, browsing templates side-by-side, and running migrations with live status feedback. **Additional `.env` keys required for the web UI:** ``` SESSION_SECRET_KEY= DOCUSIGN_CLIENT_SECRET= DOCUSIGN_REDIRECT_URI=http://localhost:8000/api/auth/docusign/callback ADOBE_REDIRECT_URI=http://localhost:8000/api/auth/adobe/callback ``` **Start the server:** ```bash uvicorn web.app:app --reload --port 8000 ``` Then open [http://localhost:8000](http://localhost:8000) in your browser. **Using the UI:** 1. Click **Connect Adobe Sign** in the header — you'll be redirected to Adobe Sign OAuth. Authorize and you'll return to the app. 2. Click **Connect DocuSign** — same flow for DocuSign. 3. Your Adobe Sign templates appear on the left with status badges: - **Not Migrated** (red) — no matching DocuSign template yet - **Migrated** (green) — a DocuSign template with the same name exists and is up to date - **Needs Update** (yellow) — the Adobe template was modified after the last migration 4. Check one or more templates and click **Migrate Selected**. 5. Migration results appear inline; the history table at the bottom logs all past runs. **API docs:** [http://localhost:8000/api/docs](http://localhost:8000/api/docs) --- ## Running tests ```bash pytest tests/ -v # full suite (29 tests) pytest tests/test_regression.py -v # compose regression only pytest tests/test_regression.py --update-snapshots # regenerate snapshots after intentional changes ``` --- ## Field type mapping See [field-mapping.md](field-mapping.md) for the full Adobe Sign → DocuSign tab type table, conditional logic mapping, and known gaps. ## Known API quirks and bugs See [tests/PLATFORM-QUIRKS.md](tests/PLATFORM-QUIRKS.md) for documented platform bugs, unexpected API behaviors, and the fixes applied. --- ## Project structure ``` src/ adobe_auth.py # One-time OAuth flow for Adobe Sign (CLI) adobe_api.py # Adobe Sign API client (auto token refresh) download_templates.py # List and download templates from Adobe Sign compose_docusign_template.py # Core conversion: Adobe Sign → DocuSign JSON docusign_auth.py # DocuSign JWT auth + one-time consent flow upload_docusign_template.py # Upsert upload: PUT if exists, POST if not migrate_template.py # End-to-end CLI runner (download → convert → upload) create_adobe_template.py # Utility: create a test template in Adobe Sign generate_pdfs.py # Utility: generate sample PDFs for offline testing web/ app.py # FastAPI entrypoint (uvicorn web.app:app) config.py # Environment-based settings session.py # Signed cookie session helpers routers/ auth.py # Adobe Sign + DocuSign OAuth endpoints templates.py # Template listing + migration status API migrate.py # Migration trigger + history API static/ index.html # Web UI (side-by-side browser + migrate flow) app.js # Vanilla JS frontend style.css # Styles + status badge colours tests/ test_upload_upsert.py # Upsert logic unit tests test_api_health.py # Health endpoint test_api_auth.py # OAuth endpoint tests test_api_templates.py # Template listing + status tests test_api_migrate.py # Migration API tests test_e2e.py # Full pipeline end-to-end test test_regression.py # Compose output vs snapshots fixtures/expected/ # Regression snapshots (3 real templates) FIELD-TYPE-REGRESSION.md # Manual field type regression checklist PLATFORM-QUIRKS.md # Known API bugs and workarounds downloads/ # Downloaded Adobe Sign templates (gitignored) migration-output/ # Converted DocuSign template JSONs + history sample-templates/ # JSON fixtures for offline testing field-mapping.md # Field type mapping table + edge case log CLAUDE.md # Claude Code instructions for this project docs/IMPLEMENTATION-PLAN.md # Feature design and test specifications docs/agent-harness/ EXECUTION-BOARD.md # Living kanban board AGENT-INSTRUCTIONS.md # Definition of done + conventions requirements.txt # Python dependencies ```