انحرافها از نقشهٔ تسکها
هر ردیفی که در چکلیستها ⚠️ مانده، اینجا با سه چیز ثبت است: نقشه چه گفت، چه شد،
و چرا. هیچکدام «انجام نشده» نیست؛ همه تصمیماند.
قاعدهٔ خواندن: اگر روزی یکی از این تصمیمها اشتباه از آب درآمد، همینجا عوضش کن و دلیل
تازه را بنویس. سندی که فقط توجیه جمع کند به درد نمیخورد.
چیزهایی که نباید به نقشه برگردند
هیچکدام. سه موردی که قبلاً اینجا بودند (idempotency با catch، تراکنش سراسری لغو، و
مانده تجمعی در UI) به نقشه برگردانده شدند — هر کدام با بستنِ باگی که دعوتش میکردند.
جزئیات در کامیت refactor: take the three risky rows back to the plan.
تسک ۰۴ — کاتالوگ سرویس
| ردیف |
نقشه |
چه شد |
چرا |
| ۴.۳ |
جدول آیتمها با نام/زمان/قیمت |
جدول در پیشنمایش انتخاب است |
همان ستونها، ولی کنار عددی که کاربر دربارهٔ آن تصمیم میگیرد؛ جدول دوم یعنی دو جای خواندن یک چیز |
| ۴.۶ |
قیمت با PriceInput |
فقط نمایش با formatRial |
این تب قیمت را ویرایش نمیکند؛ ویرایشش در ServiceItemFormModal است که از قبل PriceInput دارد |
| ۴.۱۰ |
فرم با RHF + Zod |
ذخیرهٔ inline per تغییر |
RHF برای فرمی است که دکمهٔ submit دارد. این تب ندارد — هر تغییر مستقل و فوری ذخیره میشود |
| ۴.۱۲ |
خطاها زیر همان گروه |
همهٔ خطاها زیر پیشنمایش |
قرارداد پروژه «همهٔ خطاها با هم» است؛ نگاشت group_uuid به کارت، خطا را از کنار عددِ نتیجه دور میکرد |
تسک ۰۵ — برنامهٔ نوبت
| ردیف |
نقشه |
چه شد |
چرا |
| ۱.۳ |
پنج سرویس جدا |
یک AppointmentPlanBuilder |
پنج کلاس وقتی معنا دارد که هرکدام مصرفکنندهٔ مستقل داشته باشند؛ اینجا هر پنج فقط از build() صدا زده میشوند |
| ۱.۴ |
build() تابع خالص |
از دیتابیس میخواند |
تا تسک ۰۸ خالص بود؛ تسک ۰۹ قوانین را وصل کرد و قانون در دیتابیس است. خلوص را فقط با کپیکردن قوانین در حافظه میشد نگه داشت |
| ۱.۸ |
اشغال جدا از offset نمایشی |
setup/cleanup روی PlannedRequirement |
اثر عملی یکی است و تسک ۰۷ همان را میخواند؛ دو offset جدا یعنی دو عدد که باید همزمان درست بمانند |
| ۲.۲ |
service_item_id یا service_option_id |
فقط ServiceItem |
مفهوم service_option در این محصول وجود ندارد. ستونی برای چیزی که نیست، تهی میماند و بعداً کسی فکر میکند باگ است |
| ۲.۳ |
fixed_minutes یا duration_share |
duration_source ∈ fixed|items |
«مدت از آیتمها» همان نیاز واقعی است؛ سهم درصدی هیچ مصرفکنندهای نداشت |
| ۲.۵ |
required_skills بهصورت JSON |
یک Skill با FK |
چند مهارت همزمان نیاز واقعی نداشت، و FK اعتبار ارجاعی میدهد که JSON نمیدهد — مهارتِ حذفشده در JSON بیصدا میماند |
تسک ۰۹ — موتور قوانین
رجیستریها، شش موتور و specificity ذخیرهشده ساخته شدند (کامیت
refactor(policy): build the registries and six engines). آنچه مانده:
| ردیف |
نقشه |
چه شد |
چرا |
| ۱.۱۱ |
forbiddenRanges() — کوئری نه حلقه |
spacing در لحظهٔ رزرو موقت |
هزینهاش یک اسلات است که نمایش داده و بعد رد میشود؛ سودش این است که جستجوی وقت per کاندید یک کوئری تاریخچهٔ بیمار نزند |
| ۲.۳ |
تسک ۰۶ → Spacing |
BookingPolicyGuard |
همان نتیجه، در همان نقطهای که تصمیم واقعی گرفته میشود |
| ۲.۴ |
Eligibility در confirm |
در hold |
رد کردن بعد از گرفتن صندلی هم وقت بیمار را تلف میکند هم صندلی را |
| ۲.۶ |
هیچ امضایی عوض نشد |
سه سرویس یک وابستگی سازنده گرفتند |
امضای هیچ متد عمومیای عوض نشد؛ سازنده تنها راه رسیدن قانون به آن سه است |
| نام فیلدها |
patient.age نقطهدار |
patient_age |
شرطهای ذخیرهشده روی قانونهای زندهٔ کلینیکها به نامهای فعلی اشاره میکنند؛ تغییرشان مهاجرت داده است و نگاشت یکبهیک هم ندارد |
تسک ۱۰ — آزمایشگاه قانون
| ردیف |
نقشه |
چه شد |
چرا |
| ۱.۶ |
فیلتر از داخل condition |
از دامنهٔ قانون |
شرطها فیلد id ندارند که به کوئری ترجمه شوند؛ دامنه دقیقاً همان چیزی است که قابل ترجمه است |
تسک ۱۱ — دفتر اعتبار
| ردیف |
نقشه |
چه شد |
چرا |
| ۴.۴ |
مانده هرگز منفی نمیشود |
با مصرف پشتسرهم تست شد |
تست همزمانی واقعی حالا هست (testAConcurrentConsumeIsAbsorbedWithoutBurningTheRequest) |
تسک ۱۲ — دورهٔ درمان
| ردیف |
نقشه |
چه شد |
چرا |
| ۱.۱۲ |
سختگیرانهتر برنده در هر دو جهت |
فقط max(min) |
قانون spacing اثر «حداکثر» ندارد، پس min(max) چیزی برای انتخاب کردن ندارد |
تسک ۱۳ — لغو و لیست انتظار
| ردیف |
نقشه |
چه شد |
چرا |
| ۳.۱ |
Service + Matcher جدا |
یک WaitlistNotifier |
تطبیق یک کوئری در repository است؛ کلاس جدا فقط یک لایهٔ اسمگذاری میشد |
تسک ۱۴ — رویدادها
| ردیف |
نقشه |
چه شد |
چرا |
| ۱.۱ |
کلاس پایه + چهارده زیرکلاس |
فهرست بستهٔ نام + یک entity |
زیرکلاسِ خالی که فقط نام را در تایپ نگه میدارد، همان کاری را میکند که const — با چهارده فایل بیشتر |
چندزبانگی (i18n)
پروژه فایل i18n ندارد و همهٔ رشتهها inline اند. محصول تکزبانه است و لایهٔ ترجمه
بدون زبان دوم فقط یک واسطهٔ اضافه است.
روزی که زبان دوم لازم شد، ترتیبش این است: اول assets/admin/lib/i18n.ts با یک
t() ساده و کلیدهای تخت؛ بعد صفحهبهصفحه مهاجرت، نه یکباره. مهاجرت همزمانِ هزاران
رشته یعنی رگرسیون متنی که هیچ تستی نمیگیردش.