Go to file
Paul Huliganga 516af313a1 feat(ui-phase-14): app shell — Docusign nav, router, state, brand tokens
Replace monolithic app.js/style.css with a modular CSS+JS architecture:

CSS: tokens.css (Docusign 2024 brand tokens), base.css (reset, typography,
buttons, badges, cards, toggles), nav.css (Inkwell sidebar, topbar, auth
chips), cards.css (readiness badges, filter bar, bulk toolbar, issue/result
rows), modals.css (modal shell, options panel, project switcher), tables.css
(sortable headers, pagination, checksum display), forms.css (inputs, setting
rows, connection info).

JS: utils.js (escHtml, formatDate, downloadCsv, uuid), state.js (global
reactive state with pub/sub), api.js (fetch wrappers for all endpoints),
router.js (hash-based SPA router), auth.js (connect/disconnect chips,
Adobe OAuth dialog, toast notifications), app.js (entry point — wires
router, auth, nav badges, project display).

index.html: full app shell with official docusign SVG logo, 7 nav links,
top bar with auth chips, router outlet.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 11:24:06 -04:00
bulk-send Add bulk send prototype — script, sample CSV, and demo guide 2026-04-20 01:49:19 -04:00
docs docs(ui-redesign): implementation plan for Phases 14–22 + execution board update 2026-04-21 10:37:46 -04:00
sample-templates docs: README, platform quirks, validation notes, and sample reference data 2026-04-15 19:45:46 -04:00
src feat(phases-8-13): blueprint alignment — normalized schema, validation, migration options, retry, security, batch 2026-04-21 02:19:38 -04:00
tests feat(phases-8-13): blueprint alignment — normalized schema, validation, migration options, retry, security, batch 2026-04-21 02:19:38 -04:00
validation Add latest migration files and validation outputs 2026-04-20 01:12:46 -04:00
web feat(ui-phase-14): app shell — Docusign nav, router, state, brand tokens 2026-04-21 11:24:06 -04:00
.env-adobe Add latest migration files and validation outputs 2026-04-20 01:12:46 -04:00
.env-sample chore: add .env-sample with all required environment variables 2026-04-16 10:10:28 -04:00
.gitignore chore: gitignore PDFs, private.key, and .env-orig 2026-04-16 12:35:20 -04:00
Adobe to Docusign Template migration Tool Blueprint.docx feat(ui-mockup): interactive migration console mockup with Docusign 2024 brand 2026-04-21 10:02:30 -04:00
CLAUDE.md docs: update README with web UI + upsert docs; add CLAUDE.md and AGENT-INSTRUCTIONS 2026-04-17 15:06:50 -04:00
PRODUCT-SPEC.md feat(phases-8-13): blueprint alignment — normalized schema, validation, migration options, retry, security, batch 2026-04-21 02:19:38 -04:00
PROJECT-SETUP.md Initial project scaffold (Cleo) 2026-04-14 19:21:17 -04:00
README.md feat(phases-8-13): blueprint alignment — normalized schema, validation, migration options, retry, security, batch 2026-04-21 02:19:38 -04:00
adobe_api.py:Zone.Identifier Add latest migration files and validation outputs 2026-04-20 01:12:46 -04:00
adobe_auth.py:Zone.Identifier Add latest migration files and validation outputs 2026-04-20 01:12:46 -04:00
api-samples.md Initial project scaffold (Cleo) 2026-04-14 19:21:17 -04:00
compose_docusign_template.py:Zone.Identifier Add latest migration files and validation outputs 2026-04-20 01:12:46 -04:00
conftest.py feat: idempotent upload + FastAPI web UI with full test coverage 2026-04-17 14:47:27 -04:00
field-mapping.md feat: map Adobe Sign conditional logic to DocuSign conditionalParentLabel/Value 2026-04-16 12:18:48 -04:00
requirements.txt feat: idempotent upload + FastAPI web UI with full test coverage 2026-04-17 14:47:27 -04:00

README.md

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:

pip install -r requirements.txt

2. Create a .env file in the project root (never commit this):

cp .env-sample .env

Then fill in your credentials. See .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):

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):

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:

python3 src/download_templates.py list

Download templates:

python3 src/download_templates.py download                  # all templates
python3 src/download_templates.py download "Template Name" # one specific template

Downloads to downloads/<template-name>__<id>/ — one folder per template containing metadata.json, form_fields.json, documents.json, and the PDF.

Convert a downloaded template to DocuSign format:

python3 src/compose_docusign_template.py

Writes DocuSign template JSONs to migration-output/<template-name>/docusign-template.json.

Upload to DocuSign (upsert by default):

python3 src/upload_docusign_template.py --file migration-output/<name>/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:

python3 src/upload_docusign_template.py --file <path> --force-create

Or run the full pipeline end-to-end:

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=<any random string>
DOCUSIGN_CLIENT_SECRET=<your DocuSign app 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:

uvicorn web.app:app --reload --port 8000

Then open 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


Running tests

pytest tests/ -v                           # full suite (108 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 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 for documented platform bugs, unexpected API behaviors, and the fixes applied.


Migration API options

POST /api/migrate accepts extended options (blueprint-aligned):

{
  "source_template_ids": ["tpl_001", "tpl_002"],
  "target_folder": "Migrated Templates",
  "options": {
    "dry_run": false,
    "overwrite_if_exists": false,
    "include_documents": true
  }
}
Option Default Description
dry_run false Validate and compose without creating DocuSign templates
overwrite_if_exists false If false, skip templates that already exist in DocuSign
include_documents true Embed PDFs in the DocuSign template

Batch migration (POST /api/migrate/batch) runs the same pipeline for multiple templates as a background job:

# Start batch
curl -X POST /api/migrate/batch -d '{"source_template_ids": ["id1", "id2"]}'
# → {"job_id": "abc-123", "status": "queued"}

# Poll status
curl /api/migrate/batch/abc-123
# → {"status": "running", "progress": {"completed": 1, "total": 2}, ...}

Normalized intermediate schema

The migration pipeline uses a platform-agnostic NormalizedTemplate model as a bridge between Adobe Sign and DocuSign. This decouples extraction from composition and enables the validation layer.

See src/models/normalized_template.py and src/services/mapping_service.py.


Validation

Each template is validated before migration:

  • Blockers (halt migration): no recipients, no documents
  • Warnings (logged but continue): no signature fields, unassigned fields, unsupported features

Unsupported features flagged for manual review: conditional HIDE actions, JavaScript validators, calculated fields, webhook associations, niche authentication methods.


Security

  • src/utils/log_sanitizer.py — install SanitizingFilter to redact tokens, keys, and base64 PDF content from all log output
  • PDF checksums (SHA-256) are computed and stored with each migration record
  • Tokens are never written to logs; see src/utils/log_sanitizer.py

Project structure

src/
  models/
    normalized_template.py       # Platform-agnostic intermediate schema
  services/
    mapping_service.py           # Adobe Sign → NormalizedTemplate converter
    validation_service.py        # Pre/post migration checks (blockers + warnings)
  reports/
    report_builder.py            # Structured migration report per template
  utils/
    retry.py                     # Exponential backoff retry helpers
    log_sanitizer.py             # Secret redaction from logs
  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)

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, batch, + 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_normalized_schema.py      # Normalized model + mapping service tests
  test_validation_service.py     # Validation service + report builder tests
  test_migration_options.py      # dryRun, overwriteIfExists, includeDocuments
  test_batch_migration.py        # Batch migration API tests
  test_retry.py                  # Retry with backoff utility tests
  test_security.py               # Log sanitization + PDF checksum 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)

downloads/                       # Downloaded Adobe Sign templates (gitignored)
migration-output/                # Converted DocuSign template JSONs + history
field-mapping.md                 # Field type mapping table + edge case log
PRODUCT-SPEC.md                  # Full product specification (blueprint-aligned)
docs/agent-harness/
  EXECUTION-BOARD.md             # Living kanban board
requirements.txt                 # Python dependencies