fix: seeder idempotent with firstOrCreate
Use firstOrCreate instead of create so db:seed can run safely on container restart without duplicate key violation.
This commit is contained in:
139
docs/07-API.md
Normal file
139
docs/07-API.md
Normal file
@@ -0,0 +1,139 @@
|
||||
# API Reference
|
||||
|
||||
## Authentication
|
||||
|
||||
### POST `/api/login`
|
||||
|
||||
Login via API (returns user info, no token).
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"username": "admin",
|
||||
"password": "password123"
|
||||
}
|
||||
```
|
||||
|
||||
**Success Response (200):**
|
||||
```json
|
||||
{
|
||||
"error": false,
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"email": "admin@example.com",
|
||||
"acc_lvl": 1
|
||||
}
|
||||
```
|
||||
|
||||
**Error Response (200):**
|
||||
```json
|
||||
{
|
||||
"error": true,
|
||||
"message": "Wrong Password/Username"
|
||||
}
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- No authentication token is generated — this endpoint only validates credentials
|
||||
- No session is created — API endpoints are stateless
|
||||
- All other API endpoints have **no authentication** — they are publicly accessible
|
||||
|
||||
---
|
||||
|
||||
## Station Data
|
||||
|
||||
### GET `/api/station/current`
|
||||
|
||||
Returns all stations with their latest rainfall, water level, and siren data.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"stationid": "KBLG0026",
|
||||
"name": "Stesen Kupang",
|
||||
"district": "Baling",
|
||||
"lng": 100.7521,
|
||||
"lat": 5.7879,
|
||||
"rainfall": 1,
|
||||
"waterlevel": 1,
|
||||
"siren": 1,
|
||||
"rainfall_value": 12.5,
|
||||
"rainfall_time": "2025-11-06T14:00:00",
|
||||
"waterlevel_value": 3.2,
|
||||
"waterlevel_time": "2025-11-06T14:00:00",
|
||||
"siren_level": "N",
|
||||
"siren_time": "2025-11-06T14:00:00"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### GET `/api/station/rainfall`
|
||||
|
||||
Returns latest rainfall data for rainfall-enabled stations.
|
||||
|
||||
### GET `/api/station/waterlevel`
|
||||
|
||||
Returns latest water level data for waterlevel-enabled stations.
|
||||
|
||||
### GET `/api/station/notification`
|
||||
|
||||
Returns today's latest notification per station.
|
||||
|
||||
### GET `/api/station/history`
|
||||
|
||||
Returns notification history for the last 3 days (latest per station per day).
|
||||
|
||||
### GET `/api/station/siren`
|
||||
|
||||
Returns current siren status for siren-equipped stations (last 3 days).
|
||||
|
||||
### GET `/api/station/siren/history`
|
||||
|
||||
Returns siren history for the last 3 days (excluding Normal level).
|
||||
|
||||
---
|
||||
|
||||
## Alert (Push Notification)
|
||||
|
||||
### POST `/api/alert`
|
||||
|
||||
Sends an FCM push notification. Called by the Python autoscript.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"stationid": "KBLG0026",
|
||||
"level": "Warning",
|
||||
"stationtype": 1
|
||||
}
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `stationid` | string | Station identifier |
|
||||
| `level` | string | Alert level: "Alert", "Warning", "Danger" |
|
||||
| `stationtype` | integer | 1=Rainfall, 2=Water Level, 3=Siren |
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": 200
|
||||
}
|
||||
```
|
||||
|
||||
The `status` is the HTTP status code returned by the FCM API (200 = success).
|
||||
|
||||
---
|
||||
|
||||
## Public Web API
|
||||
|
||||
### GET `/stations`
|
||||
|
||||
Returns all stations with coordinates as JSON (used by the public map).
|
||||
|
||||
### GET `/locale/{locale}`
|
||||
|
||||
Switches language. Valid values: `en`, `bm`. Redirects back to previous page.
|
||||
Reference in New Issue
Block a user