gendesign/.design-sync/AUTHORING.md
bot-backend e70f5da82b
All checks were successful
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
chore(design-sync): sync inputs for claude.ai/design trade-in DS
Imports tradein-mvp/frontend (38 components) to a claude.ai/design
design-system project. Synth-entry build (Next.js app, no dist):
- overrides/source-kit.mjs: process.env shim for browser IIFE
- preview-provider.tsx: seeded TanStack Query provider (mirrors the
  repo's offline ui-preview client) so fetch-coupled + auth-gated cards render
- previews/*.tsx: authored preview compositions (real fixture data)
- conventions.md: README header for the design agent
- config.json + NOTES.md: reproducible re-sync inputs
2026-06-27 14:40:50 +03:00

5.7 KiB
Raw Permalink Blame History

Preview authoring guide (design-sync, tradein-mvp-frontend)

You author .design-sync/previews/<Name>.tsx for assigned components so their preview cards render real, styled, plausible compositions. The bundle is already built; you only recompile your own previews.

Import contract (IMPORTANT)

  • Import the component from the package name: import { OfferCard } from 'tradein-mvp-frontend'; (the build maps this to the shipped bundle global — do NOT import from a relative src path).
  • Import realistic data from the shared fixtures: import { FIXTURE_ESTIMATE } from './_fixtures';
  • Type-only imports (import type {...} from '@/types/trade-in') are erased — fine to use for casts.
  • A provider is ALREADY configured globally (the app's Providers = TanStack Query). You do NOT wrap previews in QueryClientProvider yourself (a second copy breaks context identity).

Shared fixtures available from ./_fixtures (realistic ЕКБ 2-к secondary)

  • FIXTURE_ESTIMATE: AggregatedEstimate — median 9.85M ₽, range 9.110.6M, confidence high, analogs[3], actual_deals[2], cian_valuation, avito_imv, dkp_corridor, price_trend[6]. Covers any estimate: AggregatedEstimate prop.
  • FIXTURE_INPUT: TradeInEstimateInput — the quartira params (area 55.3, 2 rooms, floor 5/11, monolith, good).
  • FIXTURE_IMV: IMVBenchmarkResponse — for IMVBenchmark.
  • FIXTURE_HOUSES: HouseInfoForEstimate[] — for HouseInfoCard.
  • FIXTURE_PLACEMENT: PlacementHistoryItem[] — placement history rows.
  • FIXTURE_ANALYTICS: HouseAnalyticsResponse — kpi + price_history[4] + recent_sold[2].
  • FIXTURE_SELLTIME: SellTimeSensitivityResponse — exposure-vs-premium buckets.
  • FIXTURE_SALES: SalesVsListingsResponse — street deals/listings pairs. Read tradein-mvp/frontend/src/app/ui-preview/estimate/page.tsx — it shows EXACT prop usage for many components (the canonical "hero" composition). Port it.

How to find props

Read each component's source tradein-mvp/frontend/src/components/<group>/<Name>.tsx. The interface Props (or inline destructure) is the contract. Many take estimate; some take other fixtures; some take callbacks (pass () => {}); some fetch via hooks by id (see "fetch-coupled" below).

Recipe

  • 1 canonical story (the docs/page.tsx usage) named Default. Add 13 more ONLY if they visibly differ (sweep a real variant axis: a state, an enum, empty-vs-full). Budget 14 cells.
  • Realistic content only (the ЕКБ fixtures) — never foo/test.
  • Callbacks → () => {}. Booleans like isLoading/isPending → usually false for the full state.
  • Keep visually-identical variants OUT (e.g. a flag that only changes a link, not the view) — one cell.

Fetch-coupled components (PlacementHistoryCard, HouseAnalyticsSection, PhotoUpload, ListingsCard

maybe) take an estimateId and fetch internally. The global Provider's query cache is EMPTY, so they render their loading/empty state. If the component accepts data via props too, prefer that. If it can ONLY fetch and renders blank/loading, author the best you can and RECORD it in your learnings file as "renders loading/empty — fetch-coupled" — do NOT fake data you can't pass.

Your loop (per component)

  1. Read source → write .design-sync/previews/<Name>.tsx (named exports, no marker line).
  2. Rebuild ONLY your components: node .ds-sync/lib/preview-rebuild.mjs --config .design-sync/config.json --node-modules tradein-mvp/frontend/node_modules --out ./ds-bundle --components <YOUR_COMMA_LIST>
  3. Capture ONLY your components: node .ds-sync/package-capture.mjs --out ./ds-bundle --components <YOUR_COMMA_LIST>
  4. READ each ds-bundle/_screenshots/review/<group>__<Name>.png. Grade each cell on the absolute rubric: Styled (DS tokens/font visible) · Complete (renders whole, no missing children) · Plausible.
  5. Write .design-sync/.cache/review/<Name>.grade.json: {"cells":{"<CellLabel>":{"verdict":"good"|"needs-work","note":"..."}}} (keys = exact cell labels from the capture log). needs-work → fix the .tsx, rebuild, recapture, regrade until good.

HARD RULES (violating corrupts other agents' work)

  • Edit ONLY your assigned previews/<Name>.tsx, your .cache/review/<Name>.grade.json, and your .design-sync/learnings/<BATCH>.md. NOTHING else. Never touch config.json / NOTES.md / other previews.
  • NEVER run package-build.mjs or package-validate.mjs. NEVER run package-capture.mjs without --components (a full run prunes other agents' state). Only the two scoped commands above.
  • If the SAME root cause hits 2+ of your components, or ANY config-level issue (a needed provider chain, a missing token/css, a needed cardMode/viewport override, an import that won't resolve) → STOP on those, record in your learnings file .design-sync/learnings/<BATCH>.md, and report to the orchestrator. Config/NOTES changes are orchestrator-only.

Wide/overlay components

Cards with className="card" are full-width and fine. If a card visibly overflows its grid cell or an overlay (dialog/map modal) collapses, that needs a cfg.overrides.<Name>.cardMode change — you CANNOT do that (config is orchestrator-only). Record it in learnings and move on.

Calibration learnings from the solo set (HeroSummary, OfferCard, PriceRangeBar)

  • The contract works: import { X } from 'tradein-mvp-frontend' + ./_fixtures + global Provider.
  • Cards render fully styled with the trade-in tokens/Manrope font.
  • Components with analog photos show a grey placeholder (fixture photo_url=null, offline) — that is the component's REAL no-photo state, grade it good (do not try to add external image URLs).
  • Drop variants that don't change the view (brandSlug, isResubmitting rendered identical → single cell).