Civic Reporting Platform for Mauritania
Signalement citoyen · تقرير المواطن · Citizen Reporting
Baligh (بلّغ — "Report" in Arabic) is a cross-platform citizen reporting application built for Mauritania. Citizens can report local issues (infrastructure damage, environmental hazards, security concerns, etc.), browse reports submitted by others, verify credibility through voting, and communicate directly with reporters.
The app is built with Flutter (MVC architecture, Provider state management) and backed by Supabase (PostgreSQL, Auth, Storage, Realtime).
- Report submission — 4-step wizard: category → description → photo → review & submit
- Interactive map — OSM tiles with FMTC caching, category-colored markers, search & filter
- Home feed — Animated report cards, search bar, stats bar, category filter chips
- Credibility system — Confirm/reject voting with real-time count updates
- Real-time messaging — Per-report conversations with Supabase Realtime subscription & unread badges
- Notifications — DB-backed alert system with unread count
- Authentication — Supabase email/password with auto session persistence
- My Reports — Edit/delete own reports, filter by status
- Account — Profile stats (submitted/validated), reputation badge, settings access
- Multilingual — Arabic (RTL), French, English with persisted locale choice
- Theming — Light/Dark/System with Material 3, brand colors (green #2E7D32, yellow #FDD835)
- Web dashboard — Standalone HTML/JS page deployed on Vercel
- Manage reports — Filter, change status, delete
- Manage users — View stats, toggle admin role, delete
- Analytics — Category bar chart via Chart.js
| Layer | Technology |
|---|---|
| Frontend | Flutter 3.3+ (Dart 3.x) |
| State | Provider + ChangeNotifier |
| Backend | Supabase (PostgreSQL, Auth, Storage, Realtime) |
| Maps | flutter_map + OpenStreetMap + FMTC tile caching |
| i18n | flutter_localizations + intl + ARB files (3 locales) |
| Fonts | Google Fonts — Cairo (Arabic) |
| Admin | Vanilla HTML/CSS/JS + Supabase JS SDK |
| Hosting (Admin) | Vercel |
lib/
├── main.dart # Entry point, providers, theme definitions
├── core/
│ ├── database/ # Supabase DAOs (user, report, vote, notification, message)
│ ├── models/ # Data models (user, vote, notification, message)
│ └── services/ # Service implementations (auth, report, notification, location)
├── models/ # ReportModel
├── services/ # Abstract service interfaces
├── controllers/ # ChangeNotifier providers (9 total)
├── views/ # UI screens (13 views)
├── widgets/ # Shared widgets (report_card, empty_state)
└── l10n/ # Localization (ARB + generated Dart files)
- Models — Plain Dart classes with
toMap()/fromMap()serialization - Views — StatelessWidgets consuming providers via
context.watch/Selector/Consumer - Controllers (Providers) — ChangeNotifier classes holding state and business logic
- Services — Abstract interfaces (e.g.,
ReportService) with Supabase-backed implementations (ReportServiceDb) - DAOs — Data access objects encapsulating Supabase queries with typed parameters
| (screenshot placeholder) | (screenshot placeholder) | (screenshot placeholder) |
| Splash / Login | Home Feed | Report Detail |
| (screenshot placeholder) | (screenshot placeholder) | (screenshot placeholder) |
| Map View | New Report Wizard | Chat |
- Flutter SDK 3.3+ (install guide)
- A Supabase project (create one free)
- Android SDK / Xcode for device build
-
Clone the repository
git clone https://github.com/your-org/baligh-app.git cd baligh-app -
Install dependencies
flutter pub get
-
Configure Supabase Create
lib/utils/supabase_config.dart:import 'package:supabase_flutter/supabase_flutter.dart'; class SupabaseConfig { static final client = Supabase.instance.client; }
Then set your Supabase URL and anon key in
main.dart:await Supabase.initialize( url: 'https://your-project.supabase.co', anonKey: 'your-anon-key', );
-
Configure Google Sign-In (Android)
- In Google Cloud Console, create an Android OAuth 2.0 Client ID
- Package name:
com.baligh.baligh_app - SHA-1 fingerprint: get it with
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android | grep SHA1 - In Supabase Dashboard → Authentication → Providers → Google, enable it and paste the Web Client ID and Client Secret
-
Run database migration Copy the contents of
supabase_migration.sqland execute it in your Supabase SQL Editor. This creates all tables, RLS policies, storage buckets, and theupdate_vote_countsRPC function. -
Run the app
flutter run
flutter build apk --release # Android
flutter build ios --release # iOS (macOS only)Version de test. Nécessite Android 7+ (API 24+) et Google Play Services.
erDiagram
users {
uuid id PK
varchar username UK
varchar email UK
timestamptz created_at
int reputation_score
int reports_count
int confirmed_count
boolean is_admin
}
reports {
bigint id PK
uuid user_id FK
text category
text description
float latitude
float longitude
text address
text photo_url
timestamptz created_at
text status
int confirm_count
int deny_count
}
votes {
bigint id PK
bigint report_id FK
uuid user_id FK
text vote_type
timestamptz created_at
}
notifications {
bigint id PK
uuid user_id FK
bigint report_id FK
text message
int is_read
timestamptz created_at
}
messages {
bigint id PK
bigint report_id FK
uuid sender_id FK
uuid receiver_id FK
text content
boolean is_read
timestamptz created_at
}
users ||--o{ reports : "creates"
users ||--o{ votes : "casts"
users ||--o{ notifications : "receives"
users ||--o{ messages : "sends"
users ||--o{ messages : "receives"
reports ||--o{ votes : "has"
reports ||--o{ notifications : "triggers"
reports ||--o{ messages : "contains"
Relations clés :
users.id→reports.user_id(un utilisateur peut créer plusieurs signalements)users.id→votes.user_id(un utilisateur peut voter plusieurs fois)reports.id→votes.report_id(un signalement reçoit plusieurs votes)users.id→messages.sender_id/messages.receiver_id(messagerie entre utilisateurs)reports.id→messages.report_id(messages liés à un signalement)
RLS (Row Level Security) :
- Chaque utilisateur ne voit/modifie que ses propres données
- Les administrateurs (
is_admin = true) ont un accès global - Les mises à jour des compteurs de votes passent par une fonction
SECURITY DEFINERRPC qui contourne RLS - Les notifications sont insérées via une fonction
create_notification()avecSECURITY DEFINER
Index clé :
votes: contrainteUNIQUE(report_id, user_id)— un seul vote par utilisateur par signalement
Baligh supports 3 languages:
| Language | Code | Direction | Status |
|---|---|---|---|
| العربية (Arabic) | ar |
RTL | ✅ Full |
| Français (French) | fr |
LTR | ✅ Full |
| English | en |
LTR | ✅ Full |
Locale is persisted via SharedPreferences and applied at the MaterialApp level with a ValueKey to force full tree rebuild on switch.
A standalone web dashboard is deployed at:
🔗 admin-dashboard-pearl-delta-63.vercel.app
It connects directly to your Supabase project. Features: login, report management (filter, status change, delete), user management (toggle admin, delete), notification viewer, reports-by-category chart (Chart.js). Arabic/French UI with full i18n.
To redeploy after changes:
cd admin-dashboard
vercel --prod| Member | Role |
|---|---|
| Ahmedou bedou | Developer |
| Abdsalam abdelvetah | Developer |
| Abdy Mohameden | Developer |
| Hasseen Salem | Developer |
📄 Voir la répartition détaillée du travail →
This project is licensed under the MIT License — see the LICENSE file for details.
بلّغ — Because every voice matters.
Built with ♥ for Mauritania