رفتن به محتوا

معماری

packages/core دامنه: یونیت → قطعه، چیدمان ورق، قواعد، هزینه، عکس، مونتاژ، پروندهٔ پروژه
packages/i18n زبان: LOCALES، قالب‌گرِ هر زبان، رندرِ پیامِ هسته، کاتالوگ‌ها (← core)
packages/geometry صحنهٔ سه‌بعدی و ایزومتریک از همان مدل (← core)
packages/report خروجی کاغذی: HTML چاپی، CSV، DXF (← core, geometry, i18n)
packages/ui سامانهٔ طراحی: اجزای React Aria، توکن، پوسته (← هیچ بستهٔ ورک‌اسپیس)
apps/web رابط کاربری: React، بوم SVG، three (← core, i18n, geometry, report, ui)
apps/cli خط فرمان و PDF با کروم بی‌سر (← core, i18n, report)
apps/site سایت مستندات (Starlight)، همگام از docs/reference

core به هیچ بستهٔ دیگری و به هیچ چیزِ مرورگر وابسته نیست — زبان هم نه: پیام برمی‌گرداند (message.ts، شیءِ /*i18n*/ با مقدارِ تیپ‌دار) و لبه با @darzsaz/i18n رندرش می‌کند (i18n.md). شبکه هم نه: نرخ دلار را usdFromMirrors(get) از آینه‌ها تجزیه می‌کند و خودِ fetch در apps/web/src/lib/usd.ts و apps/cli/src/usd.ts است (no-restricted-globals در ESLint نگهش می‌دارد). اگر چیزی در core به DOM یا React نیاز پیدا کرد، جایش آنجا نیست. geometry فقط core را می‌بیند؛ report core، geometry (برای نقشهٔ ایزومتریکِ مونتاژ) و i18n را. ابزارها: pnpm ۱۱ (workspace)، TypeScript سخت‌گیر (exactOptionalPropertyTypes، noUncheckedIndexedAccess)، Vite ۸، Vitest ۴، React ۱۹، zustand + immer، three / react-three-fiber / drei، Playwright.

نقشهٔ سریع: کدام پوشه صاحبِ کدام موضوع است. تا فاز ۹ همین جدول در CLAUDE.md بود؛ معماری یک جا می‌ماند و بقیه به اینجا پیوند می‌دهند (۹.۴).

چه کجا
تیپ‌های مدل داده packages/core/src/types/ — قرارداد نوار لبه در part.ts
پیکره‌های نمونه packages/core/src/fixtures/ (myKitchen, lShapedProject, الگوها)
کاتالوگ ایران packages/core/src/catalog/defaults.ts
مدلِ یونیت (یک بار بدنه، نما، قطعه، یراق) packages/core/src/units/model.ts (unitModel، generateParts، hardwareForUnitnormalizeUnit در مرز
قواعد دستیار packages/core/src/validate/rules/*.ts (ترتیب در index.ts)
تنظیمات چیدمان ورق فقط nestOptions() در pipeline/derive.ts
پروندهٔ پروژه و مهاجرت packages/core/src/io/project-file.ts
وضعیت رابط apps/web/src/state/store.ts (zustand+immer، past/future)، derived.ts
پوستهٔ پنجره‌ها Dialog ِ کیت؛ چیدمانِ ویرایشگر apps/web/src/components/layout/
توکن و پوسته packages/ui/src/{themes,tokens}.ts؛ رنگِ بی‌پوسته apps/web/src/scene/materials.ts
رندر آفلاین apps/web/src/lib/{render,ao,textures}/
آزمون‌ها */test/، packages/core/test/properties.test.ts، apps/web/e2e/
لینت و قالب eslint.config.js، stylelint.config.mjs، .prettierrc، knip.config.js، lefthook.yml
نقشهٔ نسل ششم و پیشرفت plan-v6/README.md، plan-v6/PROGRESS.md، FINDINGS.md، ADMIN.md، LANDING.md؛ آرت‌بوردها در plan-v6/artboards/؛ نسل پنجم در plan-v5/، نسل‌های پیشین در docs/journal/plans/
چاپ و بسته‌های مخاطب packages/report/src/bundles.ts، apps/web/src/components/PrintCenter.tsx
کارگاه، هزینه، کاتالوگ apps/web/src/components/{workshop,cost,catalog}/
خط فرمان apps/cli/src/cli-main.ts (درخت citty)، commands/<نام>.ts با run*()
زبان و جهت packages/i18n/src/locales.ts (منبع)، apps/web/src/lib/locale.ts (سیاست)
پیامِ هسته و رندرش packages/core/src/message.ts، packages/i18n/src/render.ts
کاتالوگ ترجمه packages/i18n/src/locales/*.po؛ pnpm i18n:extract، pnpm i18n:compile
فونت tools/fonts/ (منتخب) و tools/fonts/packages/ (بستهٔ کامل)، scripts/build-fonts.mjs
سلامت ذخیره‌سازی apps/web/src/lib/storage-health.ts؛ دروازهٔ پروژه components/ProjectGate
استقرارِ سایتِ زنده docs/reference/deploy.md («سایتِ زنده — darzsaz.ir»)؛ اسکریپت و کلیدها بیرونِ مخزن، در بکاپِ رمزها
پوشه چه می‌کند نقطهٔ ورود
types/ تیپ‌های مدل داده: project.ts، unit.ts، part.ts، catalog.ts types/index.ts (بازصدورِ تیپ؛ project.ts با فهرستِ صریح)
catalog/ کاتالوگ ایران (defaults.ts، داده در data/*.ir.jsoncreateCatalog() با اعتبارسنجی زمان اجرا irCatalog()
units/ پیش‌تنظیم‌های یونیت (baseUnit، wallUnit، …) و مدلِ یونیت (units/model.ts، ۱.۱۴): بدنه، نما، قطعه و یراقِ هر یونیت یک بار؛ normalizeUnit در مرز unitModel()، generateParts()، hardwareForUnit()
parts/ یونیت → قطعه: بدنه (carcass.ts)، نما (front.ts، fronts.ts)، جعبهٔ کشو، اندازهٔ برش از نوار لبه (edging.ts)، ادغام (merge.ts) generateProjectParts()، mergeParts()
layout/ جای یونیت‌ها روی ردیف (run.ts)، برش روی صفحهٔ کار (cutouts.ts)، جای دیوار و گوشه‌ها (wall-frame.ts)، پیشنهادِ «این دیوار را پر کن» (autofill.ts) layoutRun()، countertopCutouts()، autofill()
nesting/ چیدمان گیوتینی با درخت (guillotine.ts)، MaxRects برای CNC (maxrects.ts)، جست‌وجوی تصادفی با بذر (nest.ts، rng.ts)، ترتیب برش (sequence.tsبازرس مستقل (verify.ts) nest()، verifyAll()
validate/ قواعد دستیار به دسته، چهارده پرونده: rules/{safety,fit-run,fit-appliance,structure,usability,cost,corner,countertop,tall}.ts و rules/{safety,fit,structure,usability,cost}-v3.ts؛ ترتیب در rules/index.ts validateProject()
hardware/ یراقِ لازم از روی ساختار یونیت hardwareForProject()، hardwareForUnit()
costing/ صورت‌حساب (bom.ts)، مبلغِ سطر و نشانیِ قیمتِ ورق و واحدِ پول (price.ts)، قیمت مرجع با برچسب اطمینانِ هر قلم (reference.ts، confidenceOf)، نرخ دلار (usd.ts) buildBom()
pipeline/ یک خط لوله برای همه: nestOptionsnestProjectfinishDerivederive؛ رتبهٔ پیشنهادهای پر کردن (rank.ts) و «یک ورق کمتر» (sensitivity.ts) — pipeline.md derive()
photo/ هموگرافی چهار نقطه‌ای: DLT ِ نرمال‌شده (هارتلی)، هم‌خطیِ مقیاس‌ناوابسته، نگهبان‌های نسبی solveHomography()، applyH()
assembly/ گام‌های مونتاژ از ساختار assemblySteps()
countertop/ قطعه‌های صفحهٔ هر ردیف: درز، اتصالِ گوشه، شمارِ ورقِ بازار countertopsOf()، runPieces()
machining/ ماشین‌کاری روی قطعه‌ها: اتصالِ بدنه، سیستم ۳۲، صفحهٔ لولا و لانهٔ لولا، پیچِ ریل، سوراخِ دستگیره، شیارِ پشت‌بند applyMachining()
io/ پروندهٔ پروژه: نسخه، مهاجرت، بارگذاری با خطای کددار (io/invalid)؛ بستهٔ .darz (zip، darz.ts)؛ تصویرِ بیرون از سند با شناسهٔ محتوا (assets.ts، assets/ ِ .darz) loadProject()، saveProject()، packDarz()، unpackDarz()، unpackDarzWithAssets()
schema/ اسکیمای zod ِ هر نسخهٔ پرونده (v1.ts، v2.ts، v3.ts)، دفتر قیمت، سقف‌ها و پیامِ مسئلهٔ zod (issues.tsdarz-format.md از همین‌ها تولید می‌شود projectV3، LIMITS
project/ پیش‌فرض‌های پروژه و شماره‌گذاریِ پایدارِ یونیت numberUnits()، nextUnitNumber()
variants/ گونه‌ها: تفاوت با پروژهٔ پایه به‌صورت JSON Patch (patch.ts) variantProject()، adoptVariant()
workshop/ پیشرفتِ کارگاه درونِ پروژه: ردیفِ شمرده، تکهٔ اسکن‌شده، گامِ مونتاژِ تمام‌شده scanPiece()، progressSummary()
fixtures/ پروژه‌های نمونه به‌صورت کد تایپ‌شده: myKitchen()، lShapedProject()، الگوها fixtures/index.ts
message.ts، errors.ts پیام (msg، مقدارِ تیپ‌دار) و DarzError با کد و پیام msg()، fail()، errorMsg()
digits.ts، mm.ts، ids.ts، today.ts خواندنِ رقمِ فارسیِ ورودی، گردکردن میلی‌متر، شناسه (newId)، تاریخ و لحظهٔ محلی (today()، nowIso())

projectScene(project, cat, cache?) صحنه را می‌سازد: unit-instancescarcass-instances، front-instances (با classic-instancescorner-instances و interior-instances؛ fixtures (گاز، هود، سینک، شیر و دستگاه‌ها)، transform (مختصات دیوار → اتاق)، emitter (جمع‌کردن جعبه‌های یونیت)، isometric برای نقشهٔ مونتاژ. خروجی یک Scene است — parts جعبه‌های {materialId, size, center, rotY?, …}، fixtures و bounds — بدون هیچ وابستگی به three؛ با createSceneCache() فقط یونیت‌های تغییرکرده از نو ساخته می‌شوند.

باز شدنِ نما در motion.ts است، نه در وب (نسل ششم، فاز ۳): هر قطعه frontId و motion دارد — swing (محور از ضربِ برداری، روی صفحهٔ جلوی بدنه و یک ضخامت بیرونِ لبهٔ لولادار؛ زاویه از Hinge.openAngleslide (طولِ ریل × کشش)، follow (جعبهٔ کشو، چهار تکه از قابِ کلاسیک) و fold (لنگهٔ دومِ کنجِ تاشو). leaderMotions + poseFor(part, leaders, t) جای قطعه را در لحظهٔ t می‌دهند و وب همان را روی گروهِ three می‌نشاند. vec.ts برگِ بسته است (Vec3، v) تا types.ts و motion.ts چرخه نسازند.

یک منبع برای ریاضیِ فضایی (۷٫۱۴): units.ts (S، میلی‌متر ← متر؛ تنها نسخه)، room.ts (wallSegments، roomRect، roomShell، cornerWall، alignedStart — پیش‌تر در وب)، panel-mesh.ts (رأس/نرمال/UV ِ صفحهٔ پخ‌دار، آرایهٔ خام)، counter.ts (جای سوراخ و UV ِ صفحهٔ کابینت)، facade.ts (facadeCells = layoutFront ِ هسته برای بوم). چرخشِ دیوار فقط از wallTransform (روی wallFrame ِ هسته). لبهٔ three در وب می‌ماند: lib/boxgeo.ts (BufferGeometry + انباره) و lib/countergeo.ts (سه‌گوش‌سازیِ ExtrudeGeometry) — تا هندسه، که خط فرمان هم (از راهِ @darzsaz/report) اجرایش می‌کند، three نخواهد. جای x ِ یونیت در ردیف فقط از layoutRun/runEdges (core/layout/run.ts) و حدِ عرض فقط از widthLimits/clampWidth (core/layout/width.tsapps/web/test/math-sources.test.ts.

bundles.ts سندهای کاغذی را از خروجی derive (ReportInput در input.ts) می‌سازد: یک تابعِ برگه برای هر PageKey (pages.ts) — summary-page، cutlist، cutmap + cutmap-page (نقشهٔ هر ورق)، cutout-page، countertop-page، edging-guide، drill-page، drawing-page، assembly-page، bom-page، labels — در بسته‌های مخاطب all، cutter، installer و customer؛ report.ts (fullReport) همان بستهٔ all است. html.ts پوستهٔ سند، با قلم جاسازی‌شده (fonts.ts، تولیدشده از scripts/build-fonts.mjs) و CSS چاپ (sheet.css، که scripts/report-css.mjs آن را sheet-css.ts می‌کند)؛ csv.ts (با BOM یونیکد برای اکسل)؛ dxf.ts برای CNC.

main.tsx ورود: فعال کردنِ زبان پیش از رندر؛ ثبت کارگر سرویس در تولید
App.tsx مسیرها (wouter روی هش) به صفحه‌های تنبلِ app/؛ UiProvider با پوسته و زبان
app/ صفحه‌ها: Home، EditorPage (نوار بالا، کشو، بوم/سه‌بعدی، ویژگی‌ها، نوار وضعیت)، CostPage،
WorkshopPage، SharePage، ViewerPage، Help؛ رجیستریِ فرمان، پالتِ فرمان، نقشهٔ کلید
state/store.ts zustand + immer: project، catalog، wallId، انتخاب، past/future (واگرد، نامِ قدم پیام)؛
loadIntoEditor تنها راهِ نشاندنِ پروژه؛ readOnly برای زبانهٔ بی قفل
lib/steps.ts نامِ قدم‌های تاریخچه که از چند جا ثبت می‌شوند (`historyStep`)
state/derived.ts نتیجهٔ خط لوله و «تازه بودن»ش نسبت به project
lib/derive.worker.ts چیدمان ورق و قواعدِ دستیار در Worker، و رتبهٔ پیشنهادِ پر کردن و «یک ورق کمتر»؛
نتیجهٔ Nested با مسئله‌های بی تابع برمی‌گردد
lib/derive-protocol.ts قراردادِ پیامِ نخ اصلی و Worker — با issue-data.ts تنها کدی که دو محیط شریک‌اند
lib/derive-client.ts Worker با بازیابی: مهلت ← Worker ِ تازه، سه افتادنِ پیاپی ← نخ اصلی
lib/useDerivePipeline.ts پیوند store ↔ derive-client ↔ finishDerive
lib/useIssues.ts مسئله‌های Worker ِ خط لوله؛ قواعد روی نخ اصلی فقط پیش از اولین جواب
lib/issue-data.ts مسئلهٔ بی تابع برای postMessage و راه‌حلِ تنبل هنگامِ کلیک
lib/rectify.worker.ts Worker ِ راست‌سازیِ عکس (ریاضیِ پیکسل در rectify.ts، شریک با rectify-client.ts)
editor/ ماشین حالتِ تعاملِ بوم، چفت و کشیدنِ زنده — خالص، بی React
components/ هر پنل یک پوشه وقتی بزرگ شد: catalog/، cost/، inspector/، issues/، photo/،
properties/، render/، scene/، settings/، unit-builder/، wall-canvas/، workshop/
components/layout/ پوستهٔ ویرایشگر: سه پنلِ SplitView، مرکزِ دو نمایی با یک صحنه، برگهٔ گوشی — editor.md
(پنجره‌ها همه `Dialog` ِ کیت؛ Overlay.tsx ِ دست‌ساز در فاز ۵.۵ رفت)
lib/unit-presets/ کتابخانهٔ یونیتِ کشو (زبانه‌های زمینی، دیواری، قدی)، روی پیش‌تنظیم‌های هسته
lib/render/, lib/ao/, lib/textures/ رندر آفلاین: انباشت، انسداد محیطی، بافت رویه‌ای
scene/materials.ts موادِ سه‌بعدی، نورها و رنگِ داده — تنها رنگِ خامِ TS ِ اپ
styles.css, styles/ CSS ِ چیدمانِ سراسری و کلاس‌های کمکیِ مشترک (util.module.css)
data/ لایهٔ داده: تنها جای Dexie؛ مخزن‌ها، پاکتِ ردیف، ارتقا، پشتیبان — data-layer.md
lib/persistence/ ذخیرهٔ خودکار (صف)، قفلِ زبانه و کانال، پروندهٔ متصل، آوردن و نجات — storage.md
lib/print.ts چاپ از راه iframe ِ بی اسکریپت با srcdoc

بوم دوبعدی SVG است (نه canvas) تا انتخاب، کشیدن و صفحه‌خوان طبیعی باشند. نمای سه‌بعدی با react-three-fiber؛ رندر با کیفیت از همان صحنه گرفته می‌شود (components/render/RenderBridge.tsx).

main.ts ورود و cli-main.ts درختِ فرمانِ citty؛ هر فرمان در commands/*.ts با تابعِ run*(opts, cat) و یک defineCommand؛ project.ts بارگذاری از راه unpackDarzWithAssets ِ هستهٔ مشترک (.darz و JSON، و تصویرهای پرونده برای جلدِ گزارش)؛ pdf.ts کروم بی‌سر (یافته با chrome.ts). جزئیات در cli.md.

چیز چرا نه کجا
ردیاب پرتو برای هندسه‌ای که همه‌اش جعبه است، به هزینه‌اش نمی‌ارزد docs/journal/25-render.md
پس‌پردازش با EffectComposer کل خط رندر را می‌برد و انباشت را می‌شکند همان
SoftShadows / ContactShadows از drei با three ۰٫۱۸۵ کار نمی‌کنند همان
بودجهٔ زمانی در چیدمان ورق نتیجه را به سرعت دستگاه گره می‌زد pipeline.md
حساب کاربری، ابر برنامه محلی و پرونده‌محور است docs/journal/28-plan-v2.md
Tailwind، pdf-lib، SheetJS CSS دستی، چاپ به PDF، CSV و XLSX ِ دست‌نوشت (apps/cli/src/xlsx.ts) — ساده‌تر و آفلاین این سند

هر کد در محیطی اجرا می‌شود و فقط تیپ‌های همان را می‌بیند. tsconfig.json ِ هر بسته فقط فهرستِ برنامه‌هاست (files: [] و references) برای ویرایشگر و ESLint؛ typecheck هر برنامه را جدا می‌سنجد:

برنامه کجا کتابخانه و تیپ
tsconfig.app.json ِ core، i18n، geometry، report src — مرورگر، Worker و Node یکسان ES2022 + WebWorker؛ بی تیپِ Node، بی document
apps/web/tsconfig.app.json، packages/ui/tsconfig.app.json رابط در نخ اصلی DOM؛ بی WebWorker و Node
apps/web/tsconfig.worker.json src/**/*.worker.ts WebWorker؛ بی DOM
apps/cli/tsconfig.app.json خط فرمان Node
tsconfig.test.json ِ هر بسته آزمون، e2e، story، پیکربندی‌ها Node (و DOM جایی که jsdom یا Playwright هست)
scripts/tsconfig.json scripts/**/*.mjs با // @ts-check checkJs روی Node

پیش‌تر هر بسته یک برنامه با types: ["node"] بود: process در سورسِ هسته و document در Worker از tsc می‌گذشت. tsconfig.base.json بر strict این‌ها را هم دارد: noUncheckedIndexedAccess، exactOptionalPropertyTypes، noPropertyAccessFromIndexSignature، noImplicitReturns، noImplicitOverride، noFallthroughCasesInSwitch، noUnusedLocals، noUnusedParameters و noUncheckedSideEffectImports (واردکردنِ بی‌نامی که به پرونده‌ای نمی‌رسد). tsconfig.build.json فقط برای ساخت است و شرطِ @darzsaz/source را خاموش می‌کند.

قواعد ساختاری که ابزار نگه می‌دارد

Section titled “قواعد ساختاری که ابزار نگه می‌دارد”
  • هیچ پرونده‌ای بیش از ۳۰۰ خط (بدون خط خالی و کامنت؛ آزمون‌ها ۴۰۰) — max-lines در ESLint
  • پیچیدگی هر تابع ≤ ۱۲، عمق تودرتویی ≤ ۴ — complexity، max-depth
  • تابعِ اعلام‌شده نوع بازگشت صریح دارد (explicit-function-return-type؛ کال‌بک و تابعی که تیپش از پیش معلوم است معاف‌اند)؛ any و ! در کد محصول ممنوع
  • پوششِ تیپِ هر برنامهٔ تولیدی ≥ ۹۹٪ با type-coverage --strict (as، ! و any ِ پنهان بی‌پوشش شمرده می‌شوند) — scripts/type-coverage.mjs (testing.md)
  • صادرات بی‌استفاده وجود ندارد — knip، با includeEntryExports برای packages/*: صادره‌ای از بارولِ بسته که هیچ بستهٔ دیگری و هیچ آزمونی نمی‌خواند می‌رود. knip وارد کردنِ بین‌بسته‌ای را با outDir ِ tsconfig.json ِ هر بسته از dist به src برمی‌گرداند؛ و await import('@darzsaz/core') برای knip «همهٔ صادرات مصرف دارد» است، پس وارد کردنِ ایستا.
  • چرخهٔ وارد کردن — import type هم — صفر: scripts/cycles.mjs (madge) روی src ِ هر بسته. تیپ یا تابعی که دو ماژول می‌خواهند در پروندهٔ برگ می‌نشیند (types/project.ts برای Variant، report/src/input.ts، parts/accessory-run.ts).
  • پوشش فقط بالا می‌رود — خطِ پایه در coverage-baseline.json و چرخ‌دندهٔ coverage-ratchet (testing.md)