Forgot password?
Demo access — click to expand
Initial password (all seeded users): ScanOps@2026!Init
⚠️ Change after first login — Profile → Change Password

▶ Super Admin
▶ Chief Technical
▶ Syndic Manager
▶ SHO
▶ Technician
Dashboard
Filter by client:
Open Work Orders
Compliance Status
🚨 Top 5 At-Risk Assets
📏 Overdue Meter Readings
TitleBuildingPriority StatusAssigned ToOpenedActions
BuildingCategoryCertificate # Expiry DateStatusFindingsActions
TitleBuildingSeverity OSHAStatusDateActions
TitleBuildingCategory ScheduledStatusScoreActions
NameBuildingCategory Last ServiceNext ServiceStatusActions
CompanyContactSpeciality RatingJobsStatusActions
TitleCategoryBuilding Uploaded ByDateActions
⚙️ Maintenance KPIs
📋 Compliance KPIs
👷 Contractor Performance
🔍 Inspection KPIs
🤖 Draft a Report
📄 Report Draft
📝

Your AI-drafted report will appear here.
Review carefully before sending.

NameEmailRole WhatsAppStatusLast LoginActions
🎨 Platform Theme
Super Admin only · Changes apply immediately for all users

Select a colour theme for the ScanOps platform. The theme can be set per client to match their brand identity.

Citya Brand
Burgundy · Silver accent — currently active
🏢 Organisation
⚙️ System
💰 Cost Approval Thresholds
Configured per building at creation
BuildingApproval Threshold (MUR)Approver (M+1)Actions
Résidence Les Flamboyants 10,000 Guy Régis Fachette (Chief Technical)
Garden Court Ebène 15,000 Guy Régis Fachette (Chief Technical)
🔍 Recent Audit Log
TimestampUserActionEntityDetail
🏢 Building Registry
Ref #Building NameAddressUnits Approval LimitOpen WOsComplianceActions
Unit #FloorBuildingOwner Owner EmailResidentActions
📬 Submit a Request
This portal can be shared as a public link — no login required for residents and co-owners.
📷
Tap to take a photo or choose from library
JPG, PNG — max 5 photos, 5MB each
📋 Recent Requests
🏛️ Client Portfolio
📏 Scheduled Readings
AssetMeter TypeLast ValueDue DateStatusAction
📋 Recent Readings
AssetTypeValueRangeRecorded
📈 Electricity Trend (kWh) · Résidence Les Flamboyants
🏗️ Asset Health Scorecard
Composite of WO frequency · PM recency · Inspection pass/fail · Incidents · Parts
AssetBuildingHealth ScoreOpen WOsLast PMInsp. PassIncidentsAction
🚨 Top 5 At-Risk Assets
✅ Top 5 Best Performing
📅 Work Schedules
👤 Technician Shifts
🗓️ Public Holidays — Mauritius 2026
🔁 Preventive Maintenance Plans

Recurring templates. The nightly cron job auto-generates a work order whenever a plan is due (minus its lead-time).

