adobe-to-docusign-migrator/docs/UI-REDESIGN-PLAN.md

18 KiB
Raw Permalink Blame History

UI Redesign — Implementation Plan

Branch: ui-redesign | Last updated: 2026-04-21


Overview

Replace the basic Phase 6 single-page app (web/static/) with the enterprise-grade migration console designed in docs/ui-mockup/mockup.html.

The backend is complete (Phases 813, 108/108 tests passing). All new UI phases are frontend-only unless noted. Existing FastAPI routes do not change except where noted under Phase 16 (readiness data) and Phase 19 (Verification API).

Design reference

Open docs/ui-mockup/mockup.html in a browser to see all 8 screens before starting.

Docusign 2024 brand tokens

Token Value Usage
Cobalt #4C00FF Primary CTA, active nav highlight
Inkwell #130032 Left nav background
Ecru #F8F3F0 Page background
Poppy #FF5252 Error / Blocked badge
Slate #6B6B9A Secondary text, muted labels
White #FFFFFF Card surfaces

Typography: Inter (Google Fonts), fallback -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif.


Current state

web/static/ — three files, ~600 lines total:

  • index.html — 79 lines, single-page layout (header, two panels, history table)
  • app.js — 343 lines, vanilla JS (auth, template list, migrate, history)
  • style.css — 186 lines, basic styles, non-Docusign colours

File structure after redesign

Keep no-build-step approach (vanilla JS ES modules, no bundler). Split monolith into logical files served statically by FastAPI.

web/static/
  index.html              # app shell (nav, router outlet, modals)
  css/
    tokens.css            # CSS custom properties (brand colours, spacing)
    base.css              # reset, typography, utility classes
    nav.css               # left sidebar nav + top bar
    cards.css             # template cards, readiness badges
    modals.css            # dialog / modal styles
    tables.css            # history and audit tables
    forms.css             # settings form inputs
  js/
    state.js              # global app state (project, auth, templates)
    router.js             # hash-based client-side router
    api.js                # thin fetch wrappers for all backend endpoints
    auth.js               # auth status, connect/disconnect, Adobe dialog
    project.js            # project switcher modal, project CRUD (localStorage)
    templates.js          # template list view, readiness badges, filters
    migration.js          # options modal, progress polling, results view
    verification.js       # send test envelope, poll status
    history.js            # history & audit view
    settings.js           # settings screen
    utils.js              # escHtml, formatDate, debounce, etc.

app.js and style.css are deleted (replaced by the above). index.html is rewritten as the app shell.


Phase 14 — App Shell & Navigation

Goal: Branded shell that all other views live inside. No functional logic yet — just the frame, router, and state container.

index.html structure

<body>
  <nav id="app-nav">           <!-- left sidebar, 220px, Inkwell bg -->
    <div id="nav-logo"></div> <!-- docusign SVG logo, white wordmark -->
    <ul id="nav-links"></ul>  <!-- 7 nav links with icons -->
    <div id="nav-project"></div> <!-- project switcher footer -->
  </nav>
  <div id="app-body">
    <header id="top-bar"></header>   <!-- breadcrumb + auth chips -->
    <main id="router-outlet"></main> <!-- views injected here -->
  </div>
  <!-- modal containers -->
  <div id="modal-overlay" hidden></div>
</body>

css/tokens.css

:root {
  --cobalt:  #4C00FF;
  --inkwell: #130032;
  --ecru:    #F8F3F0;
  --poppy:   #FF5252;
  --slate:   #6B6B9A;
  --white:   #FFFFFF;
  --success: #28A745;
  --warning: #F0A500;
  --border:  #E0DCF8;
  --radius-sm: 4px;
  --radius-md: 8px;
  --shadow-sm: 0 1px 4px rgba(0,0,0,0.08);
  --shadow-md: 0 4px 16px rgba(0,0,0,0.12);
}

js/router.js

const ROUTES = {
  '#/dashboard':  () => import('./templates.js').then(m => m.renderDashboard()),
  '#/templates':  () => import('./templates.js').then(m => m.renderTemplates()),
  '#/results':    () => import('./migration.js').then(m => m.renderResults()),
  '#/issues':     () => import('./issues.js').then(m => m.renderIssues()),
  '#/verify':     () => import('./verification.js').then(m => m.renderVerification()),
  '#/history':    () => import('./history.js').then(m => m.renderHistory()),
  '#/settings':   () => import('./settings.js').then(m => m.renderSettings()),
};
// Default route: #/templates

js/state.js

export const state = {
  project: null,          // { id, name } — loaded from localStorage
  auth: { adobe: false, docusign: false },
  templates: [],          // array from /api/templates/status
  selectedIds: new Set(),
  lastMigrationResults: null,  // results from most recent batch job
};
// Simple pub/sub: subscribe(key, fn) / publish(key)

js/api.js — endpoint wrappers

All existing endpoints wrapped:

export const api = {
  auth: {
    status:           () => GET('/api/auth/status'),
    connectAdobe:     () => POST('/api/auth/adobe/connect'),
    connectDocusign:  () => POST('/api/auth/docusign/connect'),
    exchangeAdobe:    (url) => POST('/api/auth/adobe/exchange', { redirect_url: url }),
    disconnect:       (p)  => POST(`/api/auth/${p}/disconnect`),
  },
  templates: {
    status:    () => GET('/api/templates/status'),
    adobe:     () => GET('/api/templates/adobe'),
    docusign:  () => GET('/api/templates/docusign'),
  },
  migrate: {
    run:         (body) => POST('/api/migrate', body),
    batch:       (body) => POST('/api/migrate/batch', body),
    batchStatus: (id)   => GET(`/api/migrate/batch/${id}`),
    history:     ()     => GET('/api/migrate/history'),
  },
};

js/utils.js

export const escHtml = str => String(str).replace(/[&<>"]/g, c => );
export const formatDate = iso => new Date(iso).toLocaleDateString();
export const formatRelative = iso => ;
export const debounce = (fn, ms) => {  };
export const uuid = () => crypto.randomUUID();

Commit

feat(ui-phase-14): app shell — nav, router, state, brand tokens


Phase 15 — Project / Customer Context

Goal: Project switcher so the same installation can manage migrations for multiple customers without mixing history or credentials.

Data model (localStorage only — no backend)

// Stored in localStorage key: 'migrator_projects'
{
  active: "uuid-1",
  projects: [
    { id: "uuid-1", name: "Acme Corp", createdAt: "2026-04-21T…" },
    { id: "uuid-2", name: "Globex Inc", createdAt: "2026-04-22T…" },
  ]
}

Credentials remain in the server-side signed cookie session. Switching projects triggers a fresh /api/auth/status check (session may still be valid if the user didn't disconnect).

js/project.js

export function listProjects() {  }       // returns projects array
export function createProject(name) {  }  // generates uuid, saves, returns project
export function deleteProject(id) {  }
export function getActive() {  }          // returns active project or null
export function setActive(id) {  }        // updates localStorage + triggers nav refresh

Project switcher modal

  • Opened by clicking project name in nav footer
  • Lists projects: name + creation date + "Activate" button
  • "New Project" inline form (name field + Create button)
  • Deleting a project requires confirmation ("Delete Acme Corp? This cannot be undone.")
  • First run: modal opens automatically with welcome copy

Shows ▸ Acme Corp (truncated to 18 chars). Clicking opens switcher modal. No project → shows ▸ New Project in amber.

Commit

feat(ui-phase-15): project switcher — localStorage CRUD, switcher modal


Phase 16 — Templates View with Readiness Badges

Goal: Replace the two-panel list with a filterable, sortable single table. Each row shows a readiness badge computed from validation results.

Readiness badge system

Badge Colour Condition
Ready --success green blockers=[], warnings=[]
Caveats --warning amber blockers=[], warnings.length > 0
Blocked --poppy red blockers.length > 0
Migrated --cobalt status=migrated and no blockers
Needs Update --warning amber status=needs_update
Verified green + ✓ post-migration verification passed (Phase 19)

Backend update required: web/routers/templates.py

Add blockers: list[str] and warnings: list[str] to each template object in GET /api/templates/status. Run validate_template() on the normalized form if the template has been downloaded; otherwise return empty lists.

# In templates.py status endpoint, for each adobe template:
normalized_dir = Path(settings.downloads_dir) / f"{template['name']}__{template['id']}"
if normalized_dir.exists():
    normalized = adobe_folder_to_normalized(str(normalized_dir))
    result = validate_template(normalized)
    blockers = result.blockers
    warnings = result.warnings
else:
    blockers, warnings = [], []

Add 3 backend tests to tests/test_api_templates.py:

  • test_status_includes_blockers_and_warnings_fields
  • test_status_blockers_populated_when_template_downloaded
  • test_status_empty_when_not_downloaded

js/templates.js

export function renderTemplates() {
  // Fetches state.templates (or refreshes via api.templates.status())
  // Renders filterable table into #router-outlet
  // Columns: ☐ | Name | Readiness | Fields | Last Modified | DS Status | Actions
  // Filter bar: search input + status dropdown + readiness dropdown
  // Bulk toolbar (hidden until ≥1 selected): "Migrate X selected" button
}

export function renderTemplateDetail(adobeId) {
  // 4-tab layout: Overview | Fields | Issues | Migration History
}

Template detail view (#/templates/:id)

  • Overview tab: name, description, roles, document count, last modified date
  • Fields tab: table of fields — type, label, page, role, required, conditional
  • Issues tab: blockers (red cards) + warnings (amber cards) from validation
  • Migration History tab: records from /api/migrate/history filtered to this template

Commit

feat(ui-phase-16): templates view — readiness badges, filters, detail tabs, backend blockers/warnings


Phase 17 — Migration Workflow UI

Goal: Options modal → progress view → results view as a cohesive flow.

Flow

Templates view → select ≥1 template → "Migrate Selected" button →
  Options modal → "Run Migration" →
  Progress view (replaces modal) →
  Results view (#/results)

js/migration.js

export function showOptionsModal(selectedIds) {
  // Renders modal with:
  //   - Dry run toggle (default: off)
  //   - Overwrite existing toggle (default: off, from settings)
  //   - Include documents toggle (default: on, from settings)
  //   - Target folder text input (optional)
  //   - Selected count display
  //   - "Run Migration" button
}

export async function runMigration(ids, options) {
  // Calls POST /api/migrate/batch
  // Returns job_id
}

export async function pollJob(jobId, onProgress, onComplete) {
  // Polls GET /api/migrate/batch/{jobId} every 2s
  // Calls onProgress({ completed, total, results })
  // Calls onComplete(finalResults) when status === 'done'
}

export function renderResults(jobResults) {
  // Navigates to #/results and renders:
  //   - Summary row: X Created | Y Updated | Z Skipped | W Blocked | V Errors
  //   - Per-template result table
  //   - "Verify Templates" button (pre-loads migrated IDs)
  //   - "Back to Templates" button
  //   - "Export CSV" button (client-side Blob download)
}

Progress view (inline, inside modal)

After "Run Migration" is clicked:

  • Modal content replaces with: progress bar + per-template status list
  • Each template row: name → spinning → success or error
  • "View Results" button appears when job status === 'done'

Commit

feat(ui-phase-17): migration workflow — options modal, progress polling, results view


Phase 18 — Issues & Warnings View

Goal: A dedicated screen to review all validation problems before migrating.

js/issues.js

export function renderIssues() {
  // Reads state.templates (already has blockers/warnings from Phase 16)
  // Renders two sections:
  //   BLOCKERS — templates that will fail migration
  //   WARNINGS — templates that will migrate with caveats
  // Each item: template name | issue message | suggested action link
  // "Migrate Anyway" button on warning items → showOptionsModal([id])
  // "View Template" link → #/templates/:id
}

Nav badge

Left nav Issues link shows a red badge with count of blocked templates. Updates whenever state.templates changes.

Commit

feat(ui-phase-18): issues view — blocked and warning templates, nav badge


Phase 19 — Verification View

Goal: Send test envelopes to confirm migrated templates work end-to-end.

New backend: web/routers/verify.py

POST /api/verify/send
  body: { template_id: str, recipient_name: str, recipient_email: str }
  action: GET /v2.1/accounts/{id}/envelopes  (create via template)
  returns: { envelope_id: str }

GET /api/verify/status/{envelope_id}
  action: GET /v2.1/accounts/{id}/envelopes/{envelopeId}
  returns: { status: str, completed_at: str | null }

POST /api/verify/void/{envelope_id}
  body: { reason: str }
  action: PUT envelope status to "voided"
  returns: { voided: true }

Register router in web/app.py: app.include_router(verify_router, prefix="/api/verify").

tests/test_api_verify.py

Four tests (all mock DocuSign calls with respx):

  • test_send_requires_auth
  • test_send_returns_envelope_id
  • test_status_returns_envelope_state
  • test_void_calls_docusign

js/verification.js

export function renderVerification(preloadedTemplateIds = []) {
  // Shows list of migrated templates (from history or passed-in IDs)
  // Per-template row:
  //   - Template name + DS template ID
  //   - "Send Test Envelope" button → opens send dialog
  //   - Status chip (Not Tested | Sent | Delivered | Completed = Verified | Voided)
  // Send dialog: recipient name + email (pre-filled from settings), "Send" button
  // After send: row updates with status, "Void" button, polling every 5s
}

Commit

feat(ui-phase-19): verification view + verify API endpoints (send/status/void)


Phase 20 — History & Audit View

Goal: Filterable, exportable migration history.

js/history.js

export function renderHistory() {
  // Calls GET /api/migrate/history
  // Renders:
  //   - Filter bar: date range, template name search, status filter
  //   - Table: timestamp | template | action | status | DS ID | warnings | checksum
  //   - Expandable row: full blockers/warnings list, field count diff
  //   - "Export CSV" button (client-side)
}

SHA-256 checksum: first 8 chars displayed, full value in title attribute (tooltip).

Commit

feat(ui-phase-20): history & audit view — filters, export, checksum display


Phase 21 — Settings View

Goal: Central config screen for verification defaults and migration defaults.

Settings (localStorage key: migrator_settings)

Key Default UI control
testRecipientName "" Text input
testRecipientEmail "" Email input
autoVoidHours 24 Number input
defaultOverwrite false Toggle
defaultIncludeDocs true Toggle

js/settings.js

export function renderSettings() {
  // 3 sections:
  //   1. Verification defaults (name, email, auto-void timer)
  //   2. Migration defaults (overwrite, include documents)
  //   3. Connection info (read-only: connected accounts, base URLs)
  // Save button writes to localStorage
  // Values pre-loaded into options modal (Phase 17) and send dialog (Phase 19)
}

Commit

feat(ui-phase-21): settings view — verification defaults, migration defaults


Phase 22 — Smoke Test Checklist & Cleanup

Goal: Validate the full redesigned UI works end-to-end, update docs.

tests/UI-SMOKE-TEST.md

Manual checklist:

  • First run: project switcher opens automatically
  • Create project "Test Customer", verify it appears in nav footer
  • Connect Adobe Sign via .env path → badge turns green
  • Connect DocuSign via JWT path → badge turns green
  • Templates view loads ≥1 template with correct readiness badge
  • Select 2 templates → options modal opens → dry run → results show dry_run status
  • Select 2 templates → real migration → progress bar counts up → results view
  • Navigate to Verification → Send Test → status updates to Completed
  • History view shows all migrations with correct counts and checksums
  • Issues view shows blocked templates (use a fixture template with no recipients)
  • Settings: save test recipient → reopen Settings → values persist

Final tasks

  • Run pytest tests/ -v — confirm all tests still pass (≥108 + new verify tests)
  • Update README.md — new UI navigation guide section
  • Update docs/agent-harness/EXECUTION-BOARD.md — Phases 1422 complete
  • Push ui-redesign branch to Gitea
  • Open PR to master

Commit

feat(ui-phase-22): smoke test checklist, README update, final cleanup


Dependency order

Phase 14 (Shell)
  └── Phase 15 (Project)
        └── Phase 16 (Templates + backend readiness data)
              ├── Phase 17 (Migration workflow)
              │     └── Phase 18 (Issues view)
              └── Phase 19 (Verification + verify API)

Phase 20 (History)   ← depends on Phase 14 only, can run after Phase 14
Phase 21 (Settings)  ← depends on Phase 14 only, can run after Phase 14

Phase 22 (Cleanup)   ← depends on all phases complete

Phases 20 and 21 can be implemented in parallel with Phases 1719.


What does NOT change

  • All existing FastAPI routes (auth.py, templates.py, migrate.py)
  • All backend Python source (src/)
  • All 108 existing tests
  • .env / credential handling
  • The CLI pipeline (src/migrate_template.py)

Only backend additions:

  1. Phase 16: blockers + warnings fields added to GET /api/templates/status
  2. Phase 19: New web/routers/verify.py with 3 envelope endpoints