System · Architecture v1.0 النظام · الهندسة v1.0

One folder per product. مجلد واحد لكل منتج.

The site is built strictly modular. New products are never maintained in code — they are uploaded as folders to the server and detected automatically. This document describes the binding schema and the workflow.

الموقع مبني بشكل معياري صارم. لا تتم صيانة المنتجات الجديدة في الشيفرة أبداً — بل تُرفع كمجلدات إلى الخادم وتُكتشف تلقائياً. يصف هذا المستند المخطط الملزم وسير العمل.

1 · Principle ١ · المبدأ

Three files, one contract: the schema (binding), the template (copy source), and the loader (frontend). As long as every product satisfies the schema, the site can grow indefinitely.

ثلاثة ملفات، عقد واحد: المخطط (مُلزم)، والقالب (مصدر النسخ)، والمُحمِّل (الواجهة). طالما أن كل منتج يلبّي المخطط، يمكن للموقع أن ينمو بلا حدود.

01 · TEMPLATE

Copy folder انسخ المجلد

_template/<slug>/

02 · FILL

product.json + images product.json + الصور

Fill required fields, drop images. املأ الحقول المطلوبة وأودِع الصور.

03 · UPLOAD

FTP push رفع FTP

Upload the folder into /products/. ارفع المجلد إلى /products/.

04 · LIVE

Auto-detection اكتشاف تلقائي

API scans, frontend renders. يفحص API، تعرض الواجهة.

2 · Directory structure ٢ · بنية المجلدات

The whole site is flat — no build tooling required. Everything related to products lives under /products/.

الموقع كامل مسطّح — دون أدوات بناء. كل ما يتعلق بالمنتجات يقع داخل /products/.

/ ├── index.html // home ├── products.html // auto-listed catalogue ├── product.html // detail page (?slug=…) ├── architecture.html // this document ├── about.html · contact.html │ ├── assets/ │ ├── css/site.css // design tokens │ └── js/ │ ├── site.js // nav + footer + i18n │ └── products.js // loader + validator │ ├── products/ │ ├── _schema/product.schema.json // JSON Schema (contract) │ ├── _template/ // copy source │ │ ├── product.json │ │ └── README.md │ │ │ ├── api.php // server-side scanner (optional) │ ├── index.json // static manifest (fallback) │ │ │ ├── hajar-h81/ // 1 product = 1 folder │ │ ├── product.json │ │ ├── images/ │ │ │ ├── cover.jpg │ │ │ ├── 01.jpg · 02.jpg · 03.jpg │ │ │ └── detail.jpg │ │ └── downloads/ │ │ └── datasheet.pdf │ │ │ ├── hajar-c180/ · … │ ├── al-hajar-app/ · … │ └── new-product/ ← just drop it here │ └── bin/build-index.mjs // CLI indexer (for static hosts)

3 · Product schema ٣ · مخطط المنتج

Every product.json is validated against /products/_schema/product.schema.json (JSON Schema Draft-7). Required fields are marked red.

كل product.json يتم التحقق منه مقابل /products/_schema/product.schema.json (JSON Schema Draft-7). الحقول المطلوبة معلَّمة بالأحمر.

Fields الحقول

Fieldالحقل Typeالنوع Descriptionالوصف
slug requiredstringURL slug. Must equal the folder name. ^[a-z0-9-]+$رمز URL. يجب أن يطابق اسم المجلد. ^[a-z0-9-]+$
name.en requiredstringDisplay name (English). name.ar optional.الاسم المعروض (إنجليزي). name.ar اختياري.
collection requiredenumstratum | mashraq | adat
category requiredenumheat-container · heat-pump · charge-container · fast-charger · energy-storage · hybrid · software · platform
status requiredenumavailable · on-request · limited · preview · in-development
headline.en requiredstring ≤140Single-sentence summary.ملخص من جملة واحدة.
description.en requiredstringBody copy. Paragraphs split by \n\n.نص أساسي. تفصل الفقرات بـ \n\n.
specs.output_kw requirednumberUseful output (heat or charge) in kW.القدرة المفيدة (تدفئة أو شحن) بالكيلوواط.
media.cover requiredpathPath relative to the product folder, e.g. images/cover.jpgمسار نسبي لمجلد المنتج، مثل images/cover.jpg
Optional
specs.* optionalmixedcascade_modules · refrigerant · cop_a7w35 · buffer_l · max_flow_temp_c · charge_outputs · max_dc_power_kw · battery_capacity_kwh · grid_connection · dimensions_cm · weight_kg · noise_db_a · monitoring · warranty_months
applications optionalarrayRecommended use cases. Items may be string or {en, ar}.حالات الاستخدام الموصى بها. عناصر إما نصية أو {en, ar}.
compliance optionalstring[]Standards / certifications.المعايير والشهادات.
media.gallery optionalpath[]Additional images.صور إضافية.
colors optionalhex[]Swatch palette.لوحة عينات الألوان.
price optionalobjectpurchase_eur · rent_eur_month · on_request: bool
downloads optionalobject[]label · file · kind (pdf/dwg/step/zip/…)
external_url optionaluriIf set, the product card links to this URL (sister brands).إن تم تحديده، تربط بطاقة المنتج بهذا الرابط (العلامات الشقيقة).
tags optionalstring[]Free-form keywords.كلمات مفتاحية حرة.
featured optionalbooleanShow on the home page.عرض في الصفحة الرئيسية.
published_at · updated_atdateISO date (YYYY-MM-DD).

