Mobile Apps Modules On Indonesia Sunshine - Complete Documentation Application Name : On Indonesia Sunshine Type : Mobile Attendance Management System Version : 1.0.0 Platform : Android, iOS, Web, Desktop (Windows, macOS, Linux) Last Updated : February 2026 Introduction About the Application On Indonesia Sunshine is a comprehensive mobile attendance management system built with Flutter. The application enables employees to clock in and out with GPS verification, capture attendance photos, track their attendance history, and manage company assets. Key Features at a Glance ✅ GPS-based attendance tracking ✅ Photo verification for check-in/check-out ✅ Real-time location mapping ✅ Attendance history with calendar view ✅ Asset management system ✅ Role-based access control ✅ Secure authentication with JWT ✅ Multi-platform support Getting Started System Requirements For Development Flutter SDK : 3.1.0 or higher Dart SDK : Included with Flutter IDE : VS Code or Android Studio OS : macOS, Windows, or Linux For Android Development Android SDK (API 20+) Android Studio or command-line tools Java Development Kit (JDK) For iOS Development (macOS only) Xcode 12.0 or higher iOS SDK CocoaPods Installation Step 1: Install Flutter macOS brew install flutter Windows Download Flutter SDK from https://flutter.dev Extract to C:\flutter Add to PATH: C:\flutter\bin Linux # Download and extract Flutter cd ~/development tar xf flutter_linux_*.tar.xz export PATH="$PATH:`pwd`/flutter/bin" Step 2: Verify Installation flutter doctor Step 3: Clone and Setup Project # Clone repository git clone cd on-indonesia-absensi # Install dependencies flutter pub get # Run the application flutter run Architecture Overview Technology Stack Component Technology Framework Flutter 3.1.0+ Language Dart State Management StatefulWidget + Global State Networking HTTP Package Local Storage SharedPreferences Maps Google Maps Flutter Authentication JWT (JSON Web Token) Backend API REST API Application Architecture ┌─────────────────────────────────┐ │ Presentation Layer │ │ (UI Screens & Widgets) │ └────────────┬────────────────────┘ │ ┌────────────┴────────────────────┐ │ Business Logic Layer │ │ (State Management, Validation) │ └────────────┬────────────────────┘ │ ┌────────────┴────────────────────┐ │ Service Layer │ │ (OnRest API, SharedPreferences)│ └────────────┬────────────────────┘ │ ┌────────────┴────────────────────┐ │ Data/Network Layer │ │ (HTTP Client, Local Storage) │ └─────────────────────────────────┘ Project Structure lib/ ├── main.dart # Application entry point ├── services/ # Backend services │ ├── onrest.dart # API service (all HTTP calls) │ ├── on_shared_preferences.dart # Local storage │ └── globals.dart # Global state variables └── pages/ # UI screens ├── spalshscreen.dart # Splash screen ├── login/ # Login module ├── mainscreen.dart # Main navigation ├── camera_preview.dart # Camera functionality └── screen/ # Feature screens ├── homescreen/ # Home & attendance ├── historyscreen/ # Attendance history ├── profilescreen/ # User profile └── assetmanagement/ # Asset management Core Features 1. Authentication Login Process The application uses JWT-based authentication: User enters credentials (username/password) App sends request to /api/auth/login Server validates and returns JWT token Token is stored in SharedPreferences Token is included in all subsequent API requests Security Features JWT token-based authentication Secure storage using SharedPreferences Screenshot prevention (Android) Device identification tracking Jailbreak/Root detection Code Example: Login Future loginApp(String username, String password) async { Uri url = Uri.parse('$apiAddress/auth/login'); final http.Response response = await http.post( url, headers: { 'Content-Type': 'application/json', }, body: jsonEncode({ "username": username, "password": password, "isNative": true }), ); if (response.statusCode == 200) { var result = json.decode(response.body); // Store token and user info return result; } } 2. Attendance Management Clock In Process Location Detection : App gets current GPS coordinates Site Verification : Finds nearest registered site Photo Capture : Takes employee photo Validation : Checks if within allowed distance Submission : Sends data to server Clock Out Process Status Check : Verifies user is clocked in Location Capture : Gets current location Photo Verification : Takes exit photo Update Record : Updates existing attendance record Data Stored for Attendance Field Description employeeCode Unique employee identifier timeIn / timeOut Server timestamp locationIn / locationOut GPS coordinates pictureIn / pictureOut Photo URLs statusIn / statusOut Onsite/Offsite status offsiteReason Reason if offsite Attendance Status Checked In : Employee has clocked in, not yet out Checked Out : Employee has completed day Offsite : Working from non-registered location Not Checked In : No active attendance 3. Location Tracking GPS Integration The app uses multiple location packages: geolocator : Gets current GPS coordinates geocoding : Converts coordinates to addresses google_maps_flutter : Displays maps Site Verification Algorithm 1. Get current location (latitude, longitude) 2. Fetch list of registered sites from API 3. Calculate distance to each site 4. Find nearest site 5. Check if distance < allowed radius 6. Set status: Onsite or Offsite Map Features Real-time location marker Nearby site markers Distance calculation Address display Refresh location button 4. History Tracking Features View attendance by month Calendar view with attendance dates Filter by date range Detailed record display Export functionality (future) History Data Display For each attendance record: Date and time in/out Duration Location (address) Photos (in/out) Status (onsite/offsite) Approval status 5. Asset Management Note : This module is role-based. Only users with asset management permission can access it. Asset Inventory Features : Add new assets Update asset information View asset details Track asset history Photo documentation Vendor management Asset Information : Asset number Asset name Serial number Brand and type Purchase date Price Condition Current location Assigned employee Asset Tracking Track asset movements and maintenance: Service history Location changes Condition updates Photo documentation Employee assignments API Reference Base Configuration Base URL: https://sunshineapi.onindonesia.id/api Authentication: Bearer Token (JWT) Content-Type: application/json Authentication Endpoints Login POST /auth/login Request Body: { "username": "string", "password": "string", "isNative": true } Response (200): { "token": "jwt_token", "name": "Employee Name", "code": "EMP001", "position": "Position Title" } Attendance Endpoints Create Attendance (Clock In) POST /attendance/create Authorization: Bearer {token} Request Body: { "employeeCode": "string", "locationIn": "address", "pictureIn": "base64_or_url", "latIn": "latitude", "longIn": "longitude", "statusIn": "onsite|offsite", "status": true, "timeIn": "timestamp", "offsiteReason": "reason_if_offsite", "dateImage": "date", "stage": "in" } Response (200): { "id": "attendance_id", "message": "Success" } Update Attendance (Clock Out) POST /attendance/update Authorization: Bearer {token} Request Body: { "id": "attendance_id", "employeeCode": "string", "locationOut": "address", "pictureOut": "base64_or_url", "latOut": "latitude", "longOut": "longitude", "statusOut": "onsite|offsite", "status": true, "timeOut": "timestamp", "offsiteReason": "reason_if_offsite", "dateImage": "date", "stage": "out" } Check Attendance Status GET /attendance/check?employeeCode={code} Authorization: Bearer {token} Response (200): { "status": "checked_in|checked_out|none", "now": { "in": { "timeIn": "timestamp", "locationIn": "address", ... }, "out": { ... } } } Get Attendance History POST /attendance/personal Authorization: Bearer {token} Request Body: { "employeeCode": "string", "date": "YYYY-MM" } Response (200): [ { "id": "id", "date": "date", "timeIn": "time", "timeOut": "time", "locationIn": "address", "locationOut": "address", ... } ] Upload Image POST /attendance/upload-image Authorization: Bearer {token} Content-Type: multipart/form-data Form Data: - image: File - employeeName: string - statement: string Response (200): { "url": "image_url", "message": "Success" } Location Endpoints Get Server Time GET /servertime?isDate=true Response (200): { "server_time": "timestamp", "date": "YYYY-MM-DD" } Get Site List GET /attendance/get-site-info Authorization: Bearer {token} Response (200): [ { "name": "Site Name", "latitude": "lat", "longitude": "long", "radius": "meters" } ] Get Nearest Site POST /attendance/get-nearest-site Authorization: Bearer {token} Request Body: { "latitude": "current_lat", "longitude": "current_long" } Response (200): { "site": "Site Name", "distance": "meters", "isWithinRadius": true } User Endpoints Change Password POST /user/change-password Authorization: Bearer {token} Request Body: { "oldPassword": "string", "newPassword": "string" } Response (200): { "message": "Password updated successfully" } Check User Access Menu GET /user/accessmenu Authorization: Bearer {token} Response (200): { "assetManagement": "true|false", "otherPermissions": "..." } Asset Management Endpoints Get Company List GET /assetManagement/company Authorization: Bearer {token} Response (200): [ { "id": "company_id", "name": "Company Name" } ] Get Asset Inventory GET /assetManagement/inventories?company={name}&filter={field}&key={value} Authorization: Bearer {token} Response (200): [ { "assetNumber": "AST001", "assetName": "Laptop", "serialNumber": "SN123", "status": "active", ... } ] Add Asset POST /assetManagement/inventories-mobile Authorization: Bearer {token} Content-Type: multipart/form-data Form Data: - assetPicture: File[] (multiple) - employeePicture: File - assetData: JSON string Response (201): { "message": "Asset created successfully", "assetNumber": "AST001" } Update Asset PUT /assetManagement/inventories Authorization: Bearer {token} Request Body: { "assetNumber": "AST001", "assetName": "Updated Name", "serialNumber": "SN123", "vendor": "Vendor Name" } Response (200): { "message": "Asset updated successfully" } Get Asset Details GET /assetManagement/tracking?assetNumber={number} Authorization: Bearer {token} Response (200): { "asset": { ... }, "history": [ ... ] } User Interface Guide Navigation Structure Bottom Navigation Tabs Home (🏠) - Attendance and location History (📅) - Attendance history Profile (👤) - User profile and settings Assets (📦) - Asset management (if authorized) Screen Descriptions Splash Screen First screen shown on app launch Displays app logo Checks authentication status Redirects to Login or Home Login Screen Elements : Email/Username input field Password input field (with show/hide toggle) Login button Error message display Validation : Required fields check Network connectivity check Credential validation Home Screen Top Section : Employee Profile Card Profile photo Employee name Position Employee code Location Section : Map View Current location marker Nearby site markers Distance indicator Refresh location button Instruction Banner : "Press the 🔘 button to find position, and Refresh button to place onsite position" Attendance Section : Clock In/Out Card Current time display Status indicator (In/Out) Check In button (when available) Check Out button (when checked in) Offsite reason input (if not in site radius) Last Attendance Section : Recent Record Date Time In/Out Location Status Photos History Screen Calendar View : Month selector Calendar grid Highlighted attendance dates Date selection Filter Options : Date range picker Status filter (all, complete, incomplete) List View : Chronological list of records Each item shows: Date Time in/out Duration Location Status badge Detail View (tap on record): Full attendance details Maps showing in/out locations Photos (in/out) Timestamps Status information Profile Screen Profile Information : Profile photo Full name Employee code Position Department Company Actions : Change Password button Logout button Change Password Screen Form Fields : Current password New password Confirm new password Validation : Current password verification Password strength check Confirmation match check Asset Management Screens Asset Menu Asset Management option Asset Inventory option Asset List Features : Search bar Company filter Asset cards showing: Photo Asset name Asset number Status badge Asset Detail View Tabs : Information Asset details Owner information Purchase details History Service records Location changes Assignments Photos Gallery view Photo details Add/Edit Asset Form Sections : Basic Information Asset Details Owner Information Vendor Details Purchase Information Photo Uploads Development Guide Project Setup for Developers 1. Environment Setup # Install Flutter flutter doctor # Clone repository git clone cd on-indonesia-absensi # Install dependencies flutter pub get # Verify setup flutter analyze 2. Running the Application # List available devices flutter devices # Run on connected device flutter run # Run on specific device flutter run -d # Run on emulator flutter run -d emulator-5554 3. Development Workflow Hot Reload : Press r in terminal Quick UI updates Preserves app state Hot Restart : Press R in terminal Full app restart Clears state Stop App : Press q in terminal Code Structure Services Layer OnRest ( lib/services/onrest.dart ) Singleton class handling all API communication. Usage : // Get instance var api = OnRest.instance; // Make API call var result = await api.loginApp(username, password); // Check result if (result != 'error') { // Success } else { // Handle error } OnSharedPreferences ( lib/services/on_shared_preferences.dart ) Wrapper for SharedPreferences. Usage : // Save data await OnSharedPreferences.instance.setStringValue("key", "value"); // Load data String value = await OnSharedPreferences.instance.getStringValue("key"); // Delete data await OnSharedPreferences.instance.removeValue("key"); // Clear all await OnSharedPreferences.instance.clear(); Globals ( lib/services/globals.dart ) Global state variables. Common Variables : import 'package:on_indonesia_sunshine/services/globals.dart' as globals; // Authentication globals.jwt // JWT token globals.code // Employee code // Attendance globals.statusattandance // Current status globals.timeIn // Clock in time globals.timeOut // Clock out time globals.capturedImage // Photo file // Location globals.latIn, globals.longIn globals.latOut, globals.longOut globals.locationIn, globals.locationOut Adding New Features Example: Adding a New Screen Create Screen File // lib/pages/screen/myfeature/my_screen.dart import 'package:flutter/material.dart'; class MyScreen extends StatefulWidget { const MyScreen({super.key}); @override State createState() => _MyScreenState(); } class _MyScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('My Feature')), body: Center(child: Text('Content')), ); } } Add Route // In main.dart routes: { '/myscreen': (context) => const MyScreen(), // ... }, Navigate to Screen Navigator.pushNamed(context, '/myscreen'); Example: Adding API Endpoint // In lib/services/onrest.dart Future myNewEndpoint(String param) async { final jwt = await OnSharedPreferences.instance.getStringValue("accessToken"); Uri url = Uri.parse('$apiAddress/my-endpoint'); final http.Response response = await http.post( url, headers: { 'Content-Type': 'application/json', HttpHeaders.authorizationHeader: "Bearer $jwt" }, body: jsonEncode({ "parameter": param, }), ); if (response.statusCode == 200) { if (kDebugMode) { print(response.body); } return jsonDecode(response.body); } else { return {'error': 'Request failed'}; } } Building for Production Android Build # 1. Update version in pubspec.yaml version: 1.0.1+2 # 2. Build release APK flutter build apk --release # 3. Or build App Bundle (for Play Store) flutter build appbundle --release # Output locations: # APK: build/app/outputs/flutter-apk/app-release.apk # AAB: build/app/outputs/bundle/release/app-release.aab iOS Build # 1. Update version # Edit pubspec.yaml # 2. Open in Xcode open ios/Runner.xcworkspace # 3. In Xcode: # - Select "Any iOS Device" # - Product → Archive # - Distribute App Build Checklist Update version number Test on physical devices Verify production API URL Remove debug code Run flutter analyze Test critical flows Prepare release notes Configuration Google Maps API Setup 1. Get API Key Go to Google Cloud Console Create or select project Enable Maps SDK for Android Enable Maps SDK for iOS Create API Key 2. Configure Android Edit android/app/src/main/AndroidManifest.xml : 3. Configure iOS Edit ios/Runner/AppDelegate.swift : import GoogleMaps @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { GMSServices.provideAPIKey("YOUR_API_KEY_HERE") GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } } Environment Configuration Currently using hardcoded API URL. To support multiple environments: Create Config File // lib/config/app_config.dart class AppConfig { static const String apiUrl = String.fromEnvironment( 'API_URL', defaultValue: 'https://sunshineapi.onindonesia.id/api', ); static const String env = String.fromEnvironment( 'ENV', defaultValue: 'production', ); } Use in Code import 'package:on_indonesia_sunshine/config/app_config.dart'; String apiAddress = AppConfig.apiUrl; Build with Environment # Development flutter run --dart-define=API_URL=https://dev.api.com --dart-define=ENV=development # Staging flutter build apk --dart-define=API_URL=https://staging.api.com --dart-define=ENV=staging # Production flutter build apk --dart-define=API_URL=https://sunshineapi.onindonesia.id/api --dart-define=ENV=production Troubleshooting Common Issues 1. "Flutter SDK not found" # Verify Flutter installation flutter doctor # Add Flutter to PATH export PATH="$PATH:[PATH_TO_FLUTTER]/flutter/bin" 2. "Waiting for another flutter command" # Remove lock file rm -rf ~/.flutter/flutter.lock 3. "CocoaPods not installed" (iOS) # Install CocoaPods sudo gem install cocoapods # Install pods cd ios pod install 4. Map not showing Verify Google Maps API key Check API key restrictions Enable Maps SDK in Google Cloud Console Check internet connectivity 5. Location permission denied // Request permission in code import 'package:permission_handler/permission_handler.dart'; var status = await Permission.location.request(); if (status.isGranted) { // Permission granted } else { // Handle permission denied } 6. Build errors after update flutter clean flutter pub get cd ios && pod install && cd .. # For iOS flutter run 7. Hot reload not working Press R for hot restart Stop and restart app Check for syntax errors Security Best Practices Application Security 1. Screenshot Prevention // Enabled in main.dart for Android await FlutterWindowManager.addFlags( FlutterWindowManager.FLAG_SECURE ); 2. Secure Storage JWT tokens stored in SharedPreferences Never log sensitive data in production Clear data on logout 3. API Security All requests use HTTPS JWT token in Authorization header Token expiration handling 4. Location Privacy Request permissions properly Only collect when needed Clear explanation to users 5. Code Security No hardcoded credentials API keys not in version control Obfuscate code for release builds Release Security Checklist Remove all debug prints Verify API endpoints (HTTPS) Check for exposed API keys Enable code obfuscation Test on rooted/jailbroken devices Review permissions Secure local storage Maintenance Regular Maintenance Tasks Monthly Update Flutter SDK Update dependencies Review security advisories Check API changes Before Each Release Update version number Run full test suite Update documentation Review performance Check error logs Updating Dependencies # Check for updates flutter pub outdated # Update to latest compatible versions flutter pub upgrade # Update to major versions (careful!) flutter pub upgrade --major-versions # After updating flutter clean flutter pub get flutter run Version Management Version Format # In pubspec.yaml version: 1.2.3+45 # 1.2.3 = Version Name (MAJOR.MINOR.PATCH) # 45 = Version Code (build number) Semantic Versioning MAJOR : Breaking changes MINOR : New features (backward compatible) PATCH : Bug fixes Appendix Dependencies Reference UI & Navigation google_nav_bar - Bottom navigation salomon_bottom_bar - Alternative nav bar animated_notch_bottom_bar - Animated nav line_icons - Icon pack page_transition - Page animations Network & Storage http - HTTP client shared_preferences - Local storage url_launcher - Launch URLs Location & Maps google_maps_flutter - Maps location - Location services geolocator - Geolocation geocoding - Reverse geocoding Media image_picker - Camera/Gallery path - File paths Date & Time intl - Formatting slide_digital_clock - Clock widget scrollable_clean_calendar - Calendar easy_date_timeline - Timeline Security flutter_jailbreak_detection - Root detection permission_handler - Permissions flutter_windowmanager - Screenshot prevention Glossary Term Definition JWT JSON Web Token - Authentication token GPS Global Positioning System - Location tracking API Application Programming Interface SDK Software Development Kit Onsite Employee at registered location Offsite Employee at non-registered location Clock In Mark arrival/start of work Clock Out Mark departure/end of work Asset Company equipment or property Geofencing Location-based boundaries Support Resources Official Documentation Flutter Docs Dart Language Pub.dev Packages Community Flutter Community Stack Overflow GitHub Issues Document Version : 1.0 Last Updated : February 2026 Maintained By : On Indonesia Development Team