# PDF Editor Step 3 - Joint Widget & Weldmap Entegrasyonu Roadmap ## 📋 Görev Özeti **Amaç:** PDF çizimlerinde interaktif joint veri girişi sağlamak ve PDF Editor, Base Weldmap ve Weldlog veritabanları arasında iki yönlü entegrasyon kurmak. **Temel Gereksinimler:** 1. Veri girişi için interaktif joint widget (popup) 2. Kayıt edilene kadar geçici veri depolama 3. Base Weldmap ve Weldlog ile SQL entegrasyonu 4. İki yönlü veri senkronizasyonu 5. Document Revision entegrasyonu (Spool Iso / As-Build) --- ## 🎯 Fonksiyonel Gereksinimler Özeti ### Senaryo 1: Engineering Iso + Adding Joints - Kullanıcı PDF üzerine üçgen (Field) veya yuvarlak (Shop) çizer - Veri girişi için widget otomatik açılır - Veriler kayıt edilene kadar hafızada tutulur - Kayıt sırasında: SQL ile Base Weldmap'e ekleme - Çizimi Document Revision "Spool Iso" kısmına kaydet ### Senaryo 2: Spool Iso/Asbuild Iso + Adding Joints & Welder - Kullanıcı mevcut joint üzerine gelir - Widget önceden girilmiş verilerle açılır (Welder1-2 boş) - Welder1-2 dropdown'larında uygun kaynakçıları listele - PDF görüntüsünü güncelle: joint no (üstte), welder ID (altta), ayırıcı çizgi - Kayıt sırasında: SQL ile Weldlog'u güncelle - Çizimi Document Revision "As-Build" kısmına kaydet ### Senaryo 3: Veri Var ama Çizim Eksik - Base Weldmap/Welder verisi var ama çizim eksik mi kontrol et - Sol paneli aktifleştir: Spool No, Joint No, Welder ID bölümleri - Kullanıcı Spool No seçer → Joint listesi - Kullanıcı Joint + F/S şekli seçer → Çizim görünür - Kullanıcı Joint + Welder + F/S şekli seçer → Welder ile çizim görünür - Document Revision'a kaydet (Spool Iso veya As-Build) --- ## 🗺️ Geliştirme Roadmap'i ### Faz 1: Temel Yapı & Veri Yapısı (Hafta 1) #### 1.1 Geçici Veri Depolama Sistemi **Hedef:** Kaydedilmemiş joint verileri için hafıza içi veri depolama sistemi oluştur **Görevler:** - [ ] Geçici depolama için `JointDataManager` JavaScript sınıfı oluştur - [ ] Veri yapısını uygula: `Map` - [ ] Depolamadan önce veri doğrulama ekle - [ ] Tarayıcı sessionStorage'da veri kalıcılığı (yedek) - [ ] Sayfa kapanışında veri temizleme oluştur **En İyi Uygulamalar:** - O(1) arama performansı için Map kullan - Çakışma çözümü için veri versiyonlama uygula - Depolamadan önce veri doğrulama katmanı ekle - Sayfa yenilemede hayatta kalması için sessionStorage kullan **Oluşturulacak/Değiştirilecek Dosyalar:** - `resources/views/admin/type/pdf-editor.blade.php` (JointDataManager sınıfı ekle) - Oluştur: `public/js/pdf-editor/joint-data-manager.js` (opsiyonel ayrım) #### 1.2 Widget Modal Geliştirmesi **Hedef:** Mevcut joint widget modal'ını tüm gerekli alanlarla geliştir **Görevler:** - [ ] `joint-widget-modal.blade.php` dosyasını gözden geçir ve geliştir - [ ] Edit type'a göre koşullu alan gösterimi ekle - [ ] IC Log member seçimi uygula (Member1, Member2) - [ ] IC Log'dan Material, Dia, NPS, Thickness için otomatik doldurma mantığı ekle - [ ] Yeterliliğe göre welder dropdown filtreleme uygula - [ ] Form doğrulama ekle **En İyi Uygulamalar:** - Dropdown'lar için Select2 kullan (projede mevcut) - Member seçimi için debounced API çağrıları uygula - Kademeli dropdown'lar uygula (member → material detayları) - Asenkron işlemler için yükleme durumları ekle - Bootstrap 5 form doğrulama kullan **Değiştirilecek Dosyalar:** - `resources/views/components/modals/joint-widget-modal.blade.php` - `resources/views/admin/type/pdf-editor.blade.php` (widget entegrasyonu) **Önemli Not:** Widget açılışı için **double-click** kullanılacak. Mevcut double-click silme özelliği kaldırılmalı veya farklı bir tuş kombinasyonu ile değiştirilmelidir. --- ### Phase 2: Shape Interaction & Widget Integration (Week 1-2) #### 2.1 Shape Click/Hover Event Handling **Goal:** Open widget when user interacts with joint shapes **Tasks:** - [ ] Add click event listener to triangle/circle shapes - [ ] Add hover event listener for existing joints (Scenario 2) - [ ] Position widget near clicked shape - [ ] Load existing data if joint already has data - [ ] Handle shape creation event (Scenario 1) **Best Practices:** - Use Fabric.js event delegation for performance - Implement debouncing for hover events - Calculate optimal widget position (avoid screen edges) - Use requestAnimationFrame for smooth animations - Add visual feedback (highlight shape on hover) **Implementation:** ```javascript // Shape click handler fabricCanvas.on('mouse:down', (e) => { if (e.target && (e.target.type === 'triangle' || e.target.type === 'circle')) { if (currentEditType === 'adding_joints' || currentEditType === 'adding_joints_welder') { openJointWidget(e.target, e.e); } } }); // Hover handler for existing joints fabricCanvas.on('mouse:over', (e) => { if (e.target && e.target.shapeId && hasExistingData(e.target.shapeId)) { showHoverTooltip(e.target); } }); ``` #### 2.2 Widget Data Binding **Goal:** Connect widget form with shape data **Tasks:** - [ ] Load shape data into widget form - [ ] Save widget data to temporary storage - [ ] Update shape label display (joint no, welder ID) - [ ] Handle form field changes (real-time updates) - [ ] Implement cancel/close behavior **Best Practices:** - Use two-way data binding pattern - Implement reactive updates (update shape when form changes) - Add unsaved changes warning - Use event-driven architecture **Files to Modify:** - `resources/views/admin/type/pdf-editor.blade.php` - `resources/views/components/modals/joint-widget-modal.blade.php` --- ### Phase 3: API Development & Database Integration (Week 2) #### 3.1 API Endpoints for Joint Data **Goal:** Create RESTful API endpoints for joint operations **Tasks:** - [ ] Create `saveJointData` endpoint (already exists, enhance) - [ ] Create `getJointData` endpoint - [ ] Create `checkExistingWeldmapData` endpoint (already exists) - [ ] Create `getQualifiedWelders` endpoint - [ ] Create `getICLogMembers` endpoint (already exists) - [ ] Create `getICLogMemberDetails` endpoint (already exists) **Best Practices:** - Use Laravel Resource classes for consistent responses - Implement proper validation rules - Add error handling and logging - Use database transactions for data integrity - Implement rate limiting for API calls **Files to Create/Modify:** - `app/Http/Controllers/Api/AnnotationController.php` (enhance existing) - `app/Http/Controllers/Api/PdfEditorLookupController.php` (enhance existing) - `routes/web.php` (add routes if needed) #### 3.2 Base Weldmap Integration **Goal:** Insert/update joint data in Base Weldmap **Tasks:** - [ ] Map widget form data to weld_logs table structure - [ ] Implement insert logic for new joints - [ ] Implement update logic for existing joints - [ ] Handle field mapping (widget → database) - [ ] Add validation for required fields - [ ] Implement batch insert for multiple joints **Database Mapping:** ``` Widget Field → weld_logs Column - joint_no → no_of_the_joint_as_per_as_built_survey - type_of_joint → type_of_joint (F/S) - welding_date → welding_date - spool_no1 → spool_number_1 - spool_no2 → spool_number_2 - pose_no1 → pose_number_1 - pose_no2 → pose_number_2 - member1 → member_1 - member2 → member_2 - material → material_1, material_2 - dia1 → dia_1 - dia2 → dia_2 - nps1 → nps_1 - nps2 → nps_2 - thickness1 → thickness_1 - thickness2 → thickness_2 - welder_id1 → welder_1 - welder_id2 → welder_2 ``` **Best Practices:** - Use Eloquent models for database operations - Implement database transactions - Add rollback on error - Use bulk insert for performance - Validate data before database operations **Files to Modify:** - `app/Http/Controllers/Api/AnnotationController.php` - `app/Models/WeldLog.php` (if needed) #### 3.3 Weldlog Integration **Goal:** Update welder assignments in Weldlog **Tasks:** - [ ] Implement welder assignment update logic - [ ] Handle real_welder_1 and real_welder_2 fields - [ ] Update joint display on PDF after assignment - [ ] Validate welder qualifications before assignment **Best Practices:** - Use updateOrCreate for idempotent operations - Implement soft validation (warnings, not errors) - Add audit trail for welder changes - Use database transactions **Files to Modify:** - `app/Http/Controllers/Api/AnnotationController.php` - `app/Models/WeldLog.php` --- ### Phase 4: Two-Way Data Synchronization (Week 2-3) #### 4.1 Data Existence Check **Goal:** Check if Base Weldmap/Welder data exists but drawing is missing **Tasks:** - [ ] Create API endpoint to check data existence - [ ] Implement left panel activation logic - [ ] Create Spool No dropdown population - [ ] Create Joint No dropdown (filtered by Spool) - [ ] Create Welder ID dropdown (filtered by Joint) **API Endpoint:** ```php GET /api/pdf-editor/check-existing-weldmap Query: drawing_number Response: { has_data: true/false, spools: [...], joints: [...], welders: [...] } ``` **Best Practices:** - Cache API responses for performance - Implement pagination for large datasets - Use eager loading for relationships - Add loading states in UI **Files to Create/Modify:** - `app/Http/Controllers/Api/PdfEditorLookupController.php` - `resources/views/admin/type/pdf-editor.blade.php` (left panel) #### 4.2 Drawing Generation from Data **Goal:** Generate PDF drawing shapes from existing database data **Tasks:** - [ ] Implement shape creation from joint data - [ ] Position shapes based on joint relationships - [ ] Add welder labels if welder data exists - [ ] Handle F/S shape selection - [ ] Update annotation storage **Best Practices:** - Use Fabric.js for shape creation - Implement smart positioning algorithm - Add collision detection - Use canvas grouping for related shapes **Files to Modify:** - `resources/views/admin/type/pdf-editor.blade.php` --- ### Phase 5: Document Revision Integration (Week 3) #### 5.1 Save to Spool Iso **Goal:** Save annotated PDF to Document Revision "Spool Iso" **Tasks:** - [ ] Implement PDF export with annotations - [ ] Save to Document Revision pdf_spool_iso column - [ ] Update revision metadata - [ ] Handle versioning **Best Practices:** - Use existing PDF export functionality - Implement async save operation - Add progress indicator - Handle save errors gracefully **Files to Modify:** - `app/Http/Controllers/Api/AnnotationController.php` - `app/Http/Controllers/Api/PdfEditorLookupController.php` (updateDocumentStage) #### 5.2 Save to As-Build **Goal:** Save annotated PDF to Document Revision "As-Build" **Tasks:** - [ ] Similar to Spool Iso but for pdf_as_build column - [ ] Include welder information in saved PDF - [ ] Update revision metadata **Files to Modify:** - Same as 5.1 --- ### Phase 6: Welder Qualification Filtering (Week 3) #### 6.1 Welder Qualification System **Goal:** Filter welders based on qualifications and validity **Tasks:** - [ ] Integrate with existing Welder Assignment system - [ ] Implement qualification filtering logic - [ ] Check welder expiry dates - [ ] Filter by material compatibility - [ ] Filter by welding method **Best Practices:** - Reuse existing welder assignment logic - Cache qualification data - Implement client-side filtering for performance - Add server-side validation **Files to Modify:** - `app/Http/Controllers/Api/PdfEditorLookupController.php` - `app/Http/Controllers/AutoCompleteType/welder-assignment/welder_1.php` (reference) --- ## 🔧 Technical Architecture ### Frontend Architecture ``` PDF Editor Canvas (Fabric.js) ↓ Shape Event Handlers ↓ Joint Data Manager (Temporary Storage) ↓ Widget Modal (Form) ↓ API Calls (AJAX) ↓ Backend Controllers ↓ Database (weld_logs, annotations, document_revisions) ``` ### Data Flow **Scenario 1: New Joint Creation** ``` User draws shape → Widget opens → User fills form → Data stored in memory → User clicks Save → Batch insert to weld_logs → Save PDF to Document Revision ``` **Scenario 2: Welder Assignment** ``` User hovers joint → Widget opens (pre-filled) → User selects welders → Update memory → User clicks Save → Update weld_logs → Update PDF display → Save PDF to Document Revision ``` **Scenario 3: Drawing from Data** ``` Check data exists → Activate left panel → User selects Spool → Joints list → User selects Joint + Shape → Create shape on PDF → Save PDF to Document Revision ``` --- ## 📚 Best Practices & Recommendations ### 1. Temporary Data Storage **Option A: In-Memory (Recommended)** - Use JavaScript Map/Object for fast access - Store in component state - Clear on page unload - **Pros:** Fast, no persistence needed - **Cons:** Lost on page refresh **Option B: SessionStorage** - Use browser sessionStorage API - Survives page refresh - Auto-clears on tab close - **Pros:** Persistence - **Cons:** Limited size, string serialization **Recommendation:** Use in-memory storage with sessionStorage backup ```javascript class JointDataManager { constructor() { this.data = new Map(); this.loadFromSession(); } save(shapeId, jointData) { this.data.set(shapeId, jointData); this.saveToSession(); } saveToSession() { const data = Object.fromEntries(this.data); sessionStorage.setItem('jointData', JSON.stringify(data)); } loadFromSession() { const stored = sessionStorage.getItem('jointData'); if (stored) { const data = JSON.parse(stored); this.data = new Map(Object.entries(data)); } } } ``` ### 2. Widget Positioning **Option A: Fixed Position (Current)** - Modal in center of screen - **Pros:** Simple, consistent - **Cons:** May cover important content **Option B: Dynamic Positioning (Recommended)** - Position near clicked shape - Calculate based on shape coordinates - **Pros:** Better UX, doesn't cover content - **Cons:** More complex **Recommendation:** Use dynamic positioning with fallback to center ```javascript function calculateWidgetPosition(shape, canvas) { const shapeBounds = shape.getBoundingRect(); const canvasOffset = canvas.getElement().getBoundingClientRect(); const x = canvasOffset.left + shapeBounds.left + shapeBounds.width; const y = canvasOffset.top + shapeBounds.top; // Check if fits on screen const windowWidth = window.innerWidth; const windowHeight = window.innerHeight; const widgetWidth = 600; // Modal width const widgetHeight = 500; // Estimated modal height let finalX = x; let finalY = y; if (x + widgetWidth > windowWidth) { finalX = x - widgetWidth - 20; // Position to left } if (y + widgetHeight > windowHeight) { finalY = windowHeight - widgetHeight - 20; } return { x: finalX, y: finalY }; } ``` ### 3. API Design **RESTful Endpoints:** ``` POST /api/pdf-editor/joint-data - Save joint data GET /api/pdf-editor/joint-data/{id} - Get joint data PUT /api/pdf-editor/joint-data/{id} - Update joint data DELETE /api/pdf-editor/joint-data/{id} - Delete joint data GET /api/pdf-editor/qualified-welders - Get qualified welders GET /api/pdf-editor/check-weldmap - Check existing weldmap data ``` **Request/Response Format:** ```json // POST /api/pdf-editor/joint-data { "drawing_number": "CW-800-AH01JL-FA00.001", "joints": [ { "shape_id": "J-001", "joint_no": "53A", "type_of_joint": "F", "welding_date": "2025-01-15", "spool_no1": "SP01", "spool_no2": "SP02", // ... other fields } ] } // Response { "success": true, "message": "Joint data saved successfully", "data": { "saved_count": 1, "joints": [...] } } ``` ### 4. Database Transactions **Best Practice:** Use database transactions for data integrity ```php public function saveJointData(Request $request): JsonResponse { DB::beginTransaction(); try { foreach ($request->joints as $jointData) { WeldLog::updateOrCreate( [ 'iso_number' => $request->drawing_number, 'no_of_the_joint_as_per_as_built_survey' => $jointData['joint_no'], ], [ // ... field mappings ] ); } DB::commit(); return response()->json(['success' => true]); } catch (\Exception $e) { DB::rollBack(); Log::error('Failed to save joint data', ['error' => $e->getMessage()]); return response()->json(['success' => false, 'message' => $e->getMessage()], 500); } } ``` ### 5. Welder Qualification Filtering **Integration with Existing System:** - Reuse `welder_1.php` autocomplete logic - Filter by material compatibility (MaterialGroupMap) - Filter by welding method - Check expiry dates - Filter by qualification status **Implementation:** ```php public function getQualifiedWelders(Request $request): JsonResponse { $request->validate([ 'material_1' => 'required|string', 'material_2' => 'required|string', 'welding_method' => 'required|string', 'joint_type' => 'nullable|string', ]); // Use existing welder assignment logic $qualifiedWelders = $this->filterQualifiedWelders( $request->material_1, $request->material_2, $request->welding_method ); return response()->json([ 'success' => true, 'data' => $qualifiedWelders ]); } ``` ### 6. Performance Optimization **Client-Side:** - Debounce API calls (300ms) - Cache API responses - Use virtual scrolling for large lists - Lazy load widget modal - Use requestAnimationFrame for animations **Server-Side:** - Use database indexes - Implement query caching - Use eager loading for relationships - Implement pagination - Use database transactions efficiently ### 7. Error Handling **Client-Side:** ```javascript async function saveJointData(jointData) { try { const response = await fetch('/api/pdf-editor/joint-data', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken }, body: JSON.stringify(jointData) }); const result = await response.json(); if (!result.success) { throw new Error(result.message || 'Failed to save joint data'); } return result; } catch (error) { console.error('Error saving joint data:', error); Swal.fire('Error', error.message, 'error'); throw error; } } ``` **Server-Side:** ```php try { // ... operation } catch (ValidationException $e) { return response()->json([ 'success' => false, 'message' => 'Validation failed', 'errors' => $e->errors() ], 422); } catch (\Exception $e) { Log::error('Joint data save failed', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return response()->json([ 'success' => false, 'message' => 'An error occurred while saving joint data' ], 500); } ``` --- ## 🧪 Testing Strategy ### Unit Tests - JointDataManager class methods - API endpoint validation - Database operations - Data mapping functions ### Integration Tests - Widget open/close flow - Data save/load cycle - API endpoint integration - Database transaction rollback ### E2E Tests - Complete joint creation flow - Welder assignment flow - Drawing generation from data - Document Revision save --- ## 📝 Implementation Checklist ### Phase 1: Foundation - [ ] Create JointDataManager class - [ ] Enhance joint widget modal - [ ] Add IC Log member selection - [ ] Implement auto-fill logic ### Phase 2: Integration - [ ] Add shape click handlers - [ ] Implement widget positioning - [ ] Connect widget to data manager - [ ] Update shape labels ### Phase 3: Backend - [ ] Enhance saveJointData endpoint - [ ] Create getQualifiedWelders endpoint - [ ] Implement Base Weldmap integration - [ ] Implement Weldlog integration ### Phase 4: Two-Way Sync - [ ] Create check-existing-weldmap endpoint - [ ] Implement left panel activation - [ ] Create drawing from data - [ ] Handle welder display ### Phase 5: Document Revision - [ ] Implement Spool Iso save - [ ] Implement As-Build save - [ ] Add versioning support ### Phase 6: Welder Filtering - [ ] Integrate qualification system - [ ] Implement material filtering - [ ] Add expiry date checking --- ## 🚀 Next Steps 1. **Review and approve roadmap** 2. **Set up development branch:** `feature/pdf-editor-step3-joint-widget` 3. **Start with Phase 1:** Foundation & Data Structure 4. **Iterative development:** Test each phase before moving to next 5. **Code review:** After each phase completion --- ## 📖 References - Existing Code: - `app/Http/Controllers/Api/AnnotationController.php` - `app/Http/Controllers/Api/PdfEditorLookupController.php` - `resources/views/components/modals/joint-widget-modal.blade.php` - `app/Http/Controllers/AutoCompleteType/welder-assignment/welder_1.php` - Database Tables: - `weld_logs` - Main joint and welder data - `annotations` - PDF shape data - `document_revisions` - PDF file storage - `incoming_control` - IC Log member data - `material_group_map` - Material compatibility - `welder_tests` - Welder qualifications --- **Document Version:** 1.0 **Last Updated:** 2025-01-XX **Author:** Development Team