Sitelet https://github.com/yo-gerr/vcroad
Skip to content

Repository files navigation

VCRoad

Flutter Dart Firebase License: MIT Website

Local road incident reporting & traffic advisory management for Valenzuela City, Philippines.

VCRoad is a cross-platform mobile and web application that empowers citizens to report road incidents (accidents, potholes, floods, debris) and stay informed with real-time traffic advisories. Built for Valenzuela City, the app replaces paper-based reporting with a digital, map-driven experience β€” integrating incident reports, traffic advisories, road safety education, and role-based administration into a single platform.


Features

πŸ—ΊοΈ Map Dashboard
  • Real-time map view of all reported incidents and active advisories using OpenStreetMap
  • Interactive markers with category-based icons and color coding
  • Barangay-level filtering and statistics
  • "Center on me" GPS location with permission-gated access
  • Marker clustering with responsive sizing across devices
πŸ“ Incident Reporting
  • Multi-step wizard: category selection β†’ location pinning β†’ media capture β†’ review & submit
  • Image upload with client-side validation (size, resolution, content heuristics)
  • GPS-assisted barangay auto-detection
  • Report history with status tracking
  • Email verification required before first report
🚦 Traffic Advisories
  • Create and publish advisories (road closures, stop-and-go, one-way, construction, etc.)
  • Map-based route plotting with OSRM road snapping
  • Configurable severity levels and affected areas
  • Real-time updates pushed to all users
  • Enhanced data model β€” advisories carry a stable barangayId (from the GeoJSON id), a Firestore GeoPoint center plus boundsNE/boundsSW for geo-queryability, denormalized lowercase searchKeywords for indexed array-contains search, createdByUid/updatedByUid audit fields, a capped versionHistory audit trail, and statusUpdatedAt/nextStatusAt timestamps
  • Optimistic locking β€” edits increment version inside a Firestore transaction and fail with a refresh prompt on conflict; security rules enforce the version + 1 bump and protect immutable fields (advisoryId, createdAt, createdBy, createdByUid)
  • Single consolidated stream β€” regular users share one realtime stream (active + scheduled, all barangays) that powers the home map, the advisory list, and the new-advisory alert popups (derived from new additions after the session baseline, with mute/dedupe/self-notification guards); the map always plots only active advisories and barangay selection on the advisory screen is a client-side filter. The admin/sysadmin all-statuses stream is capped at the 200 latest advisories for performance.
  • Shared advisory UI β€” status badges render through one AdvisoryStatusBadge widget and category icons through AdvisoryCategory.iconFor (labels/colors/icons come from the model, so cards, detail dialogs, and the wizard never drift apart). Desktop/wide screens show the advisory list as a 2-column card grid, and empty states offer an admin Create CTA. The advisory screen is split into testable widgets (AdvisoryCard, AdvisoryListView) so the list body can be exercised without Firebase.
  • Quick status toggle β€” admins can Activate/Deactivate any advisory directly from its card (re-saves with the persisted status and a bumped version; no manual re-save needed). The advisory list also supports Newest / Oldest / Recently-updated sorting.
  • UI/UX & layout (ISO 25010-aligned) β€” the advisory screen surfaces the active sort as a labeled control, the top stat cards (admin/sysadmin only) are a read-only summary (filtering is done through the single chip row below), and pull-to-refresh (mobile) or a refresh action (desktop) re-subscribe the stream. Contextual empty states distinguish "no data yet" from "no results for your search/filters" (with a Clear search & filters action). The whole surface is theme-aware β€” stat cards, filter chips, the card grid, and the details dialog all use Theme.colorScheme + AppColors.primaryAdaptive tokens (darker accents brightened in dark mode for ~3:1 contrast) while the brand-navy AppBar/FAB stay fixed; category icons pick dark or light ink from the chip color's luminance (e.g. the yellow partial-lane chip gets a dark icon) to keep WCAG contrast. Desktop uses a lazy 2-column masonry grid with each card isolated in a RepaintBoundary so scrolling doesn't repaint off-screen cards, and card action rows wrap instead of overflowing on narrow screens. The advisory details dialog shows a read-only mini map that auto-fits the entire affected + alternate route plot (padded, zoomed out one level, with a graceful fallback for single-point routes), and its image preview uses a stable hero tag. Screen-reader users get selected/button semantics on filters, a labeled sort control, and a semantically labeled card.
  • Inline wizard validation & save safety β€” validation errors in the create/edit wizard surface as a persistent inline banner above the navigation bar (not just a transient snackbar), the Details step shows live inline hints on the reason and contractor fields as you type, and an advisory photo (validated client-side: 5 MB cap, JPG/PNG) uploads to Supabase Storage at advisories/{id}/image.jpg with the superseded image cleaned up on edit. Save failures surface in the same inline banner with the real error, and leaving the wizard with unsaved changes triggers a discard confirmation via PopScope (with mounted guards on async saves).
  • Status lifecycle (deferred) β€” statuses (active / inactive / expired / scheduled) are currently set on save (client-side). nextStatusAt records when each status should next change (one-time startDate/endDate or the next recurring window boundary), so a future scheduled job or client evaluator can auto-transition by querying status + nextStatusAt. Until such a job exists, a status only changes when an admin re-saves the advisory.