Complete example مثال كامل

// /products/hajar-h81/product.json
{
  "slug": "hajar-h81",
  "name": { "en": "Hajar H81", "ar": "الهاجر H81" },
  "collection": "stratum",
  "category": "heat-container",
  "status": "available",
  "featured": true,
  "headline": { "en": "Flagship cascade heat pump…" },
  "description": { "en": "…" },
  "specs": {
    "output_kw": 81,
    "cascade_modules": "3 × 27 kW",
    "refrigerant": "R290 (Propane, GWP 3)",
    "cop_a7w35": 3.9,
    "buffer_l": 2000
  },
  "media": { "cover": "images/cover.jpg" }
}

4 · Auto-detection ٤ · الاكتشاف التلقائي

The frontend tries two sources — the first one to respond wins:

تجرب الواجهة مصدرين — يفوز أول من يستجيب:

  1. Server scan (ideal, zero manual step):
    products/api.php?list scans /products/, validates each product.json and returns the list. Requires PHP 7+ on the web server.
  2. فحص الخادم (مثالي، بدون خطوة يدوية):
    يفحص products/api.php?list المجلد /products/ ويتحقق من كل product.json ويعيد القائمة. يتطلب PHP 7+.
  3. Static manifest (fallback, one command after FTP):
    products/index.json is generated by node bin/build-index.mjs (identical logic). For hosts without PHP.
  4. قائمة ثابتة (احتياطية، أمر واحد بعد FTP):
    يُنشَأ products/index.json بأمر node bin/build-index.mjs. للاستضافات بلا PHP.

Both sources discard folders whose product.json is invalid or whose slug doesn't match the folder name. A broken upload does not break the site — the defective product simply doesn't appear.

يتجاهل كلا المصدرين المجلدات التي يكون فيها product.json غير صالح أو لا يتطابق فيها slug مع اسم المجلد. لا يكسر الرفع المعطّل الموقع — ببساطة لا يظهر المنتج التالف.

FTP workflow سير عمل FTP

// prepare locally
$ cp -r products/_template products/hajar-h120
$ vim products/hajar-h120/product.json
$ cp ./photos/*.jpg products/hajar-h120/images/

// upload
$ rsync -av products/hajar-h120/ ftp.al-hajar.ae:/www/products/hajar-h120/

// with PHP available: done. otherwise regenerate the index:
$ node bin/build-index.mjs
$ scp products/index.json ftp.al-hajar.ae:/www/products/index.json

5 · Page structure ٥ · بنية الصفحات

The navigation is declarative in assets/js/site.js (the SITE object). A new page needs three steps: create the HTML file, add an entry to SITE.nav, append a footer column.

التنقل معلَن في assets/js/site.js (كائن SITE). تحتاج صفحة جديدة ثلاث خطوات: إنشاء ملف HTML، إضافة سطر إلى SITE.nav، وإلحاق عمود تذييل.

Pageالصفحة Fileالملف Modularityالمعيارية
Homeالرئيسيةindex.htmlSection-based · featured block loads dynamically.قائم على الأقسام · يحمَّل قسم المميزة ديناميكياً.
Catalogueالكتالوجproducts.htmlFully dynamic · filters built from data.ديناميكي بالكامل · المرشحات تُبنى من البيانات.
Product detailتفصيل المنتجproduct.html?slug=…Fully dynamic · one template, all products.ديناميكي بالكامل · قالب واحد، كل المنتجات.
Houseالمؤسسةabout.htmlStatic · sections freely extensible.ثابتة · الأقسام قابلة للتوسيع بحرية.
Systemالنظامarchitecture.htmlThis document.هذا المستند.
Contactتواصلcontact.htmlStatic · form stub.ثابتة · هيكل نموذج.

6 · Extending the system ٦ · توسيع النظام

The system is deliberately flat. Extensions follow three patterns:

النظام مسطّح عمداً. تتبع التوسعات ثلاثة أنماط:

Add a category إضافة فئة

  1. Add the value to the category enum in _schema/product.schema.json.
  2. أضف القيمة إلى enum category في _schema/product.schema.json.
  3. Add a display label to CATEGORY_LABEL in products.js (EN + AR).
  4. أضف تسمية العرض إلى CATEGORY_LABEL في products.js (EN + AR).
  5. Done — the filter appears automatically.
  6. انتهى — يظهر المرشح تلقائياً.

Add a schema field إضافة حقل إلى المخطط

  1. Document the field in the schema (type + optional/required).
  2. وثِّق الحقل في المخطط (النوع + اختياري/إلزامي).
  3. Add it to _template/product.json as a starter value.
  4. أضفه إلى _template/product.json كقيمة ابتدائية.
  5. Add the render row in product.html.
  6. أضف صف العرض في product.html.

Add a sub-brand إضافة علامة فرعية

  1. Add the value to the collection enum.
  2. أضف القيمة إلى enum collection.
  3. Add a meta entry to COLLECTION_META (colors, label).
  4. أضف إدخالاً وصفياً إلى COLLECTION_META (الألوان، التسمية).
  5. Optionally: dedicated section on the home page.
  6. اختيارياً: قسم مخصص على الصفحة الرئيسية.
Maintenance rule قاعدة الصيانة
Never maintain product data in HTML or JS. Always in the folder. لا تحفظ بيانات المنتج أبداً في HTML أو JS. دائماً في المجلد.