End-to-end IoT and cloud solution built for SEATRU (Sea Turtle Research Unit) at the Chagar Hutang Turtle Sanctuary, Malaysia. The platform enables field volunteers to collect marine turtle nesting data offline and synchronize it to a central database when connectivity is restored.
┌─────────────────────────────────────────────────────────────┐
│ Volunteer's Phone (Beach — No Internet) │
│ ┌───────────────────────────────────┐ │
│ │ PWA (index.html + Service Worker)│ │
│ │ ┌─────────┐ ┌──────────────┐ │ │
│ │ │ Form │───▶│ IndexedDB │ │ Offline storage │
│ │ └─────────┘ └──────┬───────┘ │ │
│ └────────────────────────┼──────────┘ │
│ │ ◀── "Sync" when online │
└───────────────────────────┼─────────────────────────────────┘
│ POST /api/ (JSON batch)
┌───────────────────────────┼─────────────────────────────────┐
│ Docker Compose ▼ │
│ ┌─────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Nginx │───▶│ PHP-FPM │───▶│ MongoDB │ │
│ │ :8080 │ │ (api.php) │ │ turtle_data │ │
│ └─────────┘ └──────────────┘ └──────────────┘ │
│ │ │
│ └── serves frontend static files │
└─────────────────────────────────────────────────────────────┘
See docs/architecture.md for the full Mermaid diagram covering both the Turtle Monitoring and Visitor Tracking systems.
- Offline-first PWA — data is saved to IndexedDB immediately, no connectivity required on the beach.
- Batch sync — pending records are sent to the backend in a single POST once the volunteer is back online.
- Google Sign-In — volunteers authenticate with their Google account; first & last name are recorded with each observation.
- Dashboard — interactive charts (temperature, hygrometry, species distribution) powered by Chart.js.
- CSV export — download all synced observations as a CSV file for analysis in Excel, R, or Python.
- Service Worker — caches the app shell so it loads instantly even without a network.
| Layer | Technology |
|---|---|
| Frontend | Vanilla JS, Tailwind CSS (CDN), Chart.js (CDN) |
| Backend | PHP 8.3-FPM with ext-mongodb |
| Database | MongoDB 7 |
| Proxy | Nginx (Alpine) |
| Auth | Google Identity Services (GIS) |
| Container | Docker Compose |
- Docker & Docker Compose
- (Optional) A Google Cloud OAuth Client ID for production auth
git clone <repo-url>
cd TurtleScope/Turtles_Tracking
docker compose up --buildThe app is available at http://localhost:8080.
Without a Google Client ID the app runs in dev mode — volunteers enter their name and email manually. To enable Google Sign-In:
- Go to Google Cloud Console → APIs & Services → Credentials.
- Create an OAuth 2.0 Client ID (Web application).
- Add
http://localhost:8080to Authorized JavaScript origins. - Copy the Client ID and paste it in
frontend/index.html:const GOOGLE_CLIENT_ID = 'xxxx.apps.googleusercontent.com';
- Rebuild:
docker compose up --build.
- Open the app on a phone, sign in (or use dev mode).
- Fill the observation form (species, eggs, temperature, hygrometry).
- Tap Save Locally — data goes straight to IndexedDB.
- When back online, tap Synchronize Data — records are pushed to MongoDB.
- Switch to the Dashboard tab to see charts and the full data table.
- Click Export CSV to download all records.
TurtleScope/
├── docs/
│ └── architecture.md # Mermaid system diagram
├── Turtles_Tracking/
│ ├── docker-compose.yml
│ ├── nginx/
│ │ └── nginx.conf
│ ├── frontend/
│ │ ├── index.html # SPA: auth, collection form, dashboard
│ │ ├── manifest.json # PWA manifest
│ │ ├── sw.js # Service Worker (cache-first)
│ │ └── assets/
│ │ ├── seatrulogo.jpg
│ │ └── umtlogo.png
│ └── backend/
│ ├── Dockerfile # PHP 8.3-FPM + pecl mongodb
│ └── api.php # REST API (POST + GET + CSV)
├── Travelers_Tracking/ # (Future) Raspberry Pi visitor tracking
├── README.md
└── LICENSE
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/ |
Insert observation(s) — accepts { records: [...] } or a single object |
| GET | /api/ |
Retrieve all observations as JSON |
| GET | /api/?format=csv |
Download all observations as CSV |
Each document in the turtle_data MongoDB collection:
{
"species": "Green Turtle (Chelonia mydas)",
"eggs": 112,
"temperature": 29.5,
"hygrometry": 82.3,
"recorded_by": {
"email": "volunteer@gmail.com",
"given_name": "Jane",
"family_name": "Doe"
},
"recorded_at": "2026-06-04T02:30:00.000Z",
"synced_at": "2026-06-04T08:15:22.000Z"
}