πŸ“š Road Safety Education
  • Interactive lessons with 4 question types: multiple choice, true/false, identification, matching type
  • Question images supported across all types (e.g., road-signage photos): question-level images for identification/true-false, per-option images for multiple choice, and imageβ†’meaning pairs for matching type
  • Admin question editor lets you attach images to any question or option (uploaded and compressed on save) β€” ideal for signage identification drills
  • Learn dashboard β€” stats header with level badge & title (Student Driver β†’ Road Master), XP progress bar, day streak, lessons completed X/Y, overall completion %, and a tappable due-review counter that jumps to the first lesson scheduled for review
  • Per-chapter progress β€” expandable chapter headers show completed/total lesson counts with green progress bars
  • Progressive unlocking β€” only the first lesson and each chapter's opener start unlocked (locked cards are greyed out); scoring 70% or higher completes a lesson and unlocks the next one
  • Retake flow β€” scores below 70% show a "Keep Going!" result with a pass-hint card and a Retake Lesson button that resets the lesson's progress for another attempt
  • Spaced-repetition reviews β€” completed lessons open a dedicated review screen: due questions by default (intervals double on correct answers, reset on wrong), an "All caught up!" state with a next-review countdown and a Review all questions anyway option, +5 XP per completed review, and a result screen showing the next review countdown
  • Preview mode β€” admin/sysadmin-only toggle on the Learn page that unlocks every lesson card for browsing; regular users always follow the locked progression. Opening an unlocked-but-not-completed lesson in preview is a placeholder ("coming soon"), while completed lessons open normally.
  • XP system with 5 levels (Student Driver β†’ Road Master), streak tracking, and streak bonuses
  • 8 achievement badges (First Steps, Perfect Score, On a Roll, Week Warrior, Chapter Master, Quick Learner, See It β€” Report It, Review Master) β€” 7 are earnable today; "See It, Report It" awaits the report-flow link-up
  • Animated XP preview as final onboarding slide β€” shows level progression before entering the app
  • Rich lesson result screen with animated score circle, XP counter, level-up indicator, and badge awards (plus a dedicated retake state when the pass threshold isn't met)
  • "Report It" prompt after lesson completion β€” encourages filing a road report tied to what was learned (placeholder: the report link-up is not yet wired)
  • Admin/sysadmin lesson management: create, edit, delete, publish/unpublish, and per-lesson question editor (lessons are auto-numbered; chapters and questions are drag-reorderable) β€” the lesson list adds search, summary chips (N Chapters / N Lessons / N Published), and pull-to-refresh, and the question editor guards against losing unsaved changes. Lessons auto-sum per-question points into their total, and per-answer analytics (timesAnswered / timesCorrect) are tracked in Firestore.
  • Chapter manager with drag-to-reorder chapters
  • Role-aware tutorial with animated widget previews (users: 5 slides including XP preview; admins: 3 slides with dashboard overview)
  • Location permission requested contextually at point of need (center-on-map or first report), not during onboarding
πŸ‘€ User Roles & Administration
  • Three roles: user, admin, sysadmin enforced at both UI and Firestore rules level
  • Admin panel for user management, bans, and role elevation
  • Account search scans the whole users collection (bounded scan loop over createdAt-ordered pages) so matches are found regardless of where they sit β€” no paid search service (Algolia) or Cloud Functions involved; pagination is cursor-based and compositely indexed in firestore.indexes.json
  • Registration flow with identity verification (valid ID + selfie capture)
  • Reusable searchable Barangay dropdown (register, profile details, and create-admin) with instant cached names, normalized/prefixed search, load error + Retry, and a no-results state
  • Profile details page: view/edit contact & address (phone, street, house number, barangay dropdown), read-only name & email, role/verification badges, selfie display, and an unsaved-changes guard when leaving while editing
  • Profile management with appearance settings (theme toggle)
πŸ” Security & Session Management
  • Firestore-based role verification in security rules (no self-elevation)
  • Brute force protection: Firestore-based per-email lockout (5 failed attempts β†’ 15-min block) + local SharedPreferences cache
  • Single-device session enforcement: on login from a new device, the old device is notified and signed out
  • Persistent login via Firebase Auth local persistence
  • Password reset via email link with rate-limited resends (45s cooldown) and anti-enumeration messaging
πŸŒ™ Theme System
  • Light and dark themes with a navy-based dark palette
  • Persistent theme toggle via SharedPreferences (Light / Dark / System)
  • Accessible from Profile β†’ Appearance β†’ Theme
  • Full dark-mode coverage, including the profile details page β€” surface cards, text, dividers, and outlined buttons adapt to the active theme while brand-blue header and input fields stay consistent

Technology Stack

πŸ“± Framework & Language
Component Technology
Framework Flutter ^3.12.2
Language Dart ^3.12.2
Platforms Android, iOS, Web, Windows, macOS, Linux
πŸ—„οΈ Backend & Database
Service Status Details
Firebase Authentication βœ… Active Email/password, Spark free tier (unlimited)
Cloud Firestore βœ… Active Primary database, Spark free tier (50K reads/day)
Supabase Storage βœ… Active Image uploads for advisories, reports & lessons (1 GB free tier)
Firebase Storage ⏸️ Parked Not used β€” Supabase Storage is the live backend
Cloud Functions ⏸️ Parked Login tracking migrated to Firestore directly
πŸ—ΊοΈ Maps & Location
Service Replacement For Status
OpenStreetMap via flutter_map Google Maps SDK βœ… Active
Nominatim (OSM geocoding) Google Places API βœ… Active
OSRM Nearest API (road snapping) Google Roads API βœ… Active
Client-side image validation Google Cloud Vision βœ… Active
OSM tile rendering via Canvas Static map generation βœ… Active
πŸ“¦ Key Packages
Category Packages
State Management provider
Routing go_router, url_strategy
Firebase firebase_core, firebase_auth, cloud_firestore
Maps & Location flutter_map, latlong2, geolocator, permission_handler
HTTP & APIs http
UI Components lottie, carousel_slider, introduction_screen, cached_network_image
Media image_picker, file_picker, image, flutter_image_compress, video_player, video_thumbnail
Utilities shared_preferences, uuid, device_info_plus, intl, url_launcher
Fonts Poppins (Regular + Bold)

Architecture

VCRoad follows Clean Architecture with feature-first organization, aligned with ISO 25010 quality standards.

Data Flow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   Presentation Layer                      β”‚
β”‚  Screens ↔ Providers (ChangeNotifier) ↔ Shared Widgets   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                         β”‚ calls
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   Repository Layer                        β”‚
β”‚  AuthRepo β”‚ ReportRepo β”‚ AdvisoryRepo β”‚ LessonRepo ...    β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚                      β”‚
β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Firebase        β”‚   β”‚  Free APIs / Client-Side         β”‚
β”‚  (Spark tier)    β”‚   β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚   β”‚  β”‚ Nominatim (geocoding) βœ… β”‚    β”‚
β”‚  β”‚ Auth βœ…  β”‚    β”‚   β”‚  β”‚ OSRM (road snap)      βœ… β”‚    β”‚
β”‚  β”‚ Firestoreβœ…β”‚   β”‚   β”‚  β”‚ Client vision heuristicsβœ…β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚   β”‚  β”‚ OSM tiles (static map) βœ… β”‚    β”‚
β”‚                  β”‚   β”‚  β”‚ CSV export             βœ… β”‚    β”‚
β”‚                  β”‚   β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

ISO 25010 Quality Mapping

Quality How the Structure Addresses It
Maintainability Feature modules encapsulate related UI, state, and logic. Clear dependency direction (β†’ presentation β†’ data β†’ core).
Portability Repository pattern abstracts data sources. Platform-specific code isolated via conditional exports.
Modularity Feature-first grouping makes it easy to add/remove/modify features without affecting others.
Analyzability File names reflect their purpose (e.g., login_screen.dart, auth_service.dart).
Testability Repositories can be mocked independently. Providers decoupled from UI. Domain logic testable without Flutter dependencies.
Reusability Shared widgets used across features. Utility functions are pure Dart with no UI coupling.
Replaceability External services isolated behind repository interfaces, swappable without touching UI code.

Installation

Prerequisites
  • Flutter SDK ^3.12.2
  • Dart SDK ^3.12.2
  • Firebase project (configured with Authentication and Firestore)
  • A code editor (VS Code, Android Studio, or IntelliJ)
Setup
# Clone the repository
git clone https://github.com/yo-gerr/vcroad.git
cd vcroad

# Configure environment variables
cp .env.example .env
#  -> Edit .env and fill in your Supabase project URL and anon/publishable key.

# Install dependencies
flutter pub get

# Run on your preferred platform
flutter run -d chrome     # Web
flutter run -d android    # Android
flutter run -d ios        # iOS (macOS only)

# Generate launcher icons (if needed)
flutter pub run flutter_launcher_icons

Note: .env is gitignored and holds the Supabase credentials. The anon/publishable key is public by design (it ships in the client binary), so production data security relies on Supabase RLS / storage-bucket policies, not on keeping the key secret.

Firebase Configuration

The app uses Firebase for authentication and data storage. Configuration files are included:

  • lib/firebase_options.dart β€” auto-generated by FlutterFire CLI
  • android/app/google-services.json β€” Android Firebase config
  • ios/Runner/GoogleService-Info.plist β€” iOS Firebase config (if present)

To use your own Firebase project, run:

flutter pub add firebase_core
flutterfire configure

This regenerates firebase_options.dart and the platform-specific config files.

Lint & Analyze
flutter analyze

Folder Structure

lib/
β”œβ”€β”€ main.dart                         # Entry point, provider setup, GoRouter
β”œβ”€β”€ core/                             # Cross-cutting concerns
β”‚   β”œβ”€β”€ constants/                    # App-wide constants (config, password policy)
β”‚   β”œβ”€β”€ errors/                       # Error types and handling
β”‚   β”œβ”€β”€ theme/                        # AppColors, AppTextStyles, AppTheme
β”‚   └── utils/                        # Pure utility modules (no UI)
β”‚       β”œβ”€β”€ debouncer/                # Debounce utility
β”‚       β”œβ”€β”€ exception/                # try/catch helpers
β”‚       β”œβ”€β”€ format/                   # Date/text formatting
β”‚       β”œβ”€β”€ input/                    # Input validation, styling
β”‚       β”œβ”€β”€ map/                      # Map configuration
β”‚       β”œβ”€β”€ responsive/               # Responsive breakpoint helpers
β”‚       β”œβ”€β”€ routing/                  # Role-based routing config
β”‚       └── web/                      # Web-specific stubs
β”œβ”€β”€ data/                             # Data layer
β”‚   β”œβ”€β”€ models/                       # Data models (DTOs, JSON serde)
β”‚   └── repositories/                 # Repository/service implementations
└── presentation/                     # UI layer
    β”œβ”€β”€ app/                          # App shell, splash screen
    β”œβ”€β”€ providers/                    # 9 ChangeNotifier state managers
    β”œβ”€β”€ shared/                       # Shared dialogs, snackbar, widgets (banner, location prompt, coach marks)
    └── features/                     # Feature modules
        β”œβ”€β”€ auth/                     # Login, Register, Reset Password
        β”œβ”€β”€ onboarding/               # Role-aware tutorial with animated slides
        β”œβ”€β”€ home/                     # Map dashboard
        β”œβ”€β”€ reports/                  # Incident reporting wizard
        β”œβ”€β”€ advisories/               # Advisory management wizard
        β”œβ”€β”€ lesson/                   # Quiz/lesson system
        β”œβ”€β”€ admin/                    # User/account administration
        └── profile/                  # User profile & settings

assets/
β”œβ”€β”€ fonts/                            # Poppins (Regular, Bold)
β”œβ”€β”€ icons/                            # Map markers, app icons (.webp)
β”œβ”€β”€ images/                           # Feature illustrations, user content
β”œβ”€β”€ lottie/                           # Lottie animation files
β”œβ”€β”€ json/                             # Static configuration
β”œβ”€β”€ texts/                            # Agreement text (EN + Tagalog)
β”œβ”€β”€ barangays/                        # Barangay boundary GeoJSON
β”œβ”€β”€ database/                         # Archived Firestore snapshots (reference only)
└── downloads/                        # Downloadable content

Security Model

Role-based access control is enforced at the database level via firestore.rules, not just the client UI.

Role Read Write Elevation
user Own data, public reports, advisories Own profile, own reports (if verified, not banned) Self-registration sets role: user only
admin All users, reports, advisories, settings User profiles (non-admin), reports, advisories, settings Cannot self-promote to sysadmin
sysadmin Everything Everything Full access

Key Rules

  • No self-elevation β€” role changes denied unless performed by admin/sysadmin on another user
  • Report integrity β€” userId and reportedBy must match the authenticated user
  • Verification gating β€” only verified users can create reports
  • Deny-all fallback β€” match /{document=**} at the bottom rejects anything not explicitly allowed

Deploy Rules & Indexes

firebase deploy --only firestore:rules,firestore:indexes

⚠️ Firestore may prompt you to accept the composite indexes added in firestore.indexes.json (advisories status/barangay/barangayId

  • createdAt, and status + nextStatusAt) before queries using them work.

Migrate Existing Advisories

After deploying rules + indexes, backfill existing advisory documents with the new schema (idempotent, dry-run by default):

node scripts/migrate_advisories.js            # preview what will change
node scripts/migrate_advisories.js --run      # apply the backfill

Testing

Pure-Dart and widget tests (no Firebase required):

flutter test
  • test/advisory_model_test.dart β€” model units: status labels/colors, category lookup + icon fallback, buildSearchKeywords, computeCenter/computeBounds, computeNextStatusAt (one-time + recurring + wrap-around), and tolerant fromJson/toJson round-trips.
  • test/widget_test.dart β€” widget tests for the shared advisory UI: AdvisoryStatusBadge labels/colors and AdvisoryCard content, admin-action visibility, callback wiring, recurring-schedule rendering, the lazy desktop masonry grid, and the filtered-empty state's clear-filters action.

Future Improvements

Planned Enhancements
Priority Feature Notes
πŸ”΄ High Add Firebase App Check Protects API keys from unauthorized use
🟑 Medium Storage quota & image optimization Uploads already run on Supabase Storage (1 GB free tier); add a compression/cleanup pipeline for larger media
🟑 Medium Cloud Functions integration Login tracking migrated; remaining functions pending Blaze
🟑 Medium End-to-end testing suite Provider-based architecture primed for integration tests
🟑 Medium CI/CD pipeline GitHub Actions for lint β†’ test β†’ build
🟒 Low Push notifications Real-time alerting for new advisories
🟒 Low Offline-first support Firestore persistence + local sync
🟒 Low Accessibility (a11y) audit Screen reader labels, contrast, keyboard navigation
🟒 Low Localization expansion Beyond English/Tagalog

Contributing

Contributions are welcome. This project does not yet have a formal CONTRIBUTING.md β€” for now, please open an issue or pull request on GitHub. Basic guidelines:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/my-feature)
  3. Commit your changes (git commit -m 'Add my feature')
  4. Push to the branch (git push origin feature/my-feature)
  5. Open a Pull Request

License

Distributed under the MIT License. See LICENSE for more information.

MIT is recommended for open-source Flutter projects β€” it's permissive, allows commercial use, and is the most widely adopted license in the Flutter ecosystem.


Links


Built with Flutter. Backend on Firebase Spark free tier. Maps powered by OpenStreetMap and contributors. Architecture restructured July 2026.

About

Local road incident reporting & traffic advisory management for Valenzuela City, Philippines.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages