Files
familysync/.planning/milestones/v1.1-phases/17-ui-optimization-polish/17-02-PLAN.md
T
2026-06-18 22:21:38 -04:00

14 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, user_setup, must_haves
phase plan type wave depends_on files_modified autonomous requirements user_setup must_haves
17-ui-optimization-polish 02 execute 1
apps/pwa/package.json
apps/pwa/pwa-assets.config.ts
apps/pwa/public/logo.svg
apps/pwa/public/favicon.svg
apps/pwa/public/favicon.ico
apps/pwa/public/icon-192.png
apps/pwa/public/icon-512.png
apps/pwa/public/icon-maskable-512.png
apps/pwa/public/apple-touch-icon.png
false
D-03
D-04
truths artifacts key_links
A real FamilySync logo (warm/rounded/at-home/caricature-family) exists as a committed SVG
All 7 branding assets exist in apps/pwa/public/ with correct formats and dimensions
A proper maskable 512 icon exists as its own file with the logo inside the 80% safe zone
The operator has approved the logo art AND selected the brand accent before wiring (next plan) is committed
path provides
apps/pwa/public/logo.svg Hand-authored source brand mark (BrandSlot img + icon derivation source)
path provides
apps/pwa/public/icon-maskable-512.png 512x512 maskable PWA icon with safe-zone padding
path provides
apps/pwa/pwa-assets.config.ts @vite-pwa/assets-generator config (minimal-2023 preset)
path provides
apps/pwa/package.json @vite-pwa/assets-generator devDependency + pwa:icons script
from to via pattern
apps/pwa/pwa-assets.config.ts apps/pwa/public/logo.svg images: ['public/logo.svg'] — generator reads the source SVG logo.svg
Generate the complete FamilySync branding asset set (D-03, D-04): hand-author a warm/rounded/at-home/caricature-family `logo.svg`, install `@vite-pwa/assets-generator` as a devDependency in `apps/pwa`, and derive the full icon/favicon set (`favicon.svg`, `favicon.ico`, `icon-192.png`, `icon-512.png`, a PROPER `icon-maskable-512.png` with real safe-zone padding, `apple-touch-icon.png`) using the `minimal-2023` preset. Then obtain explicit operator approval of the logo art AND the brand-accent selection at a blocking human checkpoint BEFORE any wiring is committed (wiring happens in plan 17-04).

This plan deliberately produces and commits ONLY the assets + generator config. The BrandSlot/index.html/vite.config.ts wiring is a separate plan (17-04) so the checkpoint gates the wiring, exactly as the phase contract requires.

Purpose: replace the placeholder icon stubs (icon-192.png 699 B, icon-512.png, apple-touch-icon.png 617 B) and fix the missing-favicon + improper-maskable defects with a coherent, approved brand identity. Output: 8 files (logo.svg + 6 derived assets + pwa-assets.config.ts), package.json devDep + script, and a recorded operator approval (logo art + accent choice).

<execution_context> @$HOME/.claude/gsd-core/workflows/execute-plan.md @$HOME/.claude/gsd-core/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/17-ui-optimization-polish/17-UI-SPEC.md @.planning/phases/17-ui-optimization-polish/17-RESEARCH.md @.planning/phases/17-ui-optimization-polish/17-CONTEXT.md Task 1: Install @vite-pwa/assets-generator and author logo.svg + pwa-assets.config.ts apps/pwa/package.json, apps/pwa/public/logo.svg, apps/pwa/pwa-assets.config.ts - 17-CONTEXT.md §"Specific Ideas" (the brand brief: FamilySync is the brand; caricature-family vibes; warm tones; rounded corners/shapes; "comfortable and at home") - 17-UI-SPEC.md §"Workstream B — Branding Assets" → "Brand brief" + "Logo asset contract" + "Maskable safe-zone rule" - 17-RESEARCH.md §"Architecture Patterns" → "Recommended Asset-Generation Script Shape" + the minimal pwa-assets.config.ts excerpt + the generate command - 17-RESEARCH.md §"Package Legitimacy Audit" (sharp SUS verdict is a documented false positive — 13-yr/65.6M-wk package; no human-verify checkpoint needed for the package itself) - apps/pwa/public/ (the 3 placeholder stubs being replaced) Install `@vite-pwa/assets-generator@1.0.2` as a devDependency in `apps/pwa` (pulls `sharp` + `sharp-ico` transitively — these are the only new packages; per the Package Legitimacy Audit they are Approved, no human-verify gate required for the package). Add a `"pwa:icons": "pwa-assets-generator generate"` script to `apps/pwa/package.json`.
Hand-author `apps/pwa/public/logo.svg` as a square-viewBox SVG mark to the brand brief: warm tones, rounded corners/shapes, a friendly caricature-family feel that "makes you feel comfortable and at home" — NOT cold/corporate/geometric. Use a square viewBox so the generator's safe-zone arithmetic works. The mark is text-free art (the app name lives in the `<h1>`, not the logo). Keep the SVG self-contained (no external font/image refs).

Create `apps/pwa/pwa-assets.config.ts` using `defineConfig` + `minimal2023Preset` from `@vite-pwa/assets-generator/config`, with `images: ['public/logo.svg']`. Do NOT set `overrideManifestIcons: true` — the manifest is maintained by hand in vite.config.ts (plan 17-04); auto-override would stomp the explicit entries (RESEARCH anti-pattern).
test -f apps/pwa/public/logo.svg && test -f apps/pwa/pwa-assets.config.ts && node -e "const p=require('./apps/pwa/package.json'); if(!p.devDependencies['@vite-pwa/assets-generator']) process.exit(1); if(!p.scripts['pwa:icons']) process.exit(1)" && head -c 5 apps/pwa/public/logo.svg | grep -q '<' - `@vite-pwa/assets-generator` present in `apps/pwa/package.json` devDependencies; `pwa:icons` script present. - `apps/pwa/public/logo.svg` exists, is valid SVG (parses; square viewBox), self-contained, text-free art. - `apps/pwa/pwa-assets.config.ts` exists, imports `defineConfig`/`minimal2023Preset` from `@vite-pwa/assets-generator/config`, sets `images: ['public/logo.svg']`, and does NOT set `overrideManifestIcons: true`. The generator devDep + script are installed, logo.svg matches the brand brief as a valid square SVG, and pwa-assets.config.ts is configured for the minimal-2023 preset against the source logo. Task 2: Generate the full icon/favicon set and validate formats apps/pwa/public/favicon.svg, apps/pwa/public/favicon.ico, apps/pwa/public/icon-192.png, apps/pwa/public/icon-512.png, apps/pwa/public/icon-maskable-512.png, apps/pwa/public/apple-touch-icon.png - 17-UI-SPEC.md §"Workstream B" → "Logo asset contract" table (all 7 filenames + dimensions) - 17-RESEARCH.md §"Architecture Patterns" → the minimal-2023 preset output list + "Maskable safe-zone math" + "ICO generation" - 17-VALIDATION.md §"Per-Task Verification Map" rows D-03/D-04 (asset existence ls, ICO >100 bytes, maskable 512x512 via sharp metadata) - apps/pwa/pwa-assets.config.ts (authored in Task 1) Run the generator from `apps/pwa/` (`pnpm pwa:icons` or `npx @vite-pwa/assets-generator generate`) to produce the derived assets into `apps/pwa/public/`: `favicon.svg`, `favicon.ico`, `icon-192.png`, `icon-512.png`, `icon-maskable-512.png` (separate maskable file with safe-zone padding — this fixes the defect where the manifest reused icon-512.png for the maskable purpose), and `apple-touch-icon.png` (180x180). The minimal-2023 preset handles the safe-zone math, maskable background fill, and ICO encoding via sharp-ico.
Validate the outputs: confirm all 7 files (logo.svg + 6 generated) exist in `apps/pwa/public/`; confirm `favicon.ico` is non-trivial (>100 bytes); confirm `icon-maskable-512.png` is exactly 512x512 via sharp metadata (proving real safe-zone generation, not a stub). The 48px single-size ICO from the preset is acceptable (RESEARCH documents this as adequate vs 16+32 multi-size for this household app; favicon.svg covers modern browsers).

Do NOT wire anything yet (no BrandSlot/index.html/vite.config.ts edits — that is plan 17-04, gated behind the Task 3 checkpoint).
ls apps/pwa/public/logo.svg apps/pwa/public/favicon.svg apps/pwa/public/favicon.ico apps/pwa/public/icon-192.png apps/pwa/public/icon-512.png apps/pwa/public/icon-maskable-512.png apps/pwa/public/apple-touch-icon.png && test $(wc -c < apps/pwa/public/favicon.ico) -gt 100 && node -e "require('sharp')('apps/pwa/public/icon-maskable-512.png').metadata().then(m=>{if(m.width!==512||m.height!==512){console.error('bad maskable dims',m.width,m.height);process.exit(1)}console.log('maskable',m.width+'x'+m.height)})" - `ls` of all 7 asset paths succeeds (logo.svg + favicon.svg + favicon.ico + icon-192.png + icon-512.png + icon-maskable-512.png + apple-touch-icon.png). - `test $(wc -c < apps/pwa/public/favicon.ico) -gt 100` passes (ICO is real, not zero-byte). - `icon-maskable-512.png` reports exactly 512x512 via sharp metadata. - `icon-maskable-512.png` is a DISTINCT file from `icon-512.png` (different bytes — the maskable has safe-zone padding). All 7 branding assets exist with correct formats; favicon.ico is non-trivial; the maskable icon is a separate, properly-padded 512x512 file. Task 3: Checkpoint — operator approves logo art + selects brand accent + logo border-radius apps/pwa/public/logo.svg, apps/pwa/public/favicon.svg, apps/pwa/public/favicon.ico, apps/pwa/public/icon-192.png, apps/pwa/public/icon-512.png, apps/pwa/public/icon-maskable-512.png, apps/pwa/public/apple-touch-icon.png Present the generated branding assets and the brand-accent decision to the operator for blocking approval before any wiring is committed (see how-to-verify). Capture the approved logo, the selected accent hex, and the chosen --brand-logo-border-radius for plan 17-04. A complete FamilySync branding asset set generated from a hand-authored warm/rounded/at-home logo: `logo.svg` (source), `favicon.svg`, `favicon.ico`, `icon-192.png`, `icon-512.png`, `icon-maskable-512.png` (proper safe-zone maskable), and `apple-touch-icon.png` — all in `apps/pwa/public/`. Nothing is wired into the app yet; this checkpoint gates the wiring (plan 17-04). 1. Use the playwright-cli skill to render the logo in context: open the logo.svg directly and/or stage it in the BrandSlot region of `/login` for a preview screenshot, and show the favicon at small sizes. 2. Present the generated logo to the operator against the acceptance lens: does it feel warm / rounded / at-home / caricature-family (not cold/corporate/geometric)? Confirm the maskable icon keeps the mark inside the safe zone (no clipping of meaningful art). 3. Present the BRAND ACCENT decision (UI-SPEC §Color "Brand accent checkpoint", Q1) — two comparable options: - Variant A — keep cool-blue: `--color-member-0: #4a90d9`, `theme-color #4A90D9` (default if no choice). - Variant B — warm: `--color-member-0: #f25c7a` (rose, already `--color-shared-family`) OR amber `#e8915a`; contrast ≥3:1 on #ffffff. Ask the operator to pick A or one of the B candidates. Record the chosen accent hex for plan 17-04 to apply to tokens.css `--color-member-0`, index.html `theme-color`, and vite.config.ts `theme_color`. 4. Also confirm the intended `--brand-logo-border-radius` for the logo shape (0 if the SVG draws its own rounded shape, or 12px if it's a square mark needing rounding) — record for plan 17-04. Operator types "approved" with: (a) logo accepted (or revise instructions), (b) the selected brand-accent hex, (c) the --brand-logo-border-radius value. These three feed plan 17-04.

<threat_model>

Trust Boundaries

Boundary Description
Build tooling → repo @vite-pwa/assets-generator (+ sharp, sharp-ico) runs at design time and writes static assets into public/. New devDependency = supply-chain surface.

STRIDE Threat Register

Threat ID Category Component Disposition Mitigation Plan
T-17-02-SC Tampering npm devDependency install (@vite-pwa/assets-generator, sharp, sharp-ico) accept Per RESEARCH Package Legitimacy Audit all three are Approved: assets-generator (official vite-pwa project, 231K/wk), sharp (13-yr, 65.6M/wk — the too-new SUS flag is a documented false positive from the latest version's publish date), sharp-ico (431K/wk). No [SLOP]/unverified packages; no human-verify gate required for the package legitimacy. Generated assets are static images served as files — no executable content.
T-17-02-02 Information disclosure generated assets accept Assets are public-by-design brand images; no secrets or PII.

No new high-severity threats. devDependencies only; zero new runtime dependencies; generated output is static images. </threat_model>

- `ls` all 7 asset paths — present - `test $(wc -c < apps/pwa/public/favicon.ico) -gt 100` — ICO non-trivial - sharp metadata on `icon-maskable-512.png` — exactly 512x512 - `@vite-pwa/assets-generator` in apps/pwa devDependencies; `pwa:icons` script present - Blocking human checkpoint: logo art approved + brand-accent hex selected + --brand-logo-border-radius value recorded

<success_criteria> The full branding asset set is generated and committed (logo.svg + 6 derived assets), the assets-generator devDep + script are in place, format/dimension checks pass, and the operator has approved the logo and selected the brand accent + logo border-radius — unblocking the wiring plan (17-04). </success_criteria>

Create `.planning/phases/17-ui-optimization-polish/17-02-SUMMARY.md` when done. Record the approved brand-accent hex and --brand-logo-border-radius value in the SUMMARY (plan 17-04 reads them).