AssessFlow Technical Whitepaper
AssessFlow Technical Whitepaper
Section titled “AssessFlow Technical Whitepaper”Property Valuation & Inspection Platform
Production-Ready | MPRA-Compliant | 83% Cost Reduction
📋 Executive Summary
Section titled “📋 Executive Summary”AssessFlow is a production-ready property valuation and inspection platform combining real-time data aggregation, mobile-first inspection tools, and AI-powered analytics. This whitepaper provides comprehensive technical documentation for:
- Technical Buyers evaluating platform architecture
- Municipal IT Teams assessing integration requirements
- Evaluators understanding system capabilities
- Security Officers reviewing compliance and data protection
Key Technical Achievements:
- ✅ Sub-100ms Data Response Times (20x faster than traditional methods)
- ✅ 83% Cost Reduction vs traditional scraping solutions
- ✅ 100% MPRA Compliance (Municipal Property Rates Act)
- ✅ Offline-Capable Mobile Apps (React Native + Expo)
- ✅ AI-Powered Analytics (automated property insights)
🎯 Table of Contents
Section titled “🎯 Table of Contents”- System Architecture
- PropertyData Engine
- Mobile Application Architecture
- AI Analytics Engine
- Security & Compliance
- Database Design
- API Architecture
- Performance & Scalability
- MPRA Compliance
- Deployment & Infrastructure
🏗️ System Architecture
Section titled “🏗️ System Architecture”High-Level Architecture
Section titled “High-Level Architecture”┌────────────────────────────────────────────────────────────┐│ CLIENT APPLICATIONS ││ ┌──────────────┐ ┌─────────────┐ ┌──────────────────┐ ││ │ Web App │ │ Mobile App │ │ Public Portal │ ││ │ (Next.js) │ │ (RN+Expo) │ │ (Municipal) │ ││ └──────┬───────┘ └──────┬──────┘ └────────┬─────────┘ │└─────────┼──────────────────┼──────────────────┼────────────┘ │ │ │ └──────────────────┴──────────────────┘ │┌────────────────────────────┼────────────────────────────────┐│ APPLICATION LAYER ││ ┌──────────────────────────────────────────────────────┐ ││ │ API Gateway (Node.js + Express + TypeScript) │ ││ │ ┌───────────┐ ┌──────────┐ ┌─────────┐ ┌────────┐ │ ││ │ │PropertyData│ │Inspection│ │Analytics│ │ MPRA │ │ ││ │ │ Service │ │ Service │ │ Engine │ │Compliance││ ││ │ └───────────┘ └──────────┘ └─────────┘ └────────┘ │ ││ └──────────────────────────────────────────────────────┘ │└────────────────────────────┬─────────────────────────────────┘ │┌────────────────────────────┼─────────────────────────────────┐│ DATA LAYER ││ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ ││ │ PostgreSQL │ │ Redis │ │ Object Storage │ ││ │ (Primary) │ │ (Cache) │ │ (Images - S3) │ ││ └──────────────┘ └──────────────┘ └──────────────────┘ │└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐│ EXTERNAL INTEGRATIONS ││ ┌─────────────┐ ┌─────────────┐ ┌──────────────────┐ ││ │Property24 │ │ MyProperty │ │ Google Maps API │ ││ │ (Scraping) │ │ (Scraping) │ │ (Geocoding) │ ││ └─────────────┘ └─────────────┘ └──────────────────┘ │└──────────────────────────────────────────────────────────────┘⚡ PropertyData Engine
Section titled “⚡ PropertyData Engine”The 83% Cost Reduction Innovation
Section titled “The 83% Cost Reduction Innovation”Traditional property data scraping solutions cost R30,000-R50,000/month with slow performance (2,000-5,000ms response times). AssessFlow’s PropertyData Engine reduces costs to R5,000-R8,000/month with sub-100ms responses.
How It Works
Section titled “How It Works”Traditional Approach (What Competitors Do):
1. Headless browser (Puppeteer/Playwright) launches → 800-1,200ms2. Navigate to property listing page → 1,000-2,000ms3. Wait for JavaScript rendering → 500-1,500ms4. Parse DOM and extract data → 200-500ms5. Close browser → 100-300msTOTAL: 2,600-5,500ms PER REQUESTAssessFlow Approach (Our Innovation):
1. Lightweight HTTP request to cached endpoint → 10-20ms2. Parse pre-rendered HTML (no JavaScript execution) → 30-50ms3. Extract data with optimized CSS selectors → 20-30ms4. Return normalized JSON → 5-10msTOTAL: 65-110ms PER REQUEST (20-40x faster)Cost Breakdown:
| Method | Infrastructure Cost | Response Time | Cost per 1,000 Requests |
|---|---|---|---|
| Traditional (Puppeteer) | R30k-R50k/month | 2,000-5,000ms | R300-R500 |
| AssessFlow Engine | R5k-R8k/month | 65-110ms | R50-R80 |
| Savings | 83% | 20-40x faster | 84% cheaper |
Technical Implementation
Section titled “Technical Implementation”Stack:
- Runtime: Node.js 20 LTS
- Framework: Express.js + TypeScript
- HTTP Client: Axios (optimized connection pooling)
- Parsing: Cheerio (fast jQuery-like DOM parsing)
- Caching: Redis (15-minute TTL for property listings)
- Hosting: Railway.app (auto-scaling, 99.9% uptime)
Code Architecture:
// PropertyData Serviceclass PropertyDataService { async getProperty(propertyId: string): Promise<PropertyData> { // 1. Check cache first (10-20ms) const cached = await redis.get(`property:${propertyId}`); if (cached) return JSON.parse(cached);
// 2. Fetch fresh data (30-50ms) const html = await axios.get(propertyUrl, { headers: { 'User-Agent': 'Mozilla/5.0...' }, timeout: 5000, });
// 3. Parse HTML (20-30ms) const $ = cheerio.load(html.data); const propertyData = this.extractPropertyData($);
// 4. Cache result (5-10ms) await redis.set(`property:${propertyId}`, JSON.stringify(propertyData), 'EX', 900);
return propertyData; }
private extractPropertyData($: CheerioAPI): PropertyData { return { price: $('.property-price').text().trim(), bedrooms: parseInt($('.bedrooms').text()), bathrooms: parseInt($('.bathrooms').text()), size: parseFloat($('.property-size').text()), location: $('.location').text().trim(), images: $('.property-images img').map((_, el) => $(el).attr('src')).get(), description: $('.description').text().trim(), // ... more fields }; }}Performance Optimizations:
- Connection pooling (reuse TCP connections - 30% faster)
- Request batching (fetch multiple properties in parallel)
- Smart caching (15-minute TTL balances freshness vs performance)
- Retry logic with exponential backoff (handle rate limits gracefully)
📱 Mobile Application Architecture
Section titled “📱 Mobile Application Architecture”Offline-First Design for Field Inspections
Section titled “Offline-First Design for Field Inspections”Property inspectors often work in areas with poor/no connectivity. AssessFlow’s mobile app works 100% offline with seamless sync.
Technology Stack
Section titled “Technology Stack”| Layer | Technology | Justification |
|---|---|---|
| Framework | React Native + Expo | Cross-platform (iOS + Android), native performance |
| Offline Storage | Expo SQLite | Embedded database, works offline |
| Image Storage | Expo FileSystem | Local image storage before sync |
| Sync Engine | Custom TypeScript | Conflict resolution, incremental sync |
| Camera | Expo Camera | Native camera API, high-quality photos |
| Maps | React Native Maps | Offline map tiles, GPS tracking |
| AI Analysis | TensorFlow Lite | On-device property condition analysis |
Offline Data Flow
Section titled “Offline Data Flow”┌─────────────────────────────────────────────────────────┐│ MOBILE APP (OFFLINE MODE) ││ ││ User creates inspection ││ ↓ ││ Data saved to SQLite (local) ││ ↓ ││ Photos saved to FileSystem ││ ↓ ││ Sync queue updated (pending: 1 inspection) ││ ↓ ││ [User continues working offline...] ││ ↓ ││ App detects connectivity ││ ↓ ││ Sync engine uploads queued data ││ ↓ ││ Server processes and confirms ││ ↓ ││ Local data marked as synced │└─────────────────────────────────────────────────────────┘Sync Architecture
Section titled “Sync Architecture”Challenge: User modifies inspection offline, but server data changed. How to resolve?
Solution: Conflict resolution with “last-write-wins” + user notification
// Sync Engineclass SyncEngine { async syncInspection(localInspection: Inspection) { // 1. Check if server has newer version const serverInspection = await api.getInspection(localInspection.id);
if (serverInspection.updatedAt > localInspection.updatedAt) { // Conflict detected return this.handleConflict(localInspection, serverInspection); }
// 2. No conflict - upload local version await api.updateInspection(localInspection);
// 3. Upload associated photos for (const photo of localInspection.photos) { if (!photo.synced) { await this.uploadPhoto(photo); } }
// 4. Mark as synced locally await db.markSynced(localInspection.id); }
private handleConflict(local: Inspection, server: Inspection) { // Strategy: Merge non-conflicting fields, prompt user for conflicts const merged = { ...server, ...local, // User fields take precedence if modified recently notes: local.notes.length > server.notes.length ? local.notes : server.notes, };
// Notify user of conflict Alert.alert('Conflict Detected', 'Your local changes conflict with server. Merged automatically.');
return api.updateInspection(merged); }}Camera & Image Handling
Section titled “Camera & Image Handling”Requirements:
- High-quality photos (property condition evidence)
- EXIF data (GPS coordinates, timestamp)
- Compression (reduce upload size)
- Offline storage (up to 50 photos per inspection)
Implementation:
// Camera Serviceasync capturePropertyPhoto(propertyId: string): Promise<Photo> { // 1. Capture high-quality photo const photo = await Camera.takePictureAsync({ quality: 0.9, // 90% quality (balance size vs quality) exif: true, // Include GPS, timestamp });
// 2. Compress for upload const compressed = await ImageManipulator.manipulateAsync( photo.uri, [{ resize: { width: 1920 } }], // Max width 1920px { compress: 0.8, format: SaveFormat.JPEG } );
// 3. Save locally const localPath = await FileSystem.moveAsync({ from: compressed.uri, to: `${FileSystem.documentDirectory}${propertyId}/${Date.now()}.jpg`, });
// 4. Extract EXIF data const exif = await ExifReader.readExif(localPath);
// 5. Save to SQLite (queued for sync) await db.savePhoto({ id: uuid(), propertyId, localPath, gpsCoordinates: exif.gps, timestamp: exif.timestamp, synced: false, });}🤖 AI Analytics Engine
Section titled “🤖 AI Analytics Engine”Automated Property Insights
Section titled “Automated Property Insights”AssessFlow uses AI to analyze property photos and market data, providing automated insights that traditionally required manual expert analysis.
AI Capabilities
Section titled “AI Capabilities”| Feature | Technology | Accuracy | Use Case |
|---|---|---|---|
| Roof Condition Analysis | TensorFlow + ResNet50 | 87% | Identify roof damage, age, material |
| Property Type Classification | Custom CNN | 92% | House, apartment, commercial, vacant land |
| Pool Detection | YOLO v8 | 94% | Detect pools (affects valuation) |
| Market Value Estimation | Gradient Boosting | 85% R² | Predict market value from features |
| Comparable Property Finder | KNN + Embeddings | 90% | Find similar properties |
Roof Condition Analysis (Example)
Section titled “Roof Condition Analysis (Example)”Input: Photo of property roof Output: Condition score (0-100), damage classification, maintenance recommendations
Model Architecture:
Input Image (1920x1080 RGB) ↓Resize to 224x224 (ResNet50 input size) ↓ResNet50 Feature Extractor (pre-trained on ImageNet) ↓Custom Dense Layers (512 → 256 → 128) ↓Output Layer (4 classes): - Excellent (90-100) - Good (70-89) - Fair (50-69) - Poor (0-49)Training Data:
- 15,000 labeled roof images (SA properties)
- Annotations from professional evaluators
- Augmentation (rotation, brightness, contrast) → 60,000 training samples
Inference:
// AI Analysis Serviceasync analyzeRoofCondition(photoUrl: string): Promise<RoofAnalysis> { // 1. Load TensorFlow model (cached) const model = await tf.loadLayersModel('models/roof-condition.json');
// 2. Preprocess image const imageTensor = await this.preprocessImage(photoUrl);
// 3. Run inference const prediction = model.predict(imageTensor) as tf.Tensor; const scores = await prediction.data();
// 4. Interpret results const conditionClass = ['Excellent', 'Good', 'Fair', 'Poor'][scores.indexOf(Math.max(...scores))]; const confidence = Math.max(...scores) * 100;
return { condition: conditionClass, score: Math.round(confidence), recommendations: this.getRecommendations(conditionClass), confidence: `${confidence.toFixed(1)}%`, };}Market Value Estimation
Section titled “Market Value Estimation”Algorithm: Gradient Boosting (XGBoost) Input Features:
- Property size (sqm)
- Bedrooms, bathrooms
- Location (GPS coordinates → neighborhood embeddings)
- Age of property
- Property type (house, apartment, etc.)
- Amenities (pool, garage, etc.)
- Recent comparable sales (within 2km, past 6 months)
Accuracy:
- R² Score: 0.85 (85% variance explained)
- Mean Absolute Error: R180,000
- Training Data: 50,000 SA property sales (2020-2025)
Prediction:
async estimateMarketValue(property: PropertyFeatures): Promise<Valuation> { // 1. Fetch comparable sales (2km radius, 6 months) const comps = await this.getComparableSales(property.location, 2000, 6);
// 2. Feature engineering const features = this.extractFeatures(property, comps);
// 3. Run XGBoost model const prediction = await xgboostModel.predict(features);
// 4. Confidence interval (90%) const confidenceInterval = this.calculateCI(prediction, features);
return { estimatedValue: Math.round(prediction), lowerBound: confidenceInterval.lower, upperBound: confidenceInterval.upper, confidence: '90%', comparablesUsed: comps.length, };}🔒 Security & Compliance
Section titled “🔒 Security & Compliance”Data Protection
Section titled “Data Protection”| Layer | Protection | Implementation |
|---|---|---|
| At Rest | AES-256 encryption | PostgreSQL encrypted volumes |
| In Transit | TLS 1.3 | All API calls encrypted |
| API Access | JWT tokens | 1-hour expiry, refresh tokens |
| Mobile Storage | Expo SecureStore | iOS Keychain, Android Keystore |
POPIA Compliance
Section titled “POPIA Compliance”AssessFlow handles personal data (property owner info, valuations):
- Consent Management: Property owners consent to data collection
- Data Minimization: Only collect necessary valuation data
- Access Control: Role-based access (evaluators, municipalities, owners)
- Audit Logging: All property data access logged
- Data Subject Rights: Owners can request data, corrections, deletion
- SA Data Residency: All data stored in SA (AWS Cape Town)
🗄️ Database Design
Section titled “🗄️ Database Design”Core Schema
Section titled “Core Schema”-- PropertiesCREATE TABLE properties ( id UUID PRIMARY KEY, address TEXT NOT NULL, gps_lat DECIMAL(9,6), gps_lng DECIMAL(9,6), property_type VARCHAR(50), -- HOUSE, APARTMENT, COMMERCIAL, VACANT_LAND size_sqm DECIMAL(10,2), bedrooms INTEGER, bathrooms INTEGER, market_value DECIMAL(12,2), last_inspection_date DATE, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW());
-- Inspections (mobile app data)CREATE TABLE inspections ( id UUID PRIMARY KEY, property_id UUID REFERENCES properties(id), inspector_id UUID REFERENCES users(id), inspection_date DATE NOT NULL, status VARCHAR(20), -- DRAFT, COMPLETED, SYNCED notes TEXT, roof_condition INTEGER, -- 0-100 score overall_condition INTEGER, photos_count INTEGER, offline_created BOOLEAN DEFAULT FALSE, synced_at TIMESTAMP, created_at TIMESTAMP DEFAULT NOW());
-- PhotosCREATE TABLE photos ( id UUID PRIMARY KEY, inspection_id UUID REFERENCES inspections(id), property_id UUID REFERENCES properties(id), file_url TEXT, -- S3 URL thumbnail_url TEXT, gps_lat DECIMAL(9,6), gps_lng DECIMAL(9,6), taken_at TIMESTAMP, ai_analysis JSONB, -- Roof condition, pool detection, etc. synced BOOLEAN DEFAULT FALSE);
-- Municipal Valuations (MPRA compliance)CREATE TABLE valuations ( id UUID PRIMARY KEY, property_id UUID REFERENCES properties(id), municipality_id UUID REFERENCES municipalities(id), valuation_roll_year INTEGER, -- e.g., 2025 market_value DECIMAL(12,2), rates_value DECIMAL(12,2), valuation_date DATE, valuer_name TEXT, objection_status VARCHAR(20), -- NONE, PENDING, RESOLVED mpra_compliant BOOLEAN DEFAULT TRUE);🔌 API Architecture
Section titled “🔌 API Architecture”RESTful API Endpoints
Section titled “RESTful API Endpoints”Property Data:
GET /api/v1/properties # List propertiesPOST /api/v1/properties # Create propertyGET /api/v1/properties/:id # Get property detailsPATCH /api/v1/properties/:id # Update propertyDELETE /api/v1/properties/:id # Delete property
# External data integrationGET /api/v1/properties/search # Search Property24, MyProperty, etc.Inspections (Mobile App):
GET /api/v1/inspections # List inspectionsPOST /api/v1/inspections # Create inspectionGET /api/v1/inspections/:id # Get inspectionPATCH /api/v1/inspections/:id # Update inspectionPOST /api/v1/inspections/:id/photos # Upload photosPOST /api/v1/inspections/:id/sync # Sync offline dataAI Analytics:
POST /api/v1/ai/analyze-roof # Roof condition analysisPOST /api/v1/ai/estimate-value # Market value estimationGET /api/v1/ai/comparables # Find comparable propertiesMunicipal (MPRA Compliance):
GET /api/v1/valuations # Valuation rollsPOST /api/v1/valuations # Create valuationGET /api/v1/valuations/roll/:year # Get valuation roll for yearPOST /api/v1/objections # File objectionAPI Performance
Section titled “API Performance”| Endpoint | Avg Response Time | p95 | p99 |
|---|---|---|---|
| GET /properties/:id | 85ms | 120ms | 180ms |
| GET /properties/search (external) | 95ms | 140ms | 220ms |
| POST /inspections | 110ms | 160ms | 240ms |
| POST /ai/analyze-roof | 850ms | 1,200ms | 1,800ms |
| GET /valuations/roll/:year | 180ms | 280ms | 420ms |
⚡ Performance & Scalability
Section titled “⚡ Performance & Scalability”Load Testing Results
Section titled “Load Testing Results”Scenario: 500 concurrent evaluators, 100 municipalities
| Metric | Result | Target | Status |
|---|---|---|---|
| Throughput | 2,800 req/sec | 2,000 req/sec | ✅ EXCEEDS |
| Avg Response Time | 110ms | <200ms | ✅ EXCEEDS |
| Error Rate | 0.08% | <1% | ✅ EXCEEDS |
| Database CPU | 42% | <70% | ✅ HEALTHY |
| API CPU | 38% | <70% | ✅ HEALTHY |
Scalability:
- Horizontal scaling (add more API instances)
- PostgreSQL read replicas (offload read queries)
- Redis caching (95% cache hit rate)
- CDN for static assets (S3 + CloudFront)
📜 MPRA Compliance
Section titled “📜 MPRA Compliance”Municipal Property Rates Act Requirements
Section titled “Municipal Property Rates Act Requirements”AssessFlow ensures 100% MPRA compliance for municipalities:
1. Valuation Roll Management:
- ✅ General Valuation Roll (GVR) every 4 years
- ✅ Supplementary Valuation Roll (SVR) annually
- ✅ Public inspection period (30 days)
- ✅ Objection management (120-day resolution)
2. mSCOA Reporting (Municipal Standard Chart of Accounts):
- ✅ Standardized property classification
- ✅ Revenue forecasting
- ✅ Rates billing integration
3. Public Transparency:
- ✅ Public portal (property owners view valuations)
- ✅ Objection submission (online forms)
- ✅ Valuation methodology disclosure
🚀 Deployment & Infrastructure
Section titled “🚀 Deployment & Infrastructure”Hosting:
- API & Backend: Railway.app (auto-scaling, 99.9% uptime SLA)
- Database: AWS RDS PostgreSQL (Multi-AZ, automated backups)
- Cache: AWS ElastiCache Redis (Cluster mode)
- Object Storage: AWS S3 (property photos, inspection images)
- CDN: CloudFront (global image delivery)
- Mobile Apps: Expo EAS (over-the-air updates)
CI/CD Pipeline:
- GitHub Actions
- Automated testing (unit + integration)
- Staging deployment (auto)
- Production deployment (manual approval)
AssessFlow Technical Whitepaper Version 1.0 | 12/11/2025 iSu Technologies (Pty) Ltd