๐ฏ System Overview & Requirements
๐ Business Requirements Analysis
The LEONI Quality Management System (QMS) is designed to streamline quality control processes in automotive wire harness manufacturing. The system addresses critical business needs:
๐ Defect Management
Real-time defect tracking and reporting with automated severity assessment and escalation workflows.
๐ QRQC Analysis
Quick Response Quality Control with structured root cause analysis, corrective actions, and verification tracking.
๐ Audit Systems
5S and AFP audit management with automated scoring, action plans, and progress tracking.
๐ KPI Monitoring
Real-time production quality metrics with dashboard visualization and trend analysis.
๐จ Design Philosophy
User-Driven Architecture
The system is designed around actual user workflows rather than abstract service layers. AQL agents directly record defects, quality technicians perform QRQC analysis, and team leaders track implementation - no unnecessary intermediary services.
Hybrid Data Strategy
Critical queryable data is stored in structured columns for performance, while evolving form data uses JSONB for flexibility. This approach eliminates the need for schema migrations when forms change.
Scalable JSONB Architecture
The Analysis table uses a consolidated approach with only 7 columns: 4 structured columns (id, analysis_date, defect_id, production_line_id, inspector_id), 1 comprehensive JSONB column (qrqc_form) containing all 10 form sections as nested data, and 2 system columns (is_archived, created_at). This consolidation enables perfect archival where each analysis record contains complete form data as a single atomic unit.
๐๏ธ Database Design Strategy
๐ Entity Relationship Design
erDiagram
USERS {
int id PK
string username
string email
string role
boolean is_active
datetime created_at
}
ANALYSIS {
int id PK
date analysis_date
int defect_id FK
int production_line_id FK
int inspector_id FK
jsonb qrqc_form
boolean is_archived
datetime created_at
}
DEFECTS {
int id PK
int production_line_id FK
int project_id FK
string description
string status
datetime created_at
}
PRODUCTION_LINES {
int id PK
string name
string code
boolean is_active
}
AUDIT_5S {
int id PK
int line_id FK
int auditor_id FK
date audit_date
jsonb audit_data
int total_score
}
KPI {
int id PK
int line_id FK
date metric_date
decimal fpy
decimal defect_rate
}
VALUES {
int id PK
int production_line_id FK
int entered_by FK
string shift
date date
jsonb quality_data
text notes
string status
datetime created_at
datetime updated_at
}
USERS ||--o{ ANALYSIS : creates
DEFECTS ||--o{ ANALYSIS : analyzes
PRODUCTION_LINES ||--o{ DEFECTS : occurs_on
PRODUCTION_LINES ||--o{ ANALYSIS : performed_on
USERS ||--o{ AUDIT_5S : conducts
PRODUCTION_LINES ||--o{ KPI : measures
PRODUCTION_LINES ||--o{ VALUES : measures_quality
USERS ||--o{ VALUES : enters
๐ฏ Hybrid Storage Strategy
Structured Columns for Performance
-- Key queryable fields as structured columns
analysis_date DATE NOT NULL,
defect_id INTEGER REFERENCES defects(id),
production_line_id INTEGER REFERENCES production_lines(id),
inspector_id INTEGER REFERENCES users(id)
Consolidated QRQC Form Structure
-- Single consolidated JSONB column for all form data
qrqc_form JSONB NOT NULL DEFAULT '{}' CHECK (
jsonb_typeof(qrqc_form) = 'object'
),
-- Contains all 10 sections as nested structure:
-- document_info, caracterisation, personnel_notification,
-- tri_data, pre_analyse, actions_securisation,
-- analysis_data, corrective_actions, verification_tracking, metadata
is_archived BOOLEAN DEFAULT FALSE
VALUES Table - Quality Metrics JSONB Structure
-- Quality metrics with flexible JSONB storage
quality_data JSONB NOT NULL DEFAULT '{
"scrap": {
"total_scrap": 0,
"total_production": 0,
"rate": 0.0
},
"rework": {
"total_rework": 0,
"total_production": 0,
"rate": 0.0
},
"defects": {
"total_defects": 0,
"total_production": 0,
"rate_ppm": 0.0
}
}'
-- Enables scalable quality metrics entry with automatic calculations
-- AQL agents enter raw data, system calculates rates via triggers
๐ Performance Optimization
๐ Consolidated GIN Indexing
Comprehensive GIN indexes on JSONB columns for both ANALYSIS qrqc_form and VALUES quality_data, plus specific path indexes for frequently accessed form sections and quality metrics.
๐ฏ Optimized Path Indexes
Targeted JSONB path indexes for common query patterns like metadata status, TRI decisions, and actions tracking.
โก Atomic Operations
Consolidated structure enables atomic QRQC form updates and perfect archival with complete form reconstruction from single column.
๐พ Connection Pooling
Database connection pooling for optimal resource utilization and scalability.
-- Consolidated indexing strategy for optimized performance
-- ANALYSIS table indexes
CREATE INDEX idx_analysis_date ON analysis(analysis_date);
CREATE INDEX idx_qrqc_form_gin ON analysis USING GIN (qrqc_form);
CREATE INDEX idx_qrqc_status ON analysis USING GIN ((qrqc_form->'metadata'->>'status'));
CREATE INDEX idx_qrqc_tri_decision ON analysis USING GIN ((qrqc_form->'tri_data'->>'decisionRetouche'));
CREATE INDEX idx_qrqc_actions_status ON analysis USING GIN ((qrqc_form->'actions_securisation'->>'overall_status'));
-- VALUES table JSONB indexes
CREATE INDEX idx_values_quality_data ON values USING GIN (quality_data);
CREATE INDEX idx_values_scrap_rate ON values USING BTREE ((quality_data->'scrap'->'rate')::DECIMAL);
CREATE INDEX idx_values_rework_rate ON values USING BTREE ((quality_data->'rework'->'rate')::DECIMAL);
CREATE INDEX idx_values_defect_rate_ppm ON values USING BTREE ((quality_data->'defects'->'rate_ppm')::DECIMAL);
๐ API Design & Architecture
๐ RESTful API Design
graph TB
subgraph "๐ Authentication"
A1[POST /api/auth/login]
A2[POST /api/auth/logout]
A3[GET /api/auth/profile]
end
subgraph "๐ง Defect Management"
B1[GET /api/defects]
B2[POST /api/defects]
B3[PUT /api/defects/:id]
B4[DELETE /api/defects/:id]
end
subgraph "๐ QRQC Analysis"
C1[GET /api/analysis]
C2[POST /api/analysis]
C3[PUT /api/analysis/:id/section]
C4[GET /api/analysis/:id/report]
end
subgraph "๐ Audit Systems"
D1[GET /api/audits/5s]
D2[POST /api/audits/5s]
D3[GET /api/audits/afp]
D4[POST /api/audits/afp]
end
subgraph "๐ KPI & Reports"
E1[GET /api/kpi/dashboard]
E2[GET /api/reports/export]
E3[GET /api/analytics/trends]
end
subgraph "๐ Quality Metrics"
F1[GET /api/values]
F2[POST /api/values/quality-metrics]
F3[PUT /api/values/:id]
F4[GET /api/values/production-line/:id/current]
F5[GET /api/values/trends]
end
๐ Consolidated QRQC Form Updates
// QRQC Analysis - Update Consolidated Form Section
PUT /api/analysis/:id/form
{
"section": "tri_data",
"data": {
"magasinProduitFini": {"bon": 15, "mauvais": 2},
"paletteFinLigne": {"bon": 12, "mauvais": 5},
"totals": {"totalBon": 27, "totalMauvais": 7},
"decisionRetouche": false
}
}
// Updates: UPDATE analysis SET qrqc_form = jsonb_set(qrqc_form, '{tri_data}', $1)
// QRQC Analysis - Update Pre-Analyse Section
PUT /api/analysis/:id/form
{
"section": "pre_analyse",
"data": {
"operatorId": "OP123",
"postMachine": "Station 5 - Assembly Line",
"defectDate": "2025-06-18",
"defectHour": "14:30"
}
}
// QRQC Analysis - Complete Form Retrieval (Perfect for Archives)
GET /api/analysis/:id
Response: {
"id": 123,
"analysis_date": "2025-06-18",
"defect_id": 456,
"production_line_id": 1,
"inspector_id": 789,
"qrqc_form": {
"document_info": { "qrqc_reference_id": "DEF-1703123456789" },
"caracterisation": { "defect_description": "Detailed description" },
"personnel_notification": { "informed_personnel": ["operateur", "team-speaker"] },
"tri_data": { "totals": {"totalBon": 27, "totalMauvais": 7} },
"pre_analyse": { "operatorId": "OP123" },
"actions_securisation": { "action1": {"responsable": "Quality Supervisor"} },
"analysis_data": { "why1": {"field1": "Root cause analysis"} },
"corrective_actions": { "occurrence": {"pilote": "Production Manager"} },
"verification_tracking": { "teams": [{"team": "Team 1", "occurrence": "No"}] },
"metadata": { "status": "OPEN", "priority": "MEDIUM" }
},
"is_archived": false,
"created_at": "2025-06-18T10:30:00Z"
}
"responsable": "Maintenance Team",
"date": "2025-06-25",
"status": "PLANNED"
}
}
}
// Response
{
"success": true,
"message": "Section updated successfully",
"analysisId": 123,
"section": "actions_securisation",
"autoCalculated": {
"overall_status": "PLANNED",
"next_due_date": "2025-06-20"
}
}
๐ Quality Metrics API (VALUES Table)
// Quality Metrics Entry - JSONB Structure
POST /api/values/quality-metrics
{
"production_line_id": 1,
"shift": "Morning",
"date": "2025-06-18",
"quality_data": {
"scrap": {
"total_scrap": 15,
"total_production": 1000
},
"rework": {
"total_rework": 8,
"total_production": 1000
},
"defects": {
"total_defects": 3,
"total_production": 1000
}
},
"notes": "Morning shift quality metrics"
}
// Database Operation: INSERT INTO values with automatic rate calculation
// Trigger calculates: scrap_rate=1.5%, rework_rate=0.8%, defect_rate_ppm=3000
// Get Current Quality Metrics for Production Line
GET /api/values/production-line/1/current
Response: {
"success": true,
"data": {
"id": 123,
"production_line_id": 1,
"shift": "Morning",
"date": "2025-06-18",
"quality_data": {
"scrap": {"total_scrap": 15, "total_production": 1000, "rate": 1.5},
"rework": {"total_rework": 8, "total_production": 1000, "rate": 0.8},
"defects": {"total_defects": 3, "total_production": 1000, "rate_ppm": 3000.0}
},
"notes": "Morning shift quality metrics"
}
}
// Quality Trends Analysis
GET /api/values/trends?production_line_id=1&days=7
Response: {
"success": true,
"data": {
"scrap_trend": [1.2, 1.5, 1.3, 1.8, 1.4, 1.6, 1.5],
"rework_trend": [0.8, 0.9, 0.7, 1.1, 0.8, 0.9, 0.8],
"defect_ppm_trend": [2500, 3000, 2800, 3200, 2900, 3100, 3000],
"trend_analysis": {
"scrap_direction": "stable",
"rework_direction": "stable",
"defects_direction": "increasing"
}
}
}
๐ API Response Strategy
๐ Consistent Response Format
Standardized JSON response structure with success/error states, data payload, and metadata.
๐ Security Headers
CORS, CSRF protection, rate limiting, and authentication tokens for secure API access.
๐ Performance Monitoring
API response time monitoring, error tracking, and usage analytics for optimization.
๐ Documentation
Comprehensive API documentation with examples, schemas, and interactive testing.
๐งฉ Design Patterns & Best Practices
๐๏ธ Architectural Patterns
๐ฆ Repository Pattern
class AnalysisRepository {
async create(analysisData) {
const query = `
INSERT INTO analysis (
analysis_date, defect_id, production_line_id,
inspector_id, qrqc_form, is_archived
) VALUES ($1, $2, $3, $4, $5, $6)
RETURNING *
`;
return await this.db.query(query, [
analysisData.date,
analysisData.defectId,
analysisData.productionLineId,
analysisData.inspectorId,
JSON.stringify(analysisData.qrqcForm), // Consolidated form data
false
]);
}
async updateFormSection(id, section, data) {
const query = `
UPDATE analysis
SET qrqc_form = jsonb_set(qrqc_form, $2, $3)
WHERE id = $1
RETURNING *
`;
return await this.db.query(query, [
id,
`{${section}}`,
JSON.stringify(data)
]);
}
async getCompleteForm(id) {
const query = `
SELECT id, analysis_date, defect_id, production_line_id,
inspector_id, qrqc_form, is_archived, created_at
FROM analysis
WHERE id = $1
`;
return await this.db.query(query, [id]);
}
}
๐ญ Factory Pattern for Validation
class QRQCValidatorFactory {
static createValidator(section) {
const validators = {
'document_info': DocumentInfoValidator,
'caracterisation': CaracterisationValidator,
'tri_data': TriDataValidator,
'analysis_data': AnalysisDataValidator,
'corrective_actions': CorrectiveActionValidator,
'verification_tracking': VerificationValidator,
'metadata': MetadataValidator
};
const ValidatorClass = validators[section];
if (!ValidatorClass) {
throw new Error(`Unknown section: ${section}`);
}
return new ValidatorClass();
}
}
class TriDataValidator {
validate(data) {
const required = ['magasinProduitFini', 'paletteFinLigne', 'ligneAssemblage'];
const errors = [];
for (const stage of required) {
if (!data[stage] || typeof data[stage] !== 'object') {
errors.push(`Missing or invalid ${stage} data`);
}
}
return { isValid: errors.length === 0, errors };
}
}
๐ Data Flow Patterns
graph LR
A[๐ QRQC Form] --> B[โ
Validation Layer]
B --> C[๐ง Business Logic]
C --> D[๐ Data Transform]
D --> E[๐๏ธ Database Layer]
E --> F[(PostgreSQL)]
C --> G[๐ JSONB Processor]
G --> H[๐ GIN Indexing]
H --> F
F --> I[โก Query Optimizer]
I --> J[๐ Dashboard APIs]
J --> K[๐ฑ Frontend Views]
style A fill:#e1f5fe
style F fill:#f3e5f5
style K fill:#e8f5e8
๐ก๏ธ Error Handling Patterns
class ErrorHandler {
static async handleDatabaseError(error, context) {
const errorMap = {
'23505': 'Duplicate entry detected',
'23503': 'Referenced record not found',
'23514': 'Data validation failed',
'42P01': 'Table does not exist'
};
const message = errorMap[error.code] || 'Database operation failed';
logger.error('Database Error', {
code: error.code,
message: error.message,
context: context,
timestamp: new Date().toISOString()
});
return {
success: false,
error: message,
code: error.code,
timestamp: new Date().toISOString()
};
}
}
๐ Security Architecture
๐ก๏ธ Role-Based Access Control (RBAC)
graph TB
subgraph "๐ฅ User Roles"
A[๐ค AQL Agent]
B[๐ง Quality Technician]
C[๐จโ๐ผ Team Leader]
D[๐ฉโ๐ผ Quality Manager]
end
subgraph "๐ Permissions"
E[๐ Can Add Defects]
F[๐ Can View QRQC]
G[๐ Can Create QRQC]
H[โ๏ธ Can Edit QRQC]
I[๐ Can Perform Audits]
J[๐ฅ Can Manage Staff]
K[โ๏ธ Can System Admin]
end
A --> E
A --> F
B --> E
B --> F
B --> G
B --> H
B --> I
C --> E
C --> F
C --> G
C --> H
C --> I
C --> J
D --> E
D --> F
D --> G
D --> H
D --> I
D --> J
D --> K
๐ Authentication & Authorization
-- Automated permission management
CREATE OR REPLACE FUNCTION update_user_permissions()
RETURNS TRIGGER AS $$
BEGIN
DELETE FROM user_permissions WHERE user_id = NEW.id;
CASE NEW.role
WHEN 'AQL_AGENT' THEN
INSERT INTO user_permissions (user_id, can_add_defect, can_view_qrqc)
VALUES (NEW.id, TRUE, TRUE);
WHEN 'QUALITY_TECHNICIAN' THEN
INSERT INTO user_permissions (user_id, can_add_defect, can_view_qrqc,
can_add_qrqc, can_edit_qrqc, can_perform_5s_audit)
VALUES (NEW.id, TRUE, TRUE, TRUE, TRUE, TRUE);
WHEN 'QUALITY_MANAGER' THEN
-- Full permissions for quality manager
INSERT INTO user_permissions (user_id, can_system_admin, can_user_management)
VALUES (NEW.id, TRUE, TRUE);
END CASE;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
๐ก๏ธ Security Measures
๐ Data Encryption
Password hashing with bcrypt, HTTPS/TLS encryption, and secure session management with signed tokens.
๐ซ Input Validation
Server-side validation, SQL injection prevention, XSS protection, and CSRF token validation.
๐ Audit Trail
Comprehensive logging of user actions, data changes, and system events for security monitoring.
โฐ Session Management
Secure session tokens, automatic session expiry, and concurrent session monitoring.
๐ Deployment & Infrastructure
๐๏ธ Deployment Architecture
graph TB
subgraph "๐ Load Balancer"
A[Nginx/HAProxy]
end
subgraph "๐ฅ๏ธ Application Servers"
B1[App Server 1]
B2[App Server 2]
B3[App Server N]
end
subgraph "๐๏ธ Database Cluster"
C1[(PostgreSQL Primary)]
C2[(PostgreSQL Replica)]
end
subgraph "๐พ Cache Layer"
D1[Redis Primary]
D2[Redis Replica]
end
subgraph "๐ Storage"
E[File Storage]
F[Backup Storage]
end
A --> B1
A --> B2
A --> B3
B1 --> C1
B2 --> C1
B3 --> C1
C1 --> C2
B1 --> D1
B2 --> D1
B3 --> D1
D1 --> D2
B1 --> E
B2 --> E
B3 --> E
C1 --> F
๐ CI/CD Pipeline
๐ง
Development
Git, VS Code, Local PostgreSQL, Hot Reload
๐งช
Testing
Jest, Supertest, Database Fixtures, Automated Testing
๐๏ธ
Build
GitHub Actions, Docker, Asset Optimization
๐
Deploy
Docker Compose, Environment Config, Health Checks
๐ Monitoring & Observability
// Application Health Check
app.get('/health', async (req, res) => {
const health = {
status: 'OK',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
environment: process.env.NODE_ENV,
version: process.env.APP_VERSION,
checks: {
database: await checkDatabase(),
redis: await checkRedis(),
diskSpace: await checkDiskSpace(),
memory: process.memoryUsage()
}
};
const hasFailures = Object.values(health.checks)
.some(check => check.status === 'ERROR');
res.status(hasFailures ? 503 : 200).json(health);
});
// Performance Monitoring
const performanceMonitor = {
trackApiResponse: (req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`${req.method} ${req.path} - ${res.statusCode} - ${duration}ms`);
// Send metrics to monitoring service
metrics.timing('api.response_time', duration, {
method: req.method,
path: req.path,
status: res.statusCode
});
});
next();
}
};