# 🌍 التوثيق الشامل لمشروع الخرائط (Map SaaS Complete Documentation) هذا المستند يعتبر المرجع الشامل لكامل البنية التحتية لمشروع الخرائط. يشرح جميع الأجزاء (الخريطة، البحث، التوجيه)، كيف تتصل ببعضها البعض، وكيف يتم تكاملها مع واجهات الفلاتر (Flutter) الخاصة بالمستخدم. --- ## 🏛️ البنية التحتية للمشروع (Architecture Overview) يتكون النظام من ثلاثة محركات رئيسية تعمل بتناغم تام لتقديم تجربة تضاهي جوجل ماب: 1. **محرك رسم الخرائط (Tile Server - Martin)**: مسؤول عن رسم الخريطة الجغرافية والشوارع. 2. **محرك البحث الجغرافي (Geocoding Engine)**: مسؤول عن البحث، الإكمال التلقائي، وتصحيح الأخطاء. 3. **محرك التوجيه والمسارات (Routing Engine - GraphHopper)**: مسؤول عن رسم مسار الرحلات واحتساب الوقت مع الأخذ بعين الاعتبار الازدحام المروري. --- ## 🗺️ 1. محرك رسم الخرائط (Martin Tile Server) ### ❓ ما هو Martin وكيف يعمل؟ Martin هو خادم سريع جداً (مكتوب بلغة Rust) متصل مباشرة بقاعدة بيانات `PostgreSQL / PostGIS`. وظيفته هي تحويل الإحداثيات والحدود الجغرافية الموجودة في قاعدة البيانات إلى **Vector Tiles** (مربعات شعاعية بصيغة `pbf`). ### 🎨 كيف ترسم الخريطة (Rendering)؟ بدلاً من إرسال صور (Images) ثقيلة للمستخدم كما في الخرائط القديمة، يرسل Martin بيانات هندسية خفيفة جداً (أرقام وإحداثيات). المتصفح أو تطبيق الجوال (Flutter) يقوم بأخذ هذه البيانات، ويمررها إلى كرت الشاشة (GPU) ليقوم برسم الشوارع، المباني، والحدائق بسلاسة فائقة بمعدل 60 إطاراً في الثانية (60fps) بناءً على ملف تصميم يسمى `style.json`. ### 📱 استخدام الخريطة في Flutter لرسم الخريطة داخل تطبيق Flutter الخاص بك، ستحتاج إلى مكتبة [maplibre_gl](https://pub.dev/packages/maplibre_gl): ```dart MaplibreMap( styleString: 'http://SERVER_IP:3000/public/style.json', // رابط الـ Style الخاص بالخادم initialCameraPosition: CameraPosition( target: LatLng(31.95, 35.91), // عمّان zoom: 14.0, ), onMapCreated: (MaplibreMapController controller) { // الخريطة أصبحت جاهزة للرسم عليها }, ) ``` --- ## 🔍 2. محرك البحث الجغرافي (Geocoding Engine) محرك ذكي جداً مكتوب بـ `NestJS`، يتفهم لغة الشارع العربي والأخطاء الإملائية. ### أ. الإكمال التلقائي (Autocomplete API) يستدعى مع كل حرف يكتبه المستخدم لتقديم اقتراحات فورية بأقل من 50 ملي ثانية (باستخدام فهارس `varchar_pattern_ops`). - **الرابط:** `GET /api/geocoding/autocomplete?q=مستش` - **الاستخدام في Flutter:** ربطه بـ `TypeAheadField`، لعرض أسماء المستشفيات بمجرد كتابة "مستش". ### ب. البحث الدقيق (Search API) يستدعى عند ضغط زر "بحث" أو اختيار نتيجة. يقوم بترتيب الأماكن بناءً على خوارزمية ذكية: (50% تشابه نصي، 30% أهمية/شعبية المكان، 20% المسافة). - **الرابط:** `GET /api/geocoding/search?q=السيتي مول` - **ميزات النظام الداخلية المدعومة هنا:** 1. **التطبيع العربي:** يعالج (إ/ا/أ/ة/ه). 2. **الاستعلامات النسبية:** يفهم (قرب المستشفى، بجانب البنك). 3. **مداخل المنشآت (POI Gates):** قد يرجع المحرك نقاط مداخل OSM الموثقة للمنشأة ضمن مصفوفة `gates`. لا تُنشأ نقاط تقديرية، ولا توصف البوابة بأنها رئيسية إلا إذا كانت موسومة صراحةً في المصدر. 4. **هل تقصد (Did you mean):** إذا كتب المستخدم مصطلحاً خاطئاً بالكامل ("السمساني") وعاد بـ 0 نتائج، يقوم المحرك ببحث `KNN` لإرجاع اقترح للتصحيح. **الاستخدام في Flutter:** عند نجاح البحث، نأخذ الـ `latitude` و `longitude` للنتيجة، ونقوم بتحريك الكاميرا: ```dart controller.animateCamera(CameraUpdate.newLatLng(LatLng(lat, lng))); ``` وإذا كان الرد يحتوي على `gates`، يمكن إظهار نافذة منبثقة للسائق لاختيار أحد المداخل الموثقة: *"أي مدخل تقصد؟"*. عند غيابها لا يعرض التطبيق اختيار بوابة غير موثقة. --- ## 🚗 3. محرك التوجيه والمسارات (Routing & Traffic Engine) يعتمد هذا النظام على محرك `GraphHopper` المدموج بتعديلات `NestJS` لحساب الازدحام المروري وتوفير المسار الأسرع. ### طلب مسار (Route API) يقوم هذا الـ API بحساب المسار من نقطة (A) إلى نقطة (B)، مع إرجاع المسار البديل وتوجيهات الملاحة، مع أخذ "عامل الازدحام" بعين الاعتبار حسب ساعة ويوم الطلب. - **الرابط:** `GET /api/maps/route?start=lat,lng&end=lat,lng&profile=car` - **شكل الرد (Response Overview):** يُرجع الرد المسار الأفضل `points` مشفراً بصيغة (Polyline)، والوقت `duration`، والمسافة `distance`. ### 📱 رسم المسار في Flutter بما أننا ألغينا توليد الـ `GeoJSON` الثقيل من السيرفر لتخفيف العبء، فإن تطبيق الفلاتر سيتكفل بفك التشفير. 1. استقبل الـ `points` (الـ Polyline) من الـ API. 2. استخدم مكتبة مثل [flutter_polyline_points](https://pub.dev/packages/flutter_polyline_points) لفك تشفيرها إلى قائمة من إحداثيات (List of LatLng). 3. ارسمها على خريطة MapLibre كـ `LineLayer`: ```dart // فك التشفير List decodedPoints = polylinePoints.decodePolyline(apiResponse['points']); // تحويلها لصيغة يفهمها MapLibre final lineString = { "type": "Feature", "geometry": { "type": "LineString", "coordinates": decodedPoints.map((p) => [p.longitude, p.latitude]).toList() } }; // رسم المسار بخط أزرق على الخريطة await controller.addSource("route-source", GeojsonSourceProperties(data: lineString)); await controller.addLineLayer( "route-source", "route-layer", LineLayerProperties( lineColor: "#007AFF", lineWidth: 5.0, lineJoin: "round", ), ); ``` --- ## 🔄 ملخص دورة حياة الطلب (User Flow in App) 1. **الفتح الأولي:** يفتح الراكب تطبيق Flutter ⬅️ تقوم أداة `MapLibre` بتحميل خريطة الـ Vector السريعة من خادم `Martin`. 2. **البحث:** يكتب الراكب في صندوق البحث ⬅️ يتم مناداة `/autocomplete` لعرض الاقتراحات فوراً. 3. **الاختيار:** يختار الراكب (مثلاً: سيتي مول) ⬅️ يتم مناداة `/search` ⬅️ الخادم يرجع المداخل الموثقة المتاحة إن وجدت؛ وقد لا تتوفر نقاط أبواب للمنشأة. 4. **طلب الرحلة:** عند اختيار مدخل موثق، يرسل التطبيق موقع الراكب وإحداثيات ذلك المدخل إلى `/api/maps/route` ⬅️ الخادم يحسب المسار ويرجع خط سير (Polyline) ⬅️ تطبيق Flutter يفك تشفير الخط ويرسمه على الخريطة. لحقول البوابات، المصدر، التغطية والجدولة راجع [توثيق أبواب ومداخل المنشآت](PLACE_GATES_COVERAGE_AR.md). بذلك نكون قد غطينا البنية المعمارية الكاملة بأدق تفاصيلها من السيرفر وحتى واجهة التطبيق! 🚀