تولید UI از screenshot یا description میتواند یک ظاهر قانعکننده بسازد، اما تصویر proof تعامل نیست. مهندس باید description را به constraint تبدیل کند، یک vertical slice کوچک بسازد، سپس در browser رفتار واقعی را با DOM، console، network و accessibility بررسی و evidence ثبت کند. «شبیه است» با «کار میکند» دو ادعای جدا هستند.
## اهداف یادگیری
پس از این درس میتوانی از مرجع تصویری hierarchy، spacing، typography، state و responsive constraint استخراج کنی، یک slice باریک booking بسازی، DOM/console/network/accessibility را در browser بررسی کنی، evidence قابلبازتولید بنویسی و تفاوت appearance تولیدشده با interaction verified را توضیح دهی.
## جایگاه در چرخهٔ سرتاسری
این درس در `Implement → Observe → Verify` است و به S1 فصل ۵ وصل میشود: UI authenticated باید از HTTP واقعی به database و CI برسد. قرارداد reschedule هنوز ثابت است؛ بیمار مالک appointment `CONFIRMED` است، زمان معتبر در timezone کلینیک به UTC میرود، deadline بسته `409 RESCHEDULE_WINDOW_CLOSED` میدهد و خطا نباید mutation یا audit تازه بسازد. screenshot policy را تعیین نمیکند؛ فقط یک مرجع دیداری برای استخراج constraint است.
## از screenshot description تا constraint
توصیف مبهمی مانند «کارت رزرو مدرن، تمیز و شبیه تصویر، با دکمهٔ سبز» برای Agent کافی نیست. آن را به constraintهای قابل مشاهده و حالتهای رفتاری تبدیل کن:
Structure: عنوان doctor، local date/time، badge status، action reschedule.
Hierarchy: زمان اصلی از metadata بزرگتر؛ action بعد از summary.
Layout: padding، gap، max width و stacking در mobile.
States: loading، empty، error 409، disabled و success.
Typography: حداقل خوانایی و line wrapping؛ font ناموجود جایگزین صریح.
Color: semantic success/error؛ فقط hex تصویر معیار نیست.
Interaction: click و keyboard، focus visible، pending تا response.
Data: local display از API contract؛ tenant/actor از credential.هر constraint باید یکی از این نوعها را داشته باشد: **بصری**، **responsive**، **رفتاری** یا **دادهای**. این تفکیک جلوی آن را میگیرد که Agent رنگ را دقیق کند ولی loading و error را فراموش کند. اگر screenshot نسبت، pixel یا font را نشان نمیدهد، آن را fact قطعی ندان؛ assumption ثبت کن و default قابلتغییر بگذار.
مثال بد
«این screenshot را pixel-perfect بساز. API لازم نیست؛ فعلاً با دادهٔ ثابت و click alert کافی است.»ظاهر شاید عالی شود، اما route، keyboard، loading، 409، network و semantics وجود ندارد. یک screenshot از کارت بدون interaction evidence محصول نیست.
مثال خوب
Slice: بیمار یک appointment confirmed را میبیند و dialog reschedule را باز میکند.
Input: description تصویری، contract response و fixture امن.
Non-goal: calendar provider، reminder و redesign کل dashboard.
Acceptance: action با click/Enter کار کند؛ focus visible باشد؛ request واقعی status 200 یا
409 canonical داشته باشد؛ pending دوبار submit نکند؛ error با role=alert و متن قابلدسترسی دیده شود.
Evidence: screenshot حالت success/error، DOM snapshot منتخب، console، network trace و accessibility result.## یک Slice، نه یک gallery
ابتدا یک مسیر end-to-end بساز: route → کارت → بازکردن form → ارسال interval → response → success/error. همهٔ variantهای design system را نساز. Fixture باید fake اما صریح و محلی باشد؛ mock نباید جای contract واقعی را در verification بگیرد. اگر API هنوز آماده نیست، adapter موقت را با interface و limitation علامت بزن و claim را فقط به appearance/interaction محلی محدود کن.
ترتیب پیشنهادی:
1. semantic skeleton با heading، article، button و form. 2. stateهای loading و error، نه فقط happy path. 3. اتصال به route و network contract فصل ۵. 4. responsive constraint در viewport desktop و mobile. 5. keyboard/focus و پیام خطا. 6. evidence browser و review مستقل.
## Browser inspection چهارگانه
**DOM:** بررسی کن که متن، role، label، disabled و state واقعاً در tree هستند؛ صرفاً CSS pseudo-element برای status نساز. **Console:** exception، hydration warning، failed resource و unhandled promise را بررسی کن. console پاک proof کامل نیست، اما console آلوده verification را متوقف میکند. **Network:** request واقعی، method، URL، payload بدون credential خام، status، response body، loading و retry را ببین. 200 با body اشتباه pass نیست؛ 409 باید همان contract باشد. **Accessibility:** با keyboard از focus order عبور کن، accessible name/role/value را inspect کن، focus visible و error association را بسنج، و contrast/heading را با ابزار مناسب بررسی کن. اسکن خودکار شروع خوبی است، نه جایگزین keyboard و قضاوت انسانی.
سناریوی booking-platform
برای کارت appointment، زمان قابل مشاهده باید local و وابسته به timezone کلینیک باشد، اما request باید `startLocal` و `endLocal` را طبق contract بفرستد و tenant/actor را از credential بگیرد. در success، body `{ id, startAt, endAt, version }` نشان داده میشود؛ در deadline بسته، UI متن قابلدسترسی میدهد و دادهٔ قدیمی را حفظ میکند. در conflict همزمان، یک درخواست موفق و دیگری `409 SLOT_CONFLICT` است؛ UI نباید با optimistic state دائمی هر دو را موفق نشان دهد.
## Appearance generated در برابر interaction verified
Appearance claim میگوید ساختار، رنگ، spacing و typography در viewportهای مشخص به مرجع نزدیکاند. Evidence آن screenshotهای timestamped، viewport، browser و commit است. Interaction claim میگوید کاربر واقعی میتواند با mouse و keyboard مسیر را طی کند، stateها تغییر کنند، request درست برود، error قابلفهم باشد و accessibility حداقل لازم را داشته باشد. Evidence آن Playwright trace، DOM assertions، network event، console scan و accessibility report است.
Agent میتواند کد و screenshot تولید کند؛ اینها خودبهخود verified نیستند. حتی screenshot موفق ممکن است از mock یا state دستی آمده باشد. در گزارش صریح بنویس کدام ادعا verified، کدام فقط inspected و کدام unresolved است. اگر ابزار browser یا API در دسترس نیست، claim را کوچک کن؛ نتیجه را جعل نکن.
## آزمایشگاه گامبهگام
**ورودی:** screenshot description کارت appointment، Spec v1، fixture محلی، route S1 و Playwright.
۱. constraints را به جدول structure/layout/state/interaction/data تبدیل کن. ۲. فقط slice کارت و dialog reschedule را بساز؛ reminder، calendar provider و dashboard کامل non-goal هستند. ۳. dev server محلی و database ephemeral را با نام امن اجرا کن؛ سپس:
pnpm exec playwright test apps/web/tests/e2e/reschedule-card.spec.ts --project=chromium**Expected:** تست authenticated fixture را باز میکند، DOM semantic و accessible name را میسنجد، click و keyboard را اجرا میکند، request واقعی را میبیند و 200/409 را assert میکند. ۴. trace/screenshot را در Evidence با viewport، commit، browser و timestamp ثبت کن. Console error، failed network و accessibility violation را جدا فهرست کن. ۵. در desktop و mobile یک بار اجرا کن؛ سپس error state و دوباره submit را بررسی کن.
**Recovery:** اگر screenshot نزدیک است ولی DOM semantic نیست، CSS را polish نکن؛ markup را اصلاح کن. اگر network mock است، claim را «appearance inspected» نگهدار و integration را pending ثبت کن. اگر console hydration warning یا 409 اشتباه دیدی، fix را به کوچکترین Slice برگردان. هرگز از credential واقعی یا endpoint production استفاده نکن.
## خطاهای رایج و نشانهها
- pixel chasing بدون state و contract.
- ساخت gallery بزرگ بهجای یک مسیر end-to-end.
- استفاده از `div` و click handler بهجای button/label.
- mock network که success را جعل میکند.
- ثبت فقط screenshot و ادعای interaction.
- نادیدهگرفتن mobile، keyboard و focus.
- console warning حلنشده چون «ظاهر درست است».
- نمایش local time با timezone ماشین بهجای timezone کلینیک.
- ورود tenant/actor از form یا log.
## Verification
- [ ] description به constraintهای بصری، responsive، رفتاری و دادهای تبدیل شده است.
- [ ] یک Slice واقعی از route تا response وجود دارد و non-goal روشن است.
- [ ] DOM semantic، console، network و accessibility جداگانه بررسی شدهاند.
- [ ] success، loading، error `409` و disabled/retry رفتار مشخص دارند.
- [ ] click و keyboard و focus evidence دارند.
- [ ] screenshot claim از interaction claim جدا گزارش شده است.
- [ ] browser، viewport، commit و timestamp evidence ثبت شدهاند.
- [ ] محیط local/ephemeral است و credential یا endpoint واقعی ندارد.
## تمرین مستقل
برای صفحهٔ «appointment history» یک screenshot description فرضی بنویس و آن را به constraints و یک Slice تبدیل کن. حداقل دو failure state و چهار browser evidence تعیین کن.
**پاسخ نمونه و Rubric:** پاسخ باید hierarchy کارت، date/time، status، responsive stacking و focus را از ظاهر جدا کند؛ Slice باید فقط مشاهدهٔ history و بازکردن جزئیات باشد، نه export و notification. failureها شامل network error و empty state باشند. evidence باید DOM role/name، console، network status/body، keyboard/focus و accessibility report را شامل کند؛ screenshot بهتنهایی امتیاز کامل ندارد. دادهٔ tenant باید از context مجاز بیاید و endpoint production ممنوع است.
## جمعبندی
UI خوب از screenshot کپی نمیشود؛ constraint، behavior و evidence ساخته میشود. یک vertical slice باریک، با network و state واقعی، از gallery پرزرقوبرق قابلاعتمادتر است. Browser verification باید DOM، console، network و accessibility را پوشش دهد و گزارش باید صریحاً appearance generated را از interaction verified جدا کند.
## منابع مستقیم
- [Playwright Test](https://playwright.dev/docs/intro) — اجرای browser و trace؛ محیط پروژه باید pin شود.
- [Playwright accessibility testing](https://playwright.dev/docs/accessibility-testing) — راهنمای رسمی اسکن و محدودیت آن.
- [WAI-ARIA Authoring Practices](https://www.w3.org/WAI/ARIA/apg/) — الگوهای semantic و keyboard.
- [WCAG 2.2 Quick Reference](https://www.w3.org/WAI/WCAG22/quickref/) — معیارهای دسترسپذیری، نه تضمین usability کامل.
- [Cursor Browser docs](https://cursor.com/docs/agent/browser) — surface وابسته به نسخه برای browser assistance؛ evidence مستقل لازم است.
به زبان ساده
Screenshot فقط constraintهای ظاهری را نشان میدهد؛ interaction verified به DOM، network، console، keyboard و accessibility نیاز دارد. یک vertical UI slice کوچک، از gallery متصل به دادهٔ ثابت شواهد بهتری میدهد.
مثال واقعی
در سناریوی فرضی دوره، dialog reschedule باید request واقعی بفرستد، در ۲۰۰ version را نشان دهد و در ۴۰۹ پیام قابلدسترسی بدهد؛ تصویر موفق بهتنهایی اینها را اثبات نمیکند.