176 lines
14 KiB
Markdown
176 lines
14 KiB
Markdown
---
|
|
phase: 17-ui-optimization-polish
|
|
plan: 02
|
|
type: execute
|
|
wave: 1
|
|
depends_on: []
|
|
files_modified:
|
|
- 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
|
|
autonomous: false
|
|
requirements: [D-03, D-04]
|
|
user_setup: []
|
|
must_haves:
|
|
truths:
|
|
- "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"
|
|
artifacts:
|
|
- path: "apps/pwa/public/logo.svg"
|
|
provides: "Hand-authored source brand mark (BrandSlot img + icon derivation source)"
|
|
- path: "apps/pwa/public/icon-maskable-512.png"
|
|
provides: "512x512 maskable PWA icon with safe-zone padding"
|
|
- path: "apps/pwa/pwa-assets.config.ts"
|
|
provides: "@vite-pwa/assets-generator config (minimal-2023 preset)"
|
|
- path: "apps/pwa/package.json"
|
|
provides: "@vite-pwa/assets-generator devDependency + pwa:icons script"
|
|
key_links:
|
|
- from: "apps/pwa/pwa-assets.config.ts"
|
|
to: "apps/pwa/public/logo.svg"
|
|
via: "images: ['public/logo.svg'] — generator reads the source SVG"
|
|
pattern: "logo.svg"
|
|
---
|
|
|
|
<objective>
|
|
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).
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@$HOME/.claude/gsd-core/workflows/execute-plan.md
|
|
@$HOME/.claude/gsd-core/templates/summary.md
|
|
</execution_context>
|
|
|
|
<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
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Install @vite-pwa/assets-generator and author logo.svg + pwa-assets.config.ts</name>
|
|
<files>apps/pwa/package.json, apps/pwa/public/logo.svg, apps/pwa/pwa-assets.config.ts</files>
|
|
<read_first>
|
|
- 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)
|
|
</read_first>
|
|
<action>
|
|
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).
|
|
</action>
|
|
<verify>
|
|
<automated>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 '<'</automated>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- `@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`.
|
|
</acceptance_criteria>
|
|
<done>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.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Generate the full icon/favicon set and validate formats</name>
|
|
<files>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</files>
|
|
<read_first>
|
|
- 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)
|
|
</read_first>
|
|
<action>
|
|
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).
|
|
</action>
|
|
<verify>
|
|
<automated>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)})"</automated>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- `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).
|
|
</acceptance_criteria>
|
|
<done>All 7 branding assets exist with correct formats; favicon.ico is non-trivial; the maskable icon is a separate, properly-padded 512x512 file.</done>
|
|
</task>
|
|
|
|
<task type="checkpoint:human-verify" gate="blocking-human">
|
|
<name>Task 3: Checkpoint — operator approves logo art + selects brand accent + logo border-radius</name>
|
|
<files>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</files>
|
|
<action>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.</action>
|
|
<what-built>
|
|
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).
|
|
</what-built>
|
|
<how-to-verify>
|
|
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.
|
|
</how-to-verify>
|
|
<resume-signal>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.</resume-signal>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<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>
|
|
|
|
<verification>
|
|
- `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
|
|
</verification>
|
|
|
|
<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>
|
|
|
|
<output>
|
|
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).
|
|
</output>
|