Files
sides/docs/06-DATABASE.md
root 9122deaacd fix: seeder idempotent with firstOrCreate
Use firstOrCreate instead of create so db:seed can run safely
on container restart without duplicate key violation.
2026-05-21 02:31:47 +08:00

132 lines
4.5 KiB
Markdown

# Database Schema
## Tables
### `station`
Primary table storing telemetry station metadata.
| Column | Type | Description |
|--------|------|-------------|
| `stationid` | `varchar` (PK) | Unique station identifier (e.g., "KBLG0026") |
| `name` | `varchar(255)` | Station display name |
| `district` | `varchar(255)` | District location |
| `lng` | `float` | Longitude coordinate |
| `lat` | `float` | Latitude coordinate |
| `mainriverbasin` | `varchar(255)` | Main river basin name |
| `subriverbasin` | `varchar(255)` | Sub river basin name |
| `rainfall` | `integer` | Has rainfall sensor (1=yes, 0=no) |
| `waterlevel` | `integer` | Has water level sensor (1=yes, 0=no) |
| `siren` | `integer` (nullable) | Has siren (1=yes, 0=no) |
| `cctv_link` | `varchar(500)` (nullable) | URL to CCTV feed |
### `rainfall`
Stores rainfall readings from telemetry stations.
| Column | Type | Description |
|--------|------|-------------|
| `id` | `bigint` (PK, auto) | Auto-increment ID |
| `stationid` | `varchar` | Station identifier (FK to station) |
| `timestamp` | `timestamp` | Reading timestamp |
| `anncum` | `double` | Annual cumulative rainfall |
| `daily` | `double` | Daily cumulative rainfall |
| `hourly` | `double` | Hourly rainfall |
| `currentrf` | `double` | Current rainfall |
| `battery` | `double` | Battery voltage |
### `waterlevel`
Stores water level readings with threshold values.
| Column | Type | Description |
|--------|------|-------------|
| `id` | `bigint` (PK, auto) | Auto-increment ID |
| `stationid` | `varchar` | Station identifier (FK to station) |
| `datetime` | `timestamp` | Reading timestamp |
| `waterlevel` | `double` | Current water level (meters) |
| `alert` | `double` | Alert threshold level |
| `warning` | `double` | Warning threshold level |
| `danger` | `double` | Danger threshold level |
### `siren`
Stores siren activation records.
| Column | Type | Description |
|--------|------|-------------|
| `id` | `bigint` (PK, auto) | Auto-increment ID |
| `stationid` | `varchar` | Station identifier (FK to station) |
| `stationtype` | `varchar` | Station type identifier |
| `active_time` | `timestamp` | Siren activation time |
| `level` | `varchar` | Siren level (`H`=Danger, `L`=Warning, `N`=Normal) |
### `notification`
Stores threshold-exceeded alert records.
| Column | Type | Description |
|--------|------|-------------|
| `id` | `bigint` (PK, auto) | Auto-increment ID |
| `stationid` | `varchar` | Station identifier (FK to station) |
| `timestamp` | `timestamp` | Alert timestamp |
| `stationtype` | `integer` | Type: 1=rainfall, 2=waterlevel, 3=siren |
| `level` | `varchar` | Alert level (Alert, Warning, Danger) |
| `active_time` | `timestamp` (nullable) | Activation time |
### `users`
Stores application users.
| Column | Type | Description |
|--------|------|-------------|
| `id` | `bigint` (PK, auto) | Auto-increment ID |
| `name` | `varchar(255)` | Username |
| `email` | `varchar(255)` (unique) | Email address |
| `email_verified_at` | `timestamp` (nullable) | Email verification timestamp |
| `password` | `varchar(255)` | Bcrypt-hashed password |
| `access_level` | `integer` | 1=Admin, 2=User |
| `is_blocked` | `boolean` | Account blocked status |
| `login_attempts` | `integer` | Failed login attempt count |
| `remember_token` | `varchar` | Remember me token |
| `created_at`, `updated_at` | `timestamp` | Laravel timestamps |
### Laravel Standard Tables
- `password_reset_tokens` — Password reset tokens
- `sessions` — Database-backed sessions
- `cache` / `cache_locks` — Cache store
- `jobs` / `job_batches` / `failed_jobs` — Queue system
- `migrations` — Migration tracking
## Relationships
```
station (1) ──< (many) rainfall via stationid
station (1) ──< (many) waterlevel via stationid
station (1) ──< (many) siren via stationid
station (1) ──< (many) notification via stationid
```
**Note**: No database-level foreign keys or constraints exist. All relationships are maintained at the application level.
## Indexes
- `users.email` — unique index
- `sessions.last_activity` — index
- `sessions.user_id` — index
- No additional indexes on data tables (potential performance concern)
## Default Data
### Default Admin User
Created via `DatabaseSeeder` and migration `2025_12_11_124201_add_default_user_to_users_table.php`:
- **Username**: `admin` (seeder) / `admin` (migration)
- **Email**: `admin@example.com`
- **Password**: `password123`
- **Access Level**: 1 (Admin)
**Note**: The admin user is created in both the seeder AND a migration, which would cause a duplicate key error if both run.