معماری
بستهها و جهت وابستگی
Section titled “بستهها و جهت وابستگی”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/referencecore به هیچ بستهٔ دیگری و به هیچ چیزِ مرورگر وابسته نیست — زبان هم نه: پیام برمیگرداند
(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.
جای هر چیز
Section titled “جای هر چیز”نقشهٔ سریع: کدام پوشه صاحبِ کدام موضوع است. تا فاز ۹ همین جدول در 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، hardwareForUnit)؛ normalizeUnit در مرز |
| قواعد دستیار | 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»)؛ اسکریپت و کلیدها بیرونِ مخزن، در بکاپِ رمزها |
نقشهٔ packages/core/src
Section titled “نقشهٔ packages/core/src”| پوشه | چه میکند | نقطهٔ ورود |
|---|---|---|
types/ |
تیپهای مدل داده: project.ts، unit.ts، part.ts، catalog.ts |
types/index.ts (بازصدورِ تیپ؛ project.ts با فهرستِ صریح) |
catalog/ |
کاتالوگ ایران (defaults.ts، داده در data/*.ir.json)، createCatalog() با اعتبارسنجی زمان اجرا |
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/ |
یک خط لوله برای همه: nestOptions → nestProject → finishDerive → derive؛ رتبهٔ پیشنهادهای پر کردن (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.ts)؛ darz-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()) |
packages/geometry/src
Section titled “packages/geometry/src”projectScene(project, cat, cache?) صحنه را میسازد: unit-instances → carcass-instances،
front-instances (با classic-instances)، corner-instances و interior-instances؛ fixtures (گاز، هود،
سینک، شیر و دستگاهها)، transform (مختصات دیوار → اتاق)، emitter (جمعکردن جعبههای یونیت)، isometric
برای نقشهٔ مونتاژ. خروجی یک Scene است — parts جعبههای {materialId, size, center, rotY?, …}، fixtures
و bounds — بدون هیچ وابستگی به three؛ با createSceneCache() فقط یونیتهای تغییرکرده از نو ساخته میشوند.
باز شدنِ نما در motion.ts است، نه در وب (نسل ششم، فاز ۳): هر قطعه frontId و motion دارد —
swing (محور از ضربِ برداری، روی صفحهٔ جلوی بدنه و یک ضخامت بیرونِ لبهٔ لولادار؛ زاویه از
Hinge.openAngle)، slide (طولِ ریل × کشش)، 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.ts)؛ apps/web/test/math-sources.test.ts.
packages/report/src
Section titled “packages/report/src”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.
apps/web/src
Section titled “apps/web/src”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 نتیجهٔ خط لوله و «تازه بودن»ش نسبت به projectlib/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 ↔ finishDerivelib/useIssues.ts مسئلههای Worker ِ خط لوله؛ قواعد روی نخ اصلی فقط پیش از اولین جوابlib/issue-data.ts مسئلهٔ بی تابع برای postMessage و راهحلِ تنبل هنگامِ کلیکlib/rectify.worker.ts Worker ِ راستسازیِ عکس (ریاضیِ پیکسل در rectify.ts، شریک با rectify-client.ts)editor/ ماشین حالتِ تعاملِ بوم، چفت و کشیدنِ زنده — خالص، بی Reactcomponents/ هر پنل یک پوشه وقتی بزرگ شد: 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.mdlib/persistence/ ذخیرهٔ خودکار (صف)، قفلِ زبانه و کانال، پروندهٔ متصل، آوردن و نجات — storage.mdlib/print.ts چاپ از راه iframe ِ بی اسکریپت با srcdocبوم دوبعدی SVG است (نه canvas) تا انتخاب، کشیدن و صفحهخوان طبیعی باشند. نمای
سهبعدی با react-three-fiber؛ رندر با کیفیت از همان صحنه گرفته میشود
(components/render/RenderBridge.tsx).
apps/cli/src
Section titled “apps/cli/src”main.ts ورود و cli-main.ts درختِ فرمانِ citty؛ هر فرمان در commands/*.ts با تابعِ run*(opts, cat) و
یک defineCommand؛ project.ts بارگذاری از راه unpackDarzWithAssets ِ هستهٔ مشترک (.darz و JSON، و تصویرهای
پرونده برای جلدِ گزارش)؛ pdf.ts کروم بیسر (یافته با chrome.ts).
جزئیات در cli.md.
چیزهایی که عمداً نیست
Section titled “چیزهایی که عمداً نیست”| چیز | چرا نه | کجا |
|---|---|---|
| ردیاب پرتو | برای هندسهای که همهاش جعبه است، به هزینهاش نمیارزد | 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) — سادهتر و آفلاین |
این سند |
محیطهای TypeScript
Section titled “محیطهای TypeScript”هر کد در محیطی اجرا میشود و فقط تیپهای همان را میبیند. 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)