# Execution Board (Living Kanban) *Last updated: 2026-04-21 (post-redesign bug fixes + Phase 23)* --- ## Completed (v1 — CLI Pipeline) - [x] Adobe Sign OAuth setup + token auto-refresh (`src/auth_adobe.py`, `src/adobe_api.py`) ✅ - [x] Template download pipeline — metadata, fields, docs, PDF (`src/download_templates.py`) ✅ - [x] Field type mapping — all major Adobe field types → DocuSign tabs ✅ (see `field-mapping.md`) - [x] Coordinate system fix — y passthrough (top-origin, no conversion needed) ✅ - [x] Conditional logic mapping → `conditionalParentLabel/Value` ✅ (see `validation/conditional-logic-eval.md`) - [x] DocuSign template JSON composition (`src/compose_docusign_template.py`) ✅ - [x] DocuSign JWT upload (`src/upload_docusign_template.py`) ✅ - [x] Regression checklist for all field types ✅ (see `tests/FIELD-TYPE-REGRESSION.md`) - [x] End-to-end round-trip test (3 real Adobe templates → DocuSign) ✅ --- ## Phase 1 — Idempotent Upload ✅ (2026-04-17) - [x] Add `find_existing_template(name)` to `upload_docusign_template.py` — lists DS templates by name, returns most-recently-modified match - [x] Change `upload_template()` to upsert: PUT if match found, POST if not - [x] Add `--force-create` CLI flag to bypass upsert - [x] Write `tests/test_upload_upsert.py` — 4 tests passing --- ## Phase 2 — FastAPI Backend Foundation ✅ (2026-04-17) - [x] Add new dependencies to `requirements.txt` - [x] Create `web/` directory structure (app.py, config.py, session.py, routers/, static/) - [x] Implement `GET /health` endpoint - [x] Write `tests/test_api_health.py` — 2 tests passing --- ## Phase 3 — Auth Endpoints ✅ (2026-04-17) - [x] Implement Adobe Sign OAuth start + callback + disconnect in `web/routers/auth.py` - [x] Implement DocuSign OAuth start + callback + disconnect - [x] Implement `GET /api/auth/status` - [x] Write `tests/test_api_auth.py` — 4 tests passing --- ## Phase 4 — Template Listing API ✅ (2026-04-17) - [x] Implement `GET /api/templates/adobe` in `web/routers/templates.py` - [x] Implement `GET /api/templates/docusign` - [x] Implement `GET /api/templates/status` — computes `not_migrated / migrated / needs_update` - [x] Write `tests/test_api_templates.py` — 7 tests passing --- ## Phase 5 — Migration API ✅ (2026-04-17) - [x] Implement `POST /api/migrate` in `web/routers/migrate.py` — download → compose → upsert pipeline - [x] Implement `GET /api/migrate/history` — reads/writes `migration-output/.history.json` - [x] Write `tests/test_api_migrate.py` — 7 tests passing --- ## Phase 6 — Frontend ✅ (2026-04-17) - [x] Create `web/static/index.html` — side-by-side template browser layout - [x] Create `web/static/app.js` — auth status check, template listing, migrate flow, history - [x] Create `web/static/style.css` — status badges, layout --- ## Phase 7 — End-to-End & Regression ✅ (2026-04-17) - [x] Write `tests/test_e2e.py` — 7-step full pipeline test, 1 test passing - [x] Write `tests/test_regression.py` — compose pipeline vs snapshots, 4 tests passing - [x] Create `tests/fixtures/expected/` — snapshot JSONs for David Tag Demo, NDA, Rob Test - [x] Full suite: **29/29 passing** --- ## Phase 8 — Normalized Intermediate Schema ✅ (2026-04-21) - [x] Create `src/models/` package with `__init__.py` - [x] Implement `src/models/normalized_template.py` — pydantic model with NormalizedTemplate, NormalizedField, NormalizedRole, NormalizedDocument - [x] Implement `src/services/` package with `__init__.py` - [x] Implement `src/services/mapping_service.py` — Adobe Sign folder → NormalizedTemplate converter with checksums - [x] Write `tests/test_normalized_schema.py` — 13 tests passing (model construction, serialization, real fixture round-trips) - [x] Update README --- ## Phase 9 — Validation Service ✅ (2026-04-21) - [x] Implement `src/services/validation_service.py` — `ValidationResult(blockers, warnings)`, checks for no recipients, no documents, no fields, missing roles, unsupported features - [x] Implement `src/reports/report_builder.py` — `MigrationReport`, `TemplateReport`, `MigrationStatus` enum, factory functions - [x] Integrate validation into migration pipeline (`_run_validation` in `web/routers/migrate.py`) — blocks on blockers - [x] Implement `compare_field_counts(normalized, ds_template)` post-migration check - [x] Write `tests/test_validation_service.py` — 20 tests passing - [x] Update README --- ## Phase 10 — Migration Options API ✅ (2026-04-21) - [x] Extend `POST /api/migrate` request body: `source_template_ids[]`, `target_folder`, `options.dry_run`, `options.overwrite_if_exists`, `options.include_documents` - [x] Implement dry-run path — validate + compose without creating DocuSign templates (`status=dry_run`) - [x] Implement `overwrite_if_exists=false` — skip already-migrated templates (`status=skipped`) - [x] Implement `include_documents` toggle — strips `documentBase64` from payload when false - [x] Keep backward compatibility with legacy `adobe_template_ids` field - [x] Write `tests/test_migration_options.py` — 7 tests passing - [x] Update README --- ## Phase 11 — Rate Limiting & Retry with Backoff ✅ (2026-04-21) - [x] Implement `src/utils/retry.py` — `retry_with_backoff` (sync) and `async_retry_with_backoff` decorators with exponential backoff + max_delay cap - [x] Implement `check_response_retryable(status_code)` — returns True for 429/500/502/503/504 - [x] Write `tests/test_retry.py` — 14 tests passing (exponential delay, max delay, exception filtering, async) - [x] Update README --- ## Phase 12 — Security Hardening & Audit Trail ✅ (2026-04-21) - [x] Implement `src/utils/log_sanitizer.py` — `redact()`, `redact_dict()`, `SanitizingFilter`, `install_sanitizing_filter()` - [x] Redacts: Bearer tokens, JWT-style tokens, key=value secret assignments, long base64 payloads (PDF content) - [x] PDF checksum (SHA-256) computed in `mapping_service.adobe_folder_to_normalized()` and stored in `NormalizedDocument.checksum_sha256` - [x] Write `tests/test_security.py` — 15 tests passing - [x] Update README --- ## Phase 13 — Batch Migration API ✅ (2026-04-21) - [x] Implement `POST /api/migrate/batch` — async background job, returns `job_id` immediately - [x] Implement `GET /api/migrate/batch/{job_id}` — poll job status, progress, results, summary - [x] Implement retry for failed templates (one retry on upload failures) - [x] In-memory job store with progress tracking (`_batch_jobs` dict) - [x] Write `tests/test_batch_migration.py` — 6 tests passing - [x] Update README --- ## Full Test Suite ✅ (2026-04-21) **108/108 tests passing** --- ## UI Redesign — Phases 14–22 (in progress) *Full plan: `docs/UI-REDESIGN-PLAN.md`* ### Phase 14 — App Shell & Navigation ✅ (2026-04-21) - [x] Rewrite `index.html` as app shell (left nav, router outlet, top bar) - [x] `css/tokens.css` — Docusign 2024 brand custom properties - [x] `css/base.css` — reset, Inter font, utility classes - [x] `css/nav.css` — Inkwell sidebar, logo, nav links, project footer - [x] `js/utils.js` — escHtml, formatDate, debounce, uuid - [x] `js/router.js` — hash-based router (#/templates default) - [x] `js/state.js` — global state with pub/sub - [x] `js/api.js` — fetch wrappers for all existing endpoints - [x] `js/auth.js` — auth chips, Adobe OAuth dialog, toast notifications - [x] `js/app.js` — entry point wiring router, auth, nav badges ### Phase 15 — Project / Customer Context ✅ (2026-04-21) - [x] `js/project.js` — project CRUD (localStorage) - [x] Project switcher modal (list, create, delete, activate) - [x] First-run experience (auto-open modal if no projects) - [x] Active project name in nav footer ### Phase 16 — Templates View with Readiness Badges ✅ (2026-04-21) - [x] Backend: add `blockers[]` + `warnings[]` to `GET /api/templates/status` - [x] 3 new backend tests (10 total in test_api_templates.py) - [x] `js/templates.js` — filterable/sortable table with readiness badges - [x] Template detail view (3 tabs: Overview, Issues, Migration History) - [x] `css/cards.css` — badge styles, table hover, bulk toolbar ### Phase 17 — Migration Workflow UI ✅ (2026-04-21) - [x] Options modal (dry_run, overwrite, include_documents, target folder) - [x] Progress view with batch job polling (every 2s) - [x] `js/migration.js` — showOptionsModal, runMigration, pollJob, renderResults - [x] Results view (#/results) with summary + export CSV - [x] `css/modals.css` ### Phase 18 — Issues & Warnings View ✅ (2026-04-21) - [x] `js/issues.js` — issues view (Blockers + Warnings sections) - [x] Nav badge showing blocked template count ### Phase 19 — Verification View + API ✅ (2026-04-21) - [x] `web/routers/verify.py` — POST /send, GET /status/{id}, POST /void/{id} - [x] Register verify router in `web/app.py` - [x] `tests/test_api_verify.py` — 7 tests passing - [x] `js/verification.js` — send test envelope, poll status, void ### Phase 20 — History & Audit View ✅ (2026-04-21) - [x] `js/history.js` — filterable history table, expand row, export CSV - [x] Checksum display (first 8 chars, full on hover) ### Phase 21 — Settings View ✅ (2026-04-21) - [x] `js/settings.js` — 3 sections (verification defaults, migration defaults, connection info) - [x] `css/forms.css` ### Phase 22 — Smoke Test Checklist & Cleanup ✅ (2026-04-21) - [x] `tests/UI-SMOKE-TEST.md` — manual test checklist (11 sections, 55 steps) - [x] Full backend test suite: **118/118 tests passing** - [x] Update `README.md` — new UI navigation guide, workflow, project context - [x] Update EXECUTION-BOARD.md — all phases complete - [x] Push `ui-redesign` branch to Gitea - [x] Open PR to `master` --- ## Post-Redesign Bug Fixes ✅ (2026-04-21) Bugs discovered during live testing after Phase 22. - [x] **Docusign branding** — replaced all "DocuSign" with "Docusign" (2024 brand) across 8 frontend files - [x] **Template detail routing** — `router.js` `parseHash` used wrong slice indices (`slice(0,3)` instead of `slice(0,2)`), causing `#/templates/:id` to always fall through to the list view - [x] **Migration polling infinite loop** — `pollJob` only checked `'done'`/`'complete'` but backend emits `'completed'`; migration progress spinner never resolved - [x] **Verification envelope role names** — hardcoded `roleName: "Signer"` meant envelopes sent without tags; now fetches actual template role names from Docusign API before sending, falls back to `"Signer"` only on fetch failure - [x] **Verification polling rate** — changed from 5 s to 30 s per Docusign rate-limit guidance; added 5-minute timeout with amber "Timed Out" badge; note: production should use Docusign Connect webhooks - [x] **CONDITIONALTAB_HAS_INVALID_PARENT (400)** — compose was emitting `conditionalParentLabel` pointing to signature/auto-fill tabs (forbidden as parents) or to fields on different recipients (cross-recipient). Fixed by post-processing strip pass in `_strip_invalid_conditionals` - [x] **Migration modal failure UX** — failed/blocked rows now show the error message in small red text beneath the template name; completion summary shows count + "select View Results for details" hint - [x] **Template detail history tab** — migration history rows with errors/blockers/warnings now expand inline (matching History & Audit behaviour) --- ## Phase 23 — Structured Field Issue Reporting ✅ (2026-04-21) - [x] `src/models/field_issue.py` — `FieldIssue` dataclass with `code`, `field_name`, `message`, `severity`; 7 named codes: `CROSS_RECIPIENT_CONDITIONAL`, `UNSUPPORTED_OPERATOR`, `HIDE_ACTION`, `MULTI_PREDICATE`, `INVALID_PARENT_TAB`, `FIELD_TYPE_SKIPPED`, `PARTIAL_FIELD_TYPE` - [x] `src/compose_docusign_template.py` — all warning paths now also emit structured `FieldIssue`; cross-recipient detection added (builds `{field_name → assignee}` map, checks predicate fieldName assignee before applying conditional); return signature changed to `(template, warnings, issues)` - [x] `web/routers/migrate.py` — captures `field_issues` from compose result; all `_migrate_one` return paths include `field_issues: []` - [x] `web/static/js/utils.js` — `renderFieldIssues()` groups issues by code in collapsible sections; `bindFieldIssueToggles()` wires expand/collapse - [x] `web/static/js/migration.js` — results view: ⚠️ icon + amber **partial** badge for success-with-issues; field issue groups in expanded rows - [x] `web/static/js/history.js` — amber **partial** badge + field issue groups in expanded rows - [x] `web/static/js/templates.js` — template detail history tab shows field issues with partial badge per record - [x] `web/static/css/cards.css` — `.field-issues-block`, `.field-issue-group`, `.field-issue-row` styles - [x] `tests/test_regression.py` — updated for 3-tuple compose return - [x] `tests/test_api_verify.py` — updated for template role-fetch + added fallback test (9 tests) - [x] Full test suite: **119/119 tests passing** - [x] Updated `README.md`, `field-mapping.md`, `EXECUTION-BOARD.md` --- ## Gitea - [x] Committed and pushed all changes (2026-04-17) - [x] Committed Phase 8–13 work (ui-redesign branch, 2026-04-21) - [x] Committed UI mockup + Docusign 2024 brand (ui-redesign branch, 2026-04-21) - [x] Committed Phases 14–22 UI implementation (ui-redesign branch, 2026-04-21) - [x] Pushed ui-redesign branch to Gitea; PR #1 open against master --- ## Results & Lessons Learned - (2026-04-14) NDA, David Tag Demo, Rob Test all converted cleanly - (2026-04-15) Coordinate bug fixed — y is top-origin in both platforms, no conversion needed - (2026-04-15) Paul Adobe Template created via API; Company/Title fields require manual UI fix (API limitation) - (2026-04-17) v2 planning complete — idempotent upload + web UI implementation begins - (2026-04-21) Blueprint comparison complete — added normalized schema, validation service, migration options, rate-limit/retry, security hardening, and batch migration phases (Phases 8–13) - (2026-04-21) Phases 8–13 fully implemented — 108/108 tests passing on ui-redesign branch - (2026-04-21) Enterprise UI mockup designed — 8 screens, Docusign 2024 branding, official SVG logo embedded - (2026-04-21) UI Redesign plan written (Phases 14–22) — frontend-only except Phase 16 (readiness data) and Phase 19 (verify API) - (2026-04-21) Phases 14–22 fully implemented — 118/118 tests passing, enterprise UI complete - (2026-04-21) Post-redesign live testing found 7 bugs — all fixed (routing, polling, branding, verification role names, conditional parent 400s) - (2026-04-21) Phase 23 complete — structured field issue reporting end-to-end; 119/119 tests passing; cross-recipient conditional now explicitly detected and described rather than silently producing a 400