Case Study: Building OnTrack Core - Enterprise Mobile App
OnTrack Core is an enterprise-grade mobile application for infrastructure inspection, maintenance management, and asset tracking. This case study explores the technical challenges, architectural decisions, and lessons learned while building this complex cross-platform solution.
Project Overview
OnTrack Core serves field workers in the utilities and infrastructure sectors who need to conduct inspections, track assets, and manage maintenance work orders - often in remote locations with limited or no connectivity.
Key Requirements
- Full offline functionality with seamless sync
- Photo and video capture with annotation
- GPS tracking and geofencing
- Complex form management with conditional logic
- Integration with enterprise ERP systems
- Cross-platform iOS and Android support
- Enterprise security and compliance
Technology Stack
Technical Challenges
Challenge 1: Offline-First Architecture
Field workers spend hours in areas with no cell coverage. The app needed to function completely offline while ensuring data integrity when connectivity returns.
Solution: Conflict-Free Replicated Data Types (CRDT)
We implemented a CRDT-based sync engine that handles concurrent modifications gracefully:
// Simplified CRDT-based sync
struct InspectionRecord: Syncable {
let id: UUID
var data: InspectionData
var vectorClock: VectorClock
var lastModified: Date
mutating func merge(with remote: InspectionRecord) -> InspectionRecord {
// Compare vector clocks to determine order
if vectorClock.happensBefore(remote.vectorClock) {
return remote
} else if remote.vectorClock.happensBefore(vectorClock) {
return self
} else {
// Concurrent modification - merge fields
return InspectionRecord(
id: id,
data: data.merge(with: remote.data),
vectorClock: vectorClock.merge(remote.vectorClock),
lastModified: max(lastModified, remote.lastModified)
)
}
}
}
Key Learning: Traditional last-write-wins strategies lose data. CRDTs preserve all user work even when the same record is modified on multiple devices.
Challenge 2: Large Media Sync
Inspections include hundreds of photos and videos. Syncing gigabytes of media over spotty connections was problematic.
Solution: Chunked Upload with Resume
- Split large files into 1MB chunks
- Track upload progress per chunk
- Resume from last successful chunk
- Background upload with iOS background tasks
- Compress images client-side before upload
class ChunkedUploader {
private let chunkSize = 1024 * 1024 // 1MB
func uploadFile(at url: URL) async throws {
let fileHandle = try FileHandle(forReadingFrom: url)
let fileSize = try fileHandle.seekToEnd()
var offset: UInt64 = 0
while offset < fileSize {
try fileHandle.seek(toOffset: offset)
let chunk = fileHandle.readData(ofLength: chunkSize)
try await uploadChunk(
chunk,
offset: offset,
totalSize: fileSize
)
offset += UInt64(chunk.count)
saveProgress(offset: offset, for: url)
}
}
}
Challenge 3: Complex Form Engine
Inspection forms have hundreds of fields with complex conditional logic, validation rules, and calculated values.
Solution: JSON-Driven Form Renderer
We built a declarative form engine that renders forms from JSON schemas:
{
"fields": [
{
"id": "pole_condition",
"type": "select",
"label": "Pole Condition",
"options": ["Good", "Fair", "Poor", "Replace"],
"required": true
},
{
"id": "replacement_reason",
"type": "text",
"label": "Reason for Replacement",
"showWhen": {
"field": "pole_condition",
"equals": "Replace"
}
}
]
}
This approach enabled:
- Server-side form updates without app releases
- A/B testing of form designs
- Client-specific customization
- Offline form availability
Architecture Decisions
Clean Architecture
We structured the codebase into clear layers:
OnTrackCore/
├── Presentation/ # Views, ViewModels
├── Domain/ # Business Logic, Use Cases
├── Data/ # Repositories, Data Sources
│ ├── Local/ # Core Data, SQLite
│ └── Remote/ # API Clients
└── Core/ # Utilities, Extensions
Dependency Injection
All dependencies are injected, enabling:
- Easy unit testing with mocks
- Swappable implementations (local vs remote)
- Feature flags for gradual rollouts
Protocol-Oriented Design
protocol InspectionRepository {
func getInspection(id: UUID) async throws -> Inspection
func saveInspection(_ inspection: Inspection) async throws
func syncPendingInspections() async throws
}
class OfflineFirstInspectionRepository: InspectionRepository {
private let localDataSource: InspectionLocalDataSource
private let remoteDataSource: InspectionRemoteDataSource
private let syncEngine: SyncEngine
// Implementation prioritizes local data, syncs in background
}
Performance Optimizations
Database Performance
- Indexed frequently queried fields
- Batch inserts for bulk operations
- Lazy loading for large datasets
- Background context for heavy writes
Memory Management
- Image downsampling for thumbnails
- NSCache for frequently accessed data
- Automatic memory warning handling
- Streaming for large file operations
Battery Optimization
- Coalesced network requests
- Intelligent GPS accuracy levels
- Background task scheduling with BGTaskScheduler
- Minimal background activity when battery is low
Security Implementation
Enterprise clients require strict security measures:
- Data Encryption - SQLCipher for at-rest encryption
- Secure Transport - Certificate pinning for all API calls
- Authentication - OAuth 2.0 with refresh tokens
- Biometric Lock - Face ID/Touch ID for app access
- Remote Wipe - Admin can remotely clear device data
- Audit Logging - All actions are tracked for compliance
Results
The app has been transformative for the client's field operations:
- 40% faster inspection completion time
- Zero data loss since offline-first implementation
- 95% reduction in paper-based processes
- Real-time visibility into field operations
- Significant cost savings from improved efficiency
Lessons Learned
- Start offline-first - It's much harder to retrofit offline support
- Invest in sync testing - Edge cases in sync are subtle and destructive
- Build for low-end devices - Field workers don't always have latest hardware
- Plan for large datasets - What works with 100 records breaks at 100,000
- Document everything - Enterprise clients require detailed documentation
Need an Enterprise Mobile App?
I specialize in building complex, offline-capable enterprise applications. Let's discuss your project requirements.
Start a Conversation