Stage 2 final unit for Step 22 (user edit + export). u20 wires the previously placeholder bottom-action footer to the u18 /api/connect and u19 /api/export middlewares living in Front/vite.config.ts: - BottomActions.tsx • drops the dead `serializeSlidePlan` import (TS2305 blocker since u14; project-wide `tsc --noEmit` now exits 0) • exports three pure builders for vitest (no jsdom / RTL devDep needed): buildConnectRequest(run_id, slug) -> POST /api/connect {run_id, slug} buildExportRequest(run_id) -> POST /api/export {run_id} buildDownloadFilename(run_id) -> "<run_id>.html" • handleExport: POST -> blob -> a[download] click chain; toast on success / failure / network error. • handleConnect: derives slug via deriveUserOverridesKey(uploadedFile.name) and PUTs to u18 cel mirror; reports assets_copied count. • both buttons disable when runMeta is null so the UI cannot fire requests with an undefined run_id. - Home.tsx • mounts <BottomActions/> in the footer with {slidePlan, runMeta, uploadedFile, isLoading, onGenerate}. • removes 2 of 3 placeholder `toast.info('… 준비 중입니다.')` buttons (LeftMdxPanel MDX-edit placeholder remains — out of u20 scope). • adds handleTextEdit (u15 wire to text_overrides axis) and handleStructureEdit (u15 wire to structure_overrides axis) to satisfy the SlideCanvas props introduced earlier in the u-series. - imp90_bottom_actions.test.ts (new) • 11 vitest specs locking the builder URL + JSON shape against u18/u19 middleware contracts. Verified 11/11 pass. Stage 4 verification (all PASS): • u20 vitest: 11/11 • u18/u19 endpoint vitest: 31/31 • npx tsc --noEmit: exit 0 (carry-forward TS2305 resolved) • backend pytest (u1~u9 + u17 print mode, 9 files): 185/185 Out of scope: • LeftMdxPanel.tsx:333 MDX-edit placeholder toast (separate unit) • #1 / #72 / #74 / #79 / #80 / #81 / #93 closed dependencies (no re-impl) • AI-generated HTML structure (Phase Z regression guard) • frame swap via structure_overrides (locked to slot_order + hidden_slots) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>