docs: update README and field-mapping to reflect current codebase
README: - Remove Node.js prerequisite (upload now handled by Python script) - Complete .env template with all DocuSign JWT auth keys - Add DocuSign consent step to setup instructions - Update all script examples: download_templates subcommands, Python upload, migrate_template.py replacing migrate_paul_template.py - Update project structure to include all current src files field-mapping.md: - Replace incorrect coordinate translation note with confirmed behaviour: both platforms use top-left origin, direct pass-through with MIN_TEXT_WIDTH floor - Add dedicated Multi-location (Cloned) Fields section documenting tab merging and which tab types support it - Replace vague To Do items with accurate known gaps (conditional logic, formula fields, advanced validation) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e30e9d4f14
commit
780099172f
88
README.md
88
README.md
|
|
@ -8,16 +8,16 @@ It downloads templates via the Adobe Sign API, converts them to DocuSign format,
|
||||||
## What it does
|
## What it does
|
||||||
|
|
||||||
1. **Authenticates** with Adobe Sign via OAuth (one-time browser flow, tokens saved to `.env`)
|
1. **Authenticates** with Adobe Sign via OAuth (one-time browser flow, tokens saved to `.env`)
|
||||||
2. **Downloads** all visible library templates — PDF, metadata, and form field definitions
|
2. **Downloads** templates — PDF, metadata, and form field definitions
|
||||||
3. **Converts** each template to a DocuSign `envelopeTemplate` JSON, mapping all field types, coordinates, and recipient roles
|
3. **Converts** each template to a DocuSign `envelopeTemplate` JSON, mapping all field types, coordinates, and recipient roles
|
||||||
4. **Uploads** the converted template to DocuSign
|
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
|
## Prerequisites
|
||||||
|
|
||||||
- Python 3.10+
|
- Python 3.10+
|
||||||
- Node.js 18+ (for the DocuSign upload CLI — uses the `esign-direct` package)
|
|
||||||
- An Adobe Sign OAuth app (EU2 shard) with scopes: `library_read:self library_write:self user_read:self`
|
- 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
|
- A DocuSign developer account with an integration key and RSA keypair
|
||||||
|
|
||||||
|
|
@ -32,33 +32,56 @@ pip install -r requirements.txt
|
||||||
|
|
||||||
**2. Create a `.env` file** in the project root (never commit this):
|
**2. Create a `.env` file** in the project root (never commit this):
|
||||||
```
|
```
|
||||||
|
# Adobe Sign
|
||||||
ADOBE_CLIENT_ID=your-adobe-client-id
|
ADOBE_CLIENT_ID=your-adobe-client-id
|
||||||
ADOBE_CLIENT_SECRET=your-adobe-client-secret
|
ADOBE_CLIENT_SECRET=your-adobe-client-secret
|
||||||
ADOBE_REDIRECT_URI=https://localhost:8080/callback
|
|
||||||
ADOBE_BASE_URL=https://api.eu2.adobesign.com/api/rest/v6/
|
|
||||||
|
|
||||||
|
# DocuSign
|
||||||
|
DOCUSIGN_CLIENT_ID=your-integration-key
|
||||||
|
DOCUSIGN_CLIENT_SECRET=your-client-secret
|
||||||
|
DOCUSIGN_USER_ID=your-docusign-user-guid
|
||||||
DOCUSIGN_ACCOUNT_ID=your-docusign-account-id
|
DOCUSIGN_ACCOUNT_ID=your-docusign-account-id
|
||||||
DOCUSIGN_INTEGRATION_KEY=your-integration-key
|
|
||||||
DOCUSIGN_BASE_URL=https://demo.docusign.net/restapi
|
|
||||||
DOCUSIGN_PRIVATE_KEY_PATH=/path/to/private.key
|
DOCUSIGN_PRIVATE_KEY_PATH=/path/to/private.key
|
||||||
DOCUSIGN_USER_ID=your-docusign-user-id
|
DOCUSIGN_AUTH_SERVER=account-d.docusign.com
|
||||||
|
DOCUSIGN_BASE_URL=https://demo.docusign.net/restapi
|
||||||
|
DOCUSIGN_REDIRECT_URI=http://localhost:8080/callback
|
||||||
```
|
```
|
||||||
|
|
||||||
|
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):
|
**3. Authenticate with Adobe Sign** (one-time):
|
||||||
```bash
|
```bash
|
||||||
python3 src/auth_adobe.py
|
python3 src/auth_adobe.py
|
||||||
```
|
```
|
||||||
This opens a browser. After authorizing, paste the redirect URL back into the terminal. Tokens are saved to `.env` and auto-refreshed on subsequent runs.
|
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
|
## Running a migration
|
||||||
|
|
||||||
**Download all templates from Adobe Sign:**
|
**List available templates in Adobe Sign:**
|
||||||
```bash
|
```bash
|
||||||
python3 src/download_templates.py
|
python3 src/download_templates.py list
|
||||||
```
|
```
|
||||||
Downloads to `downloads/<template-name>__<id>/` — one folder per template containing `metadata.json`, `form_fields.json`, `documents.json`, and the PDF.
|
|
||||||
|
**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/<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:**
|
**Convert a downloaded template to DocuSign format:**
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -68,24 +91,28 @@ Writes DocuSign template JSONs to `migration-output/<template-name>/docusign-tem
|
||||||
|
|
||||||
**Upload to DocuSign:**
|
**Upload to DocuSign:**
|
||||||
```bash
|
```bash
|
||||||
node packages/esign-direct/build/cli.js templates create --file migration-output/<name>/docusign-template.json
|
python3 src/upload_docusign_template.py --file migration-output/<name>/docusign-template.json
|
||||||
```
|
```
|
||||||
|
|
||||||
**Or run the full pipeline end-to-end for a specific template:**
|
**Or run the full pipeline end-to-end:**
|
||||||
```bash
|
```bash
|
||||||
python3 src/migrate_paul_template.py
|
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
|
||||||
```
|
```
|
||||||
(Edit the `TEMPLATE_NAME` constant at the top of the script to target a different template. If multiple templates share the same name, the most recently modified one is used.)
|
If multiple templates share the same name, the most recently modified one is used.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Field type mapping
|
## Field type mapping
|
||||||
|
|
||||||
See [field-mapping.md](field-mapping.md) for the full Adobe Sign → DocuSign tab type table, including edge cases and known gaps.
|
See [field-mapping.md](field-mapping.md) for the full Adobe Sign → DocuSign tab type table,
|
||||||
|
including edge cases and known gaps.
|
||||||
|
|
||||||
## Known API quirks and bugs
|
## 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.
|
See [tests/PLATFORM-QUIRKS.md](tests/PLATFORM-QUIRKS.md) for documented platform bugs,
|
||||||
|
unexpected API behaviors, and the fixes applied.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -93,16 +120,21 @@ See [tests/PLATFORM-QUIRKS.md](tests/PLATFORM-QUIRKS.md) for documented platform
|
||||||
|
|
||||||
```
|
```
|
||||||
src/
|
src/
|
||||||
auth_adobe.py # One-time OAuth flow for Adobe Sign
|
auth_adobe.py # One-time OAuth flow for Adobe Sign
|
||||||
adobe_api.py # Adobe Sign API client (auto token refresh)
|
adobe_api.py # Adobe Sign API client (auto token refresh)
|
||||||
download_templates.py # Download all templates from Adobe Sign
|
download_templates.py # List and download templates from Adobe Sign
|
||||||
compose_docusign_template.py # Core conversion logic: Adobe → DocuSign JSON
|
compose_docusign_template.py # Core conversion: Adobe Sign → DocuSign JSON
|
||||||
migrate_paul_template.py # End-to-end runner (download → convert → upload)
|
docusign_auth.py # DocuSign JWT auth + one-time consent flow
|
||||||
|
upload_docusign_template.py # Upload a template JSON to DocuSign REST API
|
||||||
|
migrate_template.py # End-to-end 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
|
||||||
|
|
||||||
downloads/ # Downloaded Adobe Sign templates (gitignored)
|
downloads/ # Downloaded Adobe Sign templates (gitignored)
|
||||||
migration-output/ # Converted DocuSign template JSONs (gitignored)
|
migration-output/ # Converted DocuSign template JSONs (gitignored)
|
||||||
|
sample-templates/ # JSON fixtures for offline testing (PDFs gitignored)
|
||||||
|
|
||||||
field-mapping.md # Field type mapping table + edge case log
|
field-mapping.md # Field type mapping table + edge case log
|
||||||
tests/PLATFORM-QUIRKS.md # Known bugs and API quirks
|
tests/PLATFORM-QUIRKS.md # Known bugs and API quirks
|
||||||
requirements.txt # Python dependencies
|
requirements.txt # Python dependencies
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -45,17 +45,52 @@ Source: Adobe Sign UI "Change field type" dropdown (all 15 types) + API field da
|
||||||
- Parallel routing → Recipient routing order logic (sequential/parallel in DocuSign)
|
- Parallel routing → Recipient routing order logic (sequential/parallel in DocuSign)
|
||||||
- Conditional logic → Needs review, possible via DocuSign conditional tabs/logic
|
- Conditional logic → Needs review, possible via DocuSign conditional tabs/logic
|
||||||
|
|
||||||
## Transform Formulas & Known Mapping Gaps
|
## Coordinate System
|
||||||
|
|
||||||
- **Coordinate translation:** If Adobe origin differs from DocuSign, map as:
|
Both Adobe Sign and DocuSign measure field positions from the **top-left corner** of the
|
||||||
`docusign_left = adobe_left // or apply offset, scale, etc.`
|
page with y increasing downward — no coordinate inversion is needed. The conversion is
|
||||||
- **Radio group flattening:** Merge Adobe radios with `radioGroup` into DocuSign `radio` tab, setting all options explicitly.
|
a direct pass-through:
|
||||||
- **Missing/ambiguous features:**
|
|
||||||
- DocuSign formulas (no mapping in Adobe Sign) — flag for manual rewrite
|
```
|
||||||
- Adobe advanced field validations (regex, custom scripts) — usually skipped or mapped to best-effort validation in DocuSign
|
docusign_xPosition = adobe_location.left
|
||||||
|
docusign_yPosition = adobe_location.top
|
||||||
|
docusign_width = max(adobe_location.width, MIN_TEXT_WIDTH) # 120pt floor
|
||||||
|
docusign_height = adobe_location.height
|
||||||
|
```
|
||||||
|
|
||||||
|
`MIN_TEXT_WIDTH = 120` is enforced on all text-entry tabs so they render as visible
|
||||||
|
input boxes rather than vertical lines (DocuSign renders zero-width tabs as a thin line).
|
||||||
|
|
||||||
|
## Multi-location (Cloned) Fields
|
||||||
|
|
||||||
|
Adobe Sign allows a single field definition to have multiple `locations` — the field
|
||||||
|
appears in several places on the document and all instances stay in sync.
|
||||||
|
|
||||||
|
DocuSign replicates this via **tab merging**: multiple tabs that share the same
|
||||||
|
`tabLabel` automatically sync their value at signing time. The compose script emits
|
||||||
|
one tab per location for all data-entry tab types. Radio groups are handled differently
|
||||||
|
— each location is a separate radio button within the same group, not a clone.
|
||||||
|
|
||||||
|
Tab types that support merging (one tab emitted per location):
|
||||||
|
`textTabs`, `numberTabs`, `dateTabs`, `dateSignedTabs`, `fullNameTabs`,
|
||||||
|
`emailAddressTabs`, `companyTabs`, `titleTabs`, `listTabs`, `checkboxTabs`
|
||||||
|
|
||||||
|
Tab types that do not merge (only first location used or handled specially):
|
||||||
|
`signHereTabs`, `initialHereTabs` — each location is an independent signing action
|
||||||
|
`radioGroupTabs` — each location is one radio button within the group
|
||||||
|
`signerAttachmentTabs` — each location is an independent attachment request
|
||||||
|
|
||||||
|
## Known Gaps
|
||||||
|
|
||||||
|
- **Conditional logic**: Adobe Sign conditional show/hide rules are not mapped.
|
||||||
|
DocuSign supports conditional tabs but the logic structure differs — manual
|
||||||
|
rewrite required per template.
|
||||||
|
- **DocuSign formula fields**: No Adobe Sign equivalent — flag for manual rewrite.
|
||||||
|
- **Advanced field validation**: Adobe regex/custom script validation is not mapped;
|
||||||
|
best-effort via standard DocuSign validation types only.
|
||||||
|
- **Radio group flattening**: Adobe radios with `radioGroup` are merged into a single
|
||||||
|
DocuSign `radioGroupTabs` entry with per-location radio button coordinates.
|
||||||
|
|
||||||
## To Do
|
## To Do
|
||||||
- Add table for conditional logic/rule mapping
|
- Add conditional logic/rule mapping table
|
||||||
- Add validation/transforms needed for field masks, validation, default values
|
- Document field mask and default value transforms
|
||||||
- Document more edge cases as they are discovered in real samples
|
|
||||||
- Collect pain points/edge cases for high-fidelity migration
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue