DocuSign returns CONDITIONALTAB_HAS_INVALID_PARENT when a conditional tab
references a parent that doesn't exist or is a forbidden type (signature,
initial, auto-filled). Added _strip_invalid_conditionals() post-processing
pass that validates all conditionalParentLabel values against the actual
built tabs and removes any that won't pass DocuSign validation, logging a
warning for each. Also updated verify tests for the template role-fetch step.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rows with errors, blockers, or warnings now show a '▶ click for details'
hint and expand inline on click, matching the behaviour in History & Audit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Failed/blocked rows now show the error message or first blocker in small
red text below the template name. On completion, if any templates failed
a count + "select View Results for details" hint appears above the footer.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
DocuSign rate-limit guidance discourages polling more than once per 15 min
in production. For this manual quick-test flow, 30s intervals with a 5-min
ceiling is a reasonable middle ground. Production should migrate to DS Connect
(webhooks). Timed-out envelopes show an amber badge with Send Again action.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Hardcoded "Signer" roleName caused envelopes to send without tags. Now
fetches template recipients first and assigns test recipient to every role,
falling back to "Signer" only if the template fetch fails.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend returns "completed" but pollJob only checked "done"/"complete",
causing infinite polling and oscillating UI state.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
parts.slice(0,3) was returning the full path as base; should be slice(0,2)
so '#/templates/abc123' yields base='#/templates', param='abc123'.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GET /api/auth/{adobe,docusign}/connect and /disconnect — not POST.
api.js was calling them with POST, causing 405 Method Not Allowed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three sections: Verification (test recipient name/email, auto-void timer),
Migration Defaults (overwrite toggle, include documents toggle), Connections
(read-only auth status + account IDs from /api/auth/status). Save writes to
localStorage key 'migrator_settings'. Values pre-read by migration options
modal and verification send dialog.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Filterable by template name, status (success/error/dry_run/skipped), and
date range. Sortable by all columns. Expandable rows show blockers/warnings.
Checksum displayed as first 8 chars with full hash on hover tooltip.
Client-side CSV export. 50 records per page with prev/next pagination.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend (web/routers/verify.py): POST /send (creates envelope from template),
GET /status/{id} (polls envelope state), POST /void/{id} (voids test envelope).
Registered in app.py. 7 tests passing.
Frontend (verification.js): table of migrated templates, Send Test button opens
dialog with pre-filled name/email from settings, polling every 5s, per-row
status updates (Sent → Delivered → Verified), Void button for cleanup.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dedicated view surfacing all templates with blockers (migration will fail)
and warnings (migration with caveats). Each blocker item shows all error
messages; each warning item has a Migrate Anyway button and View Detail link.
Nav badge count driven by state.issueCount (updated when templates load).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend: add blockers[] and warnings[] to GET /api/templates/status. Calls
validate_template() on downloaded templates; returns empty lists if not
downloaded. 3 new tests (10 total, all passing).
Frontend (templates.js): filterable/sortable table with readiness badges
(Blocked/Caveats/Ready/Migrated/Needs Update), bulk-select toolbar,
per-row migrate/detail buttons, and template detail view with 3 tabs
(Overview, Issues, Migration History).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Projects stored in localStorage (key: migrator_projects). CRUD: create,
list, setActive, delete. Switcher modal opens automatically on first run
when no projects exist. Active project name displayed in nav footer and
project button. Deleting a project requires confirmation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Full UI redesign plan covering 9 phases: app shell, project/customer context,
templates view with readiness badges, migration workflow, issues view,
verification (with new verify API), history/audit, settings, and smoke test
checklist. Only backend additions are Phase 16 (blockers/warnings in status
endpoint) and Phase 19 (verify router). All other phases are frontend-only.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Embedded the official Docusign full-color vector logo sourced from
Wikimedia Commons (Docusign_Full_Color.svg, viewBox 0 0 1200 241.4).
Wordmark paths changed to fill="#FFFFFF" for visibility on the Inkwell
(#130032) nav bar; Nexus icon retains brand colors (Cobalt #4C00FF,
Poppy #FF5252, white document shape). Brand name corrected to "docusign"
(capital D, lowercase s per 2024 rebrand).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- GET /api/auth/adobe/connect: reads ADOBE_REFRESH_TOKEN from .env,
refreshes the access token, stores in session — no login required
- Falls back to OAuth dialog only if no .env credentials exist
- Restores DocuSign OAuth start/callback endpoints alongside JWT connect
- 33/33 tests passing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the DocuSign OAuth redirect flow with a direct JWT grant call
using credentials already in .env (same as the CLI). Clicking
"Connect DocuSign" now calls GET /api/auth/docusign/connect which calls
get_access_token() and stores the result in the session cookie.
No email sign-in required.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Adobe Sign OAuth app has https://localhost:8080/callback registered
(same as CLI). The web UI now uses the same manual paste flow:
- GET /api/auth/adobe/url returns the auth URL for the frontend to open
- POST /api/auth/adobe/exchange accepts the full redirect URL the user
copies after authorizing, extracts the code, exchanges for tokens
- Dialog UI guides user through the 3-step process
DocuSign keeps its standard redirect callback flow unchanged.
31/31 tests passing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PDFs are generated artifacts. private.key and .env-orig are secrets
that should never be tracked.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adobe Sign uses /oauth/v2/refresh (not /oauth/v2/token) for token
refresh — a deviation from the OAuth2 spec that caused all refresh
attempts to fail with a misleading "Invalid grant_type" error.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Setup step 2 now directs users to copy .env-sample instead of
repeating all variables inline
- "What it does" step 3 mentions conditional field logic
- Field type mapping section updated to mention conditional logic
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adobe Sign conditionalAction (SHOW/EQUALS) is now translated to
DocuSign's conditionalParentLabel + conditionalParentValue on the
dependent tab, making conditional fields work in the migrated template.
For radio groups, conditionalParentLabel matches the radio group name.
Unsupported cases emit warnings rather than silently dropping conditions:
- HIDE action (no DocuSign equivalent — field left always visible)
- Non-EQUALS operators (skipped)
- Multi-predicate ANY/ALL (first EQUALS predicate used, rest ignored)
Also updates field-mapping.md: adds Conditional Logic Mapping table
and moves this item out of Known Gaps into documented behaviour.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Documents every variable used across the project, grouped by service
(Adobe Sign and DocuSign), with comments explaining where to find each
value. Auto-written cache variables (tokens, expiry) are included but
left blank.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adobe STAMP (hanko/seal) has a direct DocuSign equivalent via
stampTabs. Previously marked as skipped with no equivalent.
- compose_docusign_template.py: emit stampTabs for STAMP input type;
PARTICIPATION_STAMP remains skipped (still no equivalent)
- field-mapping.md: update STAMP row, add stampTabs to multi-location
non-merging list, add account feature prerequisite to Known Gaps
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adobe Sign uses a non-standard separate endpoint for refresh:
/oauth/v2/refresh (not /oauth/v2/token). Using the wrong endpoint
returned a misleading "Invalid grant_type refresh_token" error.
Also:
- Remove redirect_uri from refresh requests (not required)
- Add clear RuntimeError message directing user to re-authenticate
- Validate access_token is non-empty before saving in adobe_auth.py
- Log token lengths and exchange response keys on successful auth
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Matches the naming convention of docusign_auth.py. Update all
references in README.md and the error message in adobe_api.py.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
README.md — rewritten to reflect actual usage: setup, auth flows, CLI
commands for all three scripts, and links to field-mapping and quirks docs.
tests/PLATFORM-QUIRKS.md — documents confirmed bugs and API quirks found
during development: numberTabs rendering as text+validation (DocuSign API
bug), multi-location field fix, zero-width tab fix, Company/Title contentType
SIGNER_ prefix variant from Adobe Sign API.
tests/ — SCENARIOS, EDGE-CASES, FIELD-TYPE-REGRESSION test planning docs.
validation/ — research notes: field eval, mapping ambiguity log, decision
log, conditional logic analysis, round-trip eval, DocuSign ingest eval.
docs/architecture.md — system architecture overview.
api-samples.md — annotated Adobe Sign API response examples.
PRODUCT-SPEC.md — product requirements and migration scope definition.
sample-templates/ — JSON fixtures (NDA, onboarding, sales contract) for
offline testing; PDFs excluded from version control.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
migrate_template.py — generic end-to-end CLI replacing the earlier
migrate_paul_template.py:
--list list available Adobe Sign templates
--template "Name" download → convert → upload a named template
--template "Name" --skip-upload convert only, write JSON to migration-output/
Picks most recently modified when multiple templates share a name.
create_adobe_template.py — utility for creating a test template in Adobe Sign
that exercises all 15+ field types. Uses the David Tag Demo Form PDF as the
base document and positions extra fields (Number, Email, Company, Title) in
the gaps of the original layout.
generate_pdfs.py — generates realistic sample PDFs with labelled form areas
matching the *-formfields.json fixtures in sample-templates/, for use in
offline testing without a live Adobe Sign account.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
docusign_auth.py — authentication helper supporting two flows:
- JWT Grant: service-to-service token generation using an RSA private key;
caches token + expiry in .env to avoid redundant round-trips
- Auth Code Grant (--consent): one-time browser flow to grant the app the
'impersonation' scope required for JWT; must be run once per user/app before
JWT will work
upload_docusign_template.py — posts a docusign-template.json to the DocuSign
Templates REST API (v2.1). No Node.js dependency. Retries once on 401.
requirements.txt — adds PyJWT>=2.0 and cryptography for RSA key handling.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
compose_docusign_template.py — converts a downloaded template folder into a
DocuSign envelopeTemplate JSON ready for the Templates API. Key behaviours:
- Full field type mapping: TEXT_FIELD, SIGNATURE, CHECKBOX, RADIO, DROP_DOWN,
BLOCK, FILE_CHOOSER (with warning), INLINE_IMAGE (skipped with warning)
- contentType dispatch: SIGNER_NAME → fullNameTabs, SIGNER_EMAIL →
emailAddressTabs, SIGNATURE_DATE → dateSignedTabs, COMPANY/SIGNER_COMPANY →
companyTabs, TITLE/SIGNER_TITLE → titleTabs, DATA+NUMBER → numberTabs,
DATA+DATE → dateTabs, SIGNER_INITIALS → initialHereTabs
- Multi-location (cloned) fields: emits one tab per location with the same
tabLabel so DocuSign tab merging replicates Adobe Sign's sync behaviour
- Width/height passed through from Adobe Sign locations; MIN_TEXT_WIDTH=120pt
ensures text fields render as visible boxes rather than vertical lines
- Coordinate system: both platforms use top-left origin — no inversion needed
test_mapping.py — unit test harness validating tab grouping and field mapping.
field-mapping.md — full Adobe Sign → DocuSign tab type reference table with
edge cases, known gaps, and decision log.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
download_templates.py — subcommand CLI for listing and downloading library
templates from Adobe Sign.
list — print all templates with name, modified date, ID
download — download all templates (default)
download --all — explicit download all
download "Name" — download a single named template; picks the most
recently modified if duplicates exist
Each template is saved to downloads/<name>__<id8>/ containing metadata.json,
form_fields.json, documents.json, and the source PDF.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
auth_adobe.py — one-time browser Auth Code Grant flow; saves access and
refresh tokens to .env. Targets the EU2 shard.
adobe_api.py — thin API client with auto token refresh on 401. Supports
GET, POST (JSON and multipart), PUT, and binary download.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>