Database Schema & Software Architecture Audit
Audit van het database schema en software-architectuur voor het Fire Management System (Wildfire) project.
Audit Status
✅ PASSED (Met voorbehoud - Hakken over de sloot)
Score: 0/0 (Geen kritieke punten) Date: January 14, 2026
1. Vereisten Verificatie
1.1 Databank Systeem
✅ VOLDAAN
- Systeem: MariaDB (relationeel databanksysteem)
- Versie: MariaDB 10.5+
- Karakteristieken: ACID-compliant, relationeel, ondersteuning voor geografische gegevens
1.2 Web API Architecture
✅ VOLDAAN
- Type: REST API
- Framework: Node.js + Express
- Standard: RESTful principles met POST/GET/PUT/DELETE
- Documentatie: OpenAPI/Swagger-gebaseerd
1.3 Software Architecture Schema
✅ VOLDAAN - Uitgewerkt en compleet
┌─────────────────────────────────────────────────────┐
│ FRONTEND (Client) │
│ - Vue 3 + Nuxt.js │
│ - AdminPortal & UserDashboard │
│ - Responsive UI, TypeScript │
└──────────────────┬──────────────────────────────────┘
│ (REST API calls)
┌──────────────────▼──────────────────────────────────┐
│ BACKEND (API Server) │
│ - Node.js + Express │
│ - REST API endpoints │
│ - Business logic & validation │
│ - Authentication & Authorization │
└──────────────────┬──────────────────────────────────┘
│ (SQL queries)
┌──────────────────▼──────────────────────────────────┐
│ DATABASE (Data Layer) │
│ - MariaDB (Relational) │
│ - Normalized schema │
│ - Geographic data support │
└──────────────────┬──────────────────────────────────┘
│
┌──────────────────▼──────────────────────────────────┐
│ EXTERNAL API Integration │
│ - Weather Underground API │
│ - Real-time weather data │
│ - Temperature, humidity, wind data │
└─────────────────────────────────────────────────────┘2. Technologie Keuzes & Motivatie
Frontend: Vue 3 + Nuxt.js
Motivatie:
- ✅ Modern framework met sterke type support (TypeScript)
- ✅ Server-side rendering voor betere SEO
- ✅ Auto-routing en code splitting
- ✅ Groot ecosystem van libraries
- ✅ Actieve community en goed ondersteund
Backend: Node.js + Express
Motivatie:
- ✅ JavaScript throughout (full-stack development)
- ✅ Asynchrone processing voor real-time data
- ✅ Lightweight & performant
- ✅ Npm ecosystem met nodige packages
- ✅ Geschikt voor API-first architectuur
Database: MariaDB
Motivatie:
- ✅ Relationeel systeem voor structured data
- ✅ ACID compliance voor data integriteit
- ✅ Geografische extensies beschikbaar
- ✅ Open-source & kosteneffectief
- ✅ Goed voor normalized schemas
External API: Weather Underground
Motivatie:
- ✅ Real-time weather data nodig voor fire risk assessment
- ✅ Betere nauwkeurigheid dan lokale metingen
- ✅ Coverage van groot geografisch gebied
- ✅ Stabiele API met goed uptime
3. Data & Logic Distribution
Backend Logic
Volgende logica bevindt zich in de backend:
🔵 User Authentication & Authorization
- Login/logout, JWT tokens
- Role-based access control
🔵 Data Validation
- Input validation op alle endpoints
- Business rule enforcement
🔵 Business Logic
- Fire risk calculation
- Alert generation
- Data aggregation & reporting
🔵 External API Integration
- Weather data fetching
- Data transformation & storage
🔵 Database Operations
- CRUD operations
- Complex queries & joins
Frontend Logic
Volgende logica bevindt zich in de frontend:
🟠 Presentation Logic
- UI rendering & components
- Form handling & validation
🟠 User Interaction
- Navigation, filtering, searching
- Real-time updates via WebSockets
🟠 State Management
- Pinia store (global state)
- Component-level state
🟠 Data Visualization
- Maps (Leaflet/Mapbox)
- Charts & graphs
API Data Contract
De Web API stelt volgende data ter beschikking:
// User endpoint
GET /api/users/:id
{
"id": "user_123",
"email": "user@example.com",
"role": "viewer",
"permissions": ["view_perimeter", "view_incidents"]
}
// Perimeter endpoint
GET /api/perimeters/:id
{
"id": "perim_001",
"name": "Northern Forest Zone",
"area_size": 15000.5,
"polygon": "POLYGON(...)",
"risk_level": "high",
"last_incident": "2025-12-15"
}
// Incident endpoint
GET /api/incidents?perimeter_id=perim_001
{
"id": "incident_2025_001",
"perimeter_id": "perim_001",
"start_date": "2025-01-14T10:30:00Z",
"location_id": "loc_123",
"fire_type": "crown_fire",
"temperature": 28.5,
"humidity": 45,
"wind_speed": 12.3
}4. Database Schema
4.1 Naming Convention
✅ GESPECIFICEERD & TOEGEPAST
Convention: Volledig Engels, lowercase, geen afkappingstekens, enkelvoudige namen voor FK-kolommen
Voorbeelden:
- ✅
perimeter_id(singular, notperimeters_id) - ✅
location_id(singular, notlocations_id) - ✅
created_at(lowercase, underscore) - ✅
temperature(nottemp)
4.2 Tabel Definities
users
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
role ENUM('admin', 'viewer', 'analyst') NOT NULL DEFAULT 'viewer',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);locations
CREATE TABLE locations (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
latitude DECIMAL(10, 8) NOT NULL,
longitude DECIMAL(11, 8) NOT NULL,
altitude INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);perimeters
CREATE TABLE perimeters (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
area_size DECIMAL(10, 2),
polygon_data LONGTEXT NOT NULL, -- GeoJSON or WKT format
risk_level ENUM('low', 'medium', 'high', 'critical') DEFAULT 'medium',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);incidents
CREATE TABLE incidents (
id INT AUTO_INCREMENT PRIMARY KEY,
perimeter_id INT NOT NULL,
location_id INT NOT NULL,
start_date TIMESTAMP NOT NULL,
end_date TIMESTAMP,
fire_type ENUM('ground_fire', 'surface_fire', 'crown_fire') NOT NULL,
area_burned DECIMAL(10, 2),
status ENUM('active', 'contained', 'extinguished') DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (perimeter_id) REFERENCES perimeters(id),
FOREIGN KEY (location_id) REFERENCES locations(id),
INDEX idx_perimeter_date (perimeter_id, start_date)
);weather_data
CREATE TABLE weather_data (
id INT AUTO_INCREMENT PRIMARY KEY,
location_id INT NOT NULL,
measurement_time TIMESTAMP NOT NULL,
temperature DECIMAL(5, 2), -- in Celsius
humidity INT, -- 0-100 percentage
wind_speed DECIMAL(5, 2), -- in m/s
wind_direction VARCHAR(10), -- N, NE, E, etc.
pressure DECIMAL(7, 2),
precipitation DECIMAL(5, 2),
source VARCHAR(100), -- 'weather_underground', 'local_sensor'
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (location_id) REFERENCES locations(id),
INDEX idx_location_time (location_id, measurement_time)
);alerts
CREATE TABLE alerts (
id INT AUTO_INCREMENT PRIMARY KEY,
perimeter_id INT NOT NULL,
incident_id INT,
alert_type ENUM('fire_detected', 'high_risk', 'weather_warning') NOT NULL,
severity ENUM('info', 'warning', 'critical') NOT NULL,
message TEXT NOT NULL,
is_resolved BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
resolved_at TIMESTAMP,
FOREIGN KEY (perimeter_id) REFERENCES perimeters(id),
FOREIGN KEY (incident_id) REFERENCES incidents(id),
INDEX idx_perimeter_severity (perimeter_id, severity)
);sensor_readings
CREATE TABLE sensor_readings (
id INT AUTO_INCREMENT PRIMARY KEY,
location_id INT NOT NULL,
reading_time TIMESTAMP NOT NULL,
temperature DECIMAL(5, 2),
humidity INT,
smoke_level INT, -- 0-100 scale
sensor_status ENUM('active', 'offline', 'error') DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (location_id) REFERENCES locations(id),
INDEX idx_location_time (location_id, reading_time)
);incident_images
CREATE TABLE incident_images (
id INT AUTO_INCREMENT PRIMARY KEY,
incident_id INT NOT NULL,
image_path VARCHAR(500) NOT NULL, -- Store path, not BLOB
image_hash VARCHAR(64) UNIQUE, -- SHA-256 hash for unique identification
uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (incident_id) REFERENCES incidents(id),
INDEX idx_incident (incident_id)
);5. Schema Evaluatie
5.1 Normalisatie
✅ 3NF Compliant
- ✅ Alle tabellen gegenormaliseerd
- ✅ Geen redundante data
- ✅ Foreign key relaties correct gedefinieerd
- ✅ Atomaire waarden in alle kolommen
5.2 Data Types - Opmerkingen van Docent
VARCHAR → ENUM/SPECIFIC TYPE
⚠️ Issue: Sommige kolommen gebruikten VARCHAR voor vaste waarden Oplossing: Gewijzigd naar ENUM waar van toepassing
Voorbeelden:
fire_type: ENUM('ground_fire', 'surface_fire', 'crown_fire') ✅status: ENUM('active', 'contained', 'extinguished') ✅alert_type: ENUM('fire_detected', 'high_risk', 'weather_warning') ✅
Decimale Waarden
⚠️ Opmerking: Temperature en slope moeten DECIMAL zijn voor precisie
Huiderplaat:
-- ✅ CORRECT
temperature DECIMAL(5, 2) -- range: -999.99 to 9999.99, 2 decimals
slope DECIMAL(5, 2) -- range: 0 to 100%, 2 decimals
-- ❌ FOUT
temperature FLOAT -- precision issues
slope INT -- loses decimal precisionPOLYGON Datatype
⚠️ Opmerking: Geografische data handling
Huderplaat Opties:
Met geografische support (AANBEVOLEN)
sqlALTER TABLE perimeters MODIFY COLUMN polygon GEOMETRY SRID 4326; -- WGS84 projection -- Enable spatial indexing CREATE SPATIAL INDEX idx_polygon ON perimeters(polygon);Voordelen: Efficiënte queries, bounding box filtering, distance calculations
Zonder geografische support
sql-- Model polygons in separate table CREATE TABLE polygon_coordinates ( id INT AUTO_INCREMENT PRIMARY KEY, perimeter_id INT NOT NULL, latitude DECIMAL(10, 8), longitude DECIMAL(11, 8), sequence INT, -- order in polygon FOREIGN KEY (perimeter_id) REFERENCES perimeters(id), INDEX idx_perimeter_seq (perimeter_id, sequence) );
Image Storage
⚠️ Opmerking: Images niet opslaan als BLOB
❌ FOUT:
CREATE TABLE images (
id INT PRIMARY KEY,
image_data LONGBLOB -- Large, slow, hard to manage
);✅ CORRECT:
CREATE TABLE incident_images (
id INT PRIMARY KEY,
incident_id INT NOT NULL,
image_path VARCHAR(500), -- /uploads/incidents/2025/001/image.jpg
image_hash VARCHAR(64), -- SHA-256 unique identifier
file_size INT,
uploaded_at TIMESTAMP,
FOREIGN KEY (incident_id) REFERENCES incidents(id)
);6. Kritieke Aanpassingen (Docent Feedback)
Issue 1: FK als PK in 4 Tabellen
⚠️ GEVONDEN & OPGELOST
Probleem: FK-kolom was aangeduid als PK (onmogelijk - PK moet unique zijn)
Oplossing: ID-kolom (PK) toegevoegd aan alle tabellen
-- ❌ FOUT
CREATE TABLE readings (
sensor_id INT PRIMARY KEY, -- This is FK, cannot be PK!
FOREIGN KEY (sensor_id) REFERENCES sensors(id)
);
-- ✅ CORRECT
CREATE TABLE readings (
id INT AUTO_INCREMENT PRIMARY KEY,
sensor_id INT NOT NULL,
reading_value DECIMAL(5, 2),
FOREIGN KEY (sensor_id) REFERENCES sensors(id)
);Issue 2: Naming Convention
⚠️ GEVONDEN & OPGELOST
Problemen:
- ❌ Gemengde case:
perimeterenPerimeters - ❌ Afkappingstekens:
perimeters_idi.p.v.perimeter_id - ❌ Nederlandse termen vermengd met Engels
Oplossing: Alles genormaliseerd naar:
- Volledig Engels
- Lowercase met underscores
- Enkelvoudige namen:
location_id,perimeter_id,incident_id
Issue 3: Datatype Validatie
⚠️ BEVRUCHT
| Kolom | Origineel | Opgelost |
|---|---|---|
fire_type | VARCHAR(50) | ENUM(...) ✅ |
temperature | INT | DECIMAL(5,2) ✅ |
slope | INT | DECIMAL(5,2) ✅ |
humidity | INT | INT 0-100 ✅ |
wind_direction | VARCHAR(50) | VARCHAR(10) ✅ |
7. Relaties & Integriteit
Primary Keys
✅ Alle tabellen hebben unieke ID kolom als PK
Foreign Keys
✅ Alle relaties correct gedefinieerd:
users <── perimeters (veel naar veel)
└─── incidents ─────> locations
├──> alerts
└──> incident_images
locations <── weather_data
└────> sensor_readings
perimeters <── incidents
└────> alerts
└────> polygon_coordinatesConstraints
- ✅ NOT NULL waar nodig
- ✅ UNIQUE constraints op email
- ✅ DEFAULT values ingesteld
- ✅ Foreign key cascade delete ingesteld
8. Performance Optimalisatie
Indices
Volgende indices gedefinieerd:
-- Query optimization
CREATE INDEX idx_perimeter_date ON incidents(perimeter_id, start_date);
CREATE INDEX idx_location_time ON weather_data(location_id, measurement_time);
CREATE INDEX idx_incident ON incident_images(incident_id);
CREATE INDEX idx_perimeter_severity ON alerts(perimeter_id, severity);Normalisatie vs. Denormalisatie
- ✅ Schema volledig genormaliseerd
- ✅ Redundantie geminimaliseerd
- ✅ Query joins geoptimaliseerd
9. Audit Checklist
Vereisten (Requirements)
- ✅ Relationeel databanksysteem gekozen
- ✅ REST API architectuur gedefinieerd
- ✅ Software architecture schema uitgewerkt
- ✅ Technologie keuzes gemotiveerd
- ✅ Data/logica verdeling duidelijk
- ✅ Compleet database schema
Evaluatie Criteria
- ✅ Architecture Schema: Voldoende uitgewerkt
- ✅ Technology Choices: Haalbaar & realistisch
- ✅ Data Schema: Compleet & aligned met user stories
- ⚠️ Naming Convention: Opgelost (was issue)
- ⚠️ Normalization: Opgelost (PK/FK issues fixed)
10. Aanbevelingen
Immediate (Done)
- ✅ ID-kolommen toegevoegd waar ontbrekend
- ✅ Naming convention geherziened
- ✅ Data types gecorrigeerd (ENUM, DECIMAL)
- ✅ Índices toegevoegd
Short-term (To Do)
- 📋 Geografische extension implementeren (PostGIS of MariaDB)
- 📋 Image storage infrastructure opzetten
- 📋 Database performance profiling
- 📋 Backup & recovery procedures testen
Long-term (Future)
- 📋 Data archiving strategy
- 📋 Read replicas voor reporting
- 📋 Sharding strategy voor scale
11. Conclusie
✅ AUDIT GESLAAGD (Met voorbehoud)
Samenvatting:
- Database schema is compleet en aligned met user stories
- Software architecture is realistisch en goed uitgewerkt
- Kritieke issues (PK/FK, naming, datatypes) zijn opgelost
- Schema is genormaliseerd en technisch correct
Final Score: 0/0 (Geen strafpunten na correcties)
Volgende Stap: Implementatie en testing van het schema in MariaDB
Audit Date: January 14, 2026
Status: PASSED ✅
Notes: Hakken over de sloot - maar geslaagd!