RefNameBuildingCategoryEveryNext DueActiveActions
🛠️ Skill Library
👷 Coverage Matrix
🟢 Expert  🔵 Competent  🟡 Trainee  ⬜ None
⚠️ Expiring Certifications — Next 60 Days
TechnicianSkillLevelExpiresDays Left
⚠️ Rules are enforced at submission. Users cannot close Work Orders, submit Inspections or complete PM executions without satisfying all required attachments.
📎 Attachment Rules
📊 Compliance Snapshot
🔍 Preview — WO Close (blocked)
🔒 Cannot close until all required attachments are uploaded.
ℹ️ Admin & Manager roles have org-wide access. Technician & Viewer roles are scoped to their assigned sites only — they cannot see data from other sites.
🔐 User Site Access Matrix
UserRoleRésidence Les FlamboyantsGarden Court EbèneEffective Scope
📋 Recent Access Changes (Audit)
TimestampUserSiteActionGranted By
🔮
Predictive Intelligence
AI-surfaced risks from your operational data — no IoT required
GEAR AI
Avg MTTR
Mean Time To Repair (hours)
Avg MTBF
Mean Time Between Failures (days)
Overdue Assets
Past next service date
Compliance Expiring
Within 30 days
⚠️ Active Risk Alerts
Auto-refreshed from operational data
🏗️ Asset Health Scorecard
AssetBuildingLast Service Next ServiceDays OverdueHealthAction
🤝
Supplier & Contractor Accountability
SLA adherence, performance scores, and contract review evidence
GEAR AI
📊 SLA Performance Dashboard
📋 Contractor Detail — SLA Log
ContractorSpecialityJobs Avg RatingSLA AdherenceOn-Time %Status
📊
Executive Automated Report
Board-ready KPI summary — auto-generated, no manual assembly
⚡ Auto-generated GEAR AI
🤖 AI Narrative Summary
🔧 Work Orders Breakdown
📋 Compliance Status
🎛️
AI Hub — Modular Intelligence Control
Activate or deactivate AI features per client or site
GEAR AI
🔮 Predictive Intelligence
MTTR / MTBF Tracking
Track repair and failure intervals per asset automatically
Asset Risk Alerts
Flag assets approaching or past service dates
Compliance Expiry Warnings
Auto-alert 30, 14, and 7 days before certificate expiry
Failure Pattern Detection
Surface assets with repeated failures within 90 days
⚡ Admin Automation
Auto Preventive Scheduling
Create WOs automatically when assets hit service date
WhatsApp Follow-up Reminders
Auto-ping technician if WO open > 48 hours with no update
Auto Report Generation
Send weekly KPI digest to manager every Monday 8am
Compliance Auto-Logging
Log every compliance event to audit trail without manual entry
🤝 Supplier Intelligence
SLA Adherence Tracking
Score each contractor on on-time delivery and quality
Underperformance Alerts
Flag contractors with rating below 3.5 or on-time < 70%
Contract Review Evidence Pack
Auto-compile SLA data CSV for contract renegotiation
📊 Executive Reporting
Weekly KPI Digest
Auto-email leadership summary every Monday
AI Narrative Generation
Generate plain-language summary of KPI changes
Board PDF Auto-Export
Generate formatted PDF report on 1st of each month
📈 Automation Savings Estimate
📱
Sprint 8 — Native Android App via Capacitor
Gap closure against LoginOnline — wrapping the ScanOps PWA in a native shell for Google Play distribution
SPRINT 8
Est. 12 developer-days
📋 Capacitor Integration Guide (10 Steps)
VITE + REACT 18
1
Install Capacitor Core + Android + CLI
npm install @capacitor/core @capacitor/android npm install -D @capacitor/cli
2
Build the Vite PWA first (required before cap init)
npm run build # produces dist/
3
Initialise Capacitor with correct appId
npx cap init ScanOps digital.celard.scanops --web-dir dist
4
Set Vite base to './' for file:// compatibility
// vite.config.ts export default defineConfig({ base: './', // ← REQUIRED for Capacitor plugins: [react()], })
5
Configure capacitor.config.ts (production-ready)
// capacitor.config.ts import type { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { appId: 'digital.celard.scanops', appName: 'ScanOps', webDir: 'dist', server: { hostname: 'app.scanops.mu', androidScheme: 'https', allowNavigation: ['*.scanops.mu','api.scanops.mu'], }, plugins: { SplashScreen: { launchShowDuration: 2500, backgroundColor: '#0F2B2B', androidSplashResourceName: 'splash', launchAutoHide: false, }, StatusBar: { style: 'DARK', backgroundColor: '#0F2B2B', }, PushNotifications: { presentationOptions: ['badge','sound','alert'], }, Keyboard: { resize: 'body' }, }, }; export default config;
6
Add Android platform
npx cap add android # generates android/ directory
7
Add permissions to AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
8
Sync web assets to native (run after every build)
npm run build && npx cap sync android
9
Open Android Studio
npx cap open android
10
Generate signed AAB for Play Store
cd android ./gradlew bundleRelease # Output: android/app/build/outputs/bundle/release/app-release.aab
📶 Service Worker — Offline Cache Strategy
Workbox
📂 Static Assets (App Shell) → CacheFirst · 30 days
JS/CSS/fonts/images — served from cache instantly. Network only used on first load or after force refresh.
📋 Job LIST /api/work-orders → StaleWhileRevalidate · 24h TTL · Max 5 entries
Shows cached list immediately; revalidates in background. Keeps technician job queue visible offline.
🔧 Job DETAIL /api/work-orders/:id → NetworkFirst · 5s timeout · 48h TTL · Max 50
Tries live data first; falls back to cache if offline or slow. Technician can still view full job details on-site.
💰 Service Rates → CacheFirst · 7 days
Rates change rarely; serve from cache to speed up invoice line creation offline.
🔄 Background Sync Queue: scanops-job-sync-queue (3-day retention)
PATCH job-complete + POST check-in requests queued when offline. Auto-sync fires when connectivity returns. Zero data loss for technicians in weak-signal zones.
🔌 Native Plugin Integrations
3 PLUGINS
📷
Camera — Photo Evidence
@capacitor/camera
npm install @capacitor/camera npx cap sync android // src/hooks/useJobCamera.ts import { Camera, CameraResultType, CameraSource } from '@capacitor/camera'; export function useJobCamera() { const [photos, setPhotos] = useState<string[]>([]); const capturePhoto = async () => { const perm = await Camera.requestPermissions({ permissions: ['camera'] }); if (perm.camera !== 'granted') throw new Error('Camera permission denied'); const image = await Camera.getPhoto({ quality: 85, allowEditing: false, resultType: CameraResultType.Base64, source: CameraSource.Camera, saveToGallery: false, }); if (image.base64String) { setPhotos(prev => [...prev, image.base64String!]); } return image.base64String; }; const uploadPhotos = async (workOrderId: string) => { const uploads = photos.map(b64 => fetch('/api/work-orders/' + workOrderId + '/photos', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ data: b64, mimeType: 'image/jpeg' }), }) ); await Promise.all(uploads); setPhotos([]); }; return { photos, capturePhoto, uploadPhotos }; }
📍
Geolocation — Check-In Verification
@capacitor/geolocation
npm install @capacitor/geolocation npx cap sync android // src/hooks/useCheckinGeo.ts import { Geolocation } from '@capacitor/geolocation'; const GEOFENCE_RADIUS_M = 150; function haversineDistance(lat1:number,lon1:number,lat2:number,lon2:number){ const R=6371000;const dLat=(lat2-lat1)*Math.PI/180; const dLon=(lon2-lon1)*Math.PI/180; const a=Math.sin(dLat/2)**2+Math.cos(lat1*Math.PI/180) *Math.cos(lat2*Math.PI/180)*Math.sin(dLon/2)**2; return R*2*Math.atan2(Math.sqrt(a),Math.sqrt(1-a)); } export function useCheckinGeo() { const checkIn = async (siteLat: number, siteLng: number) => { const perm = await Geolocation.requestPermissions(); if (perm.location !== 'granted') throw new Error('Location denied'); const pos = await Geolocation.getCurrentPosition({ enableHighAccuracy: true, timeout: 10000, }); const { latitude, longitude } = pos.coords; const dist = haversineDistance(latitude,longitude,siteLat,siteLng); return { latitude, longitude, distanceMetres: Math.round(dist), withinGeofence: dist <= GEOFENCE_RADIUS_M, timestamp: new Date().toISOString(), }; }; return { checkIn }; }
🔔
Push Notifications — Job Assignments
@capacitor/push-notifications
npm install @capacitor/push-notifications npx cap sync android // src/lib/pushNotifications.ts import { PushNotifications } from '@capacitor/push-notifications'; export async function initialisePush(userId: string) { const perm = await PushNotifications.requestPermissions(); if (perm.receive !== 'granted') return; await PushNotifications.register(); PushNotifications.addListener('registration', async ({ value: fcmToken }) => { await fetch('/api/users/push-token', { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userId, fcmToken }), }); }); PushNotifications.addListener('pushNotificationReceived', notification => { const { type, workOrderId, title } = notification.data; if (type === 'job_assigned') window.dispatchEvent(new CustomEvent('scanops:navigate', { detail: { page: 'workorders', woId: workOrderId } })); }); PushNotifications.addListener('pushNotificationActionPerformed', action => { const { workOrderId } = action.notification.data; if (workOrderId) window.dispatchEvent(new CustomEvent('scanops:navigate', { detail: { page: 'workorders', woId: workOrderId } })); }); }
🏪 Google Play Store Checklist
DPA 2017
  • App Icons: 48×48 (mdpi), 72×72 (hdpi), 96×96 (xhdpi), 144×144 (xxhdpi), 192×192 (xxxhdpi), 512×512 (Play Store), 108dp adaptive
  • Feature Graphic: 1024×500px JPG/PNG — landscape promotional banner
  • AAB: targetSdk 34, minSdk 26 (Android 8.0+)
  • Content Rating: IARC — Everyone (no age restriction needed)
  • Privacy Policy: https://scanops.mu/privacy — DPA 2017 compliant, DPO: Marcio Isnard (marcio.isnard@celard.digital)
  • Data Safety Form: Declare geolocation (precise, on-device only), camera (photos encrypted, purpose: job evidence)
  • google-services.json: FCM config file for push notifications — generate in Firebase Console
  • Signed Keystore: Generate production keystore, store credentials securely (GitHub Secrets recommended)
📝 Store Listing — EN Short Description (80 chars):
"Location-intelligent field ops for syndic property managers in Mauritius."
📝 Store Listing — FR Short Description (80 chars):
"Gestion des opérations terrain intelligente pour syndics à l'Île Maurice."
📝 Full EN Description (excerpt):
ScanOps is the field operations platform built for syndic property managers and maintenance teams across Mauritius. Powered by location intelligence, ScanOps connects your on-site technicians, syndic managers, and chief technical officers in a single real-time workflow — from job assignment to close-out. Key features: GPS-verified technician check-ins, photo evidence capture, offline job access, 3-level digital approval gate, auto-generated MUR invoices with VAT, compliance certificate tracking, and predictive asset maintenance alerts. Built by CelArd Ltée, Mauritius. DPO: Marcio Isnard.
🧾 Invoice Register
Invoice # Property Work Order Date Amount (MUR) Status Actions
📄 Invoice Preview

Select an invoice to preview

💰 Service Rate Card — MUR
Code
Description
Unit Price (MUR)
VAT?
Active
Actions
3-level gate required before invoice generation

Select a work order to view its approval gate