Files
sides/CHANGELOG.md

6.1 KiB
Raw Blame History

Changelog

All notable changes to the SIDES project are documented in this file.


[2026-05-28] — Audit Fix, Configuration & Database Recovery

Security

  • F-01 Parameterized SQL queries in RainfallController::index() — replaced string-interpolated CAST('$dateFilter' AS date) and AND s.stationid = '{$stationFilter}' with ? bindings, eliminating SQL injection vectors
  • F-02 Parameterized SQL queries in WaterLevelController::index() — replaced WHERE s.stationid = '{$stationFilter}' and AND w.datetime = '{$sqlDate}' with ? bindings
  • F-06 Fixed XSS risk in stationmgmt.blade.php — replaced {!! $types ... !!} with e() escaping for translation strings inside badge HTML
  • F-07 Standardized password policy in AdminController — both storeUser() and updatePassword() now use Password::defaults() instead of min:6
  • F-10 Stopped leaking internal exception messages to users — AdminController catch blocks now log errors via Log::error() and return __('toast.error') generic messages; added toast.error translation keys for EN and BM
  • F-23 Added Referrer-Policy: strict-origin-when-cross-origin and Content-Security-Policy headers to Nginx config; changed existing headers to always directive
  • F-24 Added url validation rule for cctv_link in both storeStation() and updateStation(); removed hardcoded http:// prefix from CCTV link in cctv.blade.php

Reliability

  • F-09 Added error handling to FcmService::__construct() — validates credentials file existence, catches JsonException on parse, logs errors, and returns status 500 in sendToTopic() when credentials are unavailable
  • F-11 Added required parameter validation to WaterLevelController::wlHistory(), WaterLevelController::exportHistoricalWl(), RainfallController::historicalRainfall(), and RainfallController::exportHourlyRainfallExcel() — all now validate station, startdate, and enddate before use
  • F-12 Wrapped AdminController::storeStation(), storeUser(), and updateUsers() write operations in DB::transaction() for atomicity
  • F-15 Removed all commented-out dead code blocks from cctvController.php, RainfallController.php, AlertController.php, AppServiceProvider.php, homeapp.blade.php, home.blade.php, usermgmt.blade.php, and threshold.blade.php

Performance

  • F-13 Created migration 2026_05_28_000000_add_performance_indexes.php adding indexes on:
    • rainfall(stationid), rainfall(timestamp), rainfall(stationid, timestamp)
    • waterlevel(stationid), waterlevel(datetime), waterlevel(stationid, datetime)
    • notification(stationid), notification(timestamp), notification(stationtype)
    • siren(stationid), siren(active_time)

Configuration

  • F-18 Created src/.env.example with all documented environment variables (APP, DB, SESSION, CACHE, QUEUE, MAIL, FIREBASE, FCM, POSTGRES, PGADMIN)
  • Created src/.env with populated values: generated APP_KEY, set DB_* matching docker-compose PostgreSQL service, set FIREBASE_PROJECT_ID=sides-b4abb, set FIREBASE_CREDENTIALS path
  • Created root .env for docker-compose with POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD, PGADMIN_EMAIL, PGADMIN_PASSWORD
  • Added src/.gitignore and root .gitignore to exclude .env from version control

Deployment

  • F-19 Removed redundant COPY ./src /var/www/html line from Dockerfile — kept only COPY --chown=www:www ./src /var/www/html; removed commented-out dead lines (RUN curl, RUN tar, COPY fileni)
  • Fixed docker-compose.yml PostgreSQL data directory from /var/lib/postgres/data to /var/lib/postgresql/data and added PGDATA env var
  • Set non-empty POSTGRES_PASSWORD and DB_PASSWORD (was empty, causing PostgreSQL 18 to refuse initialization)
  • Set non-empty PGADMIN_PASSWORD (was empty, causing pgAdmin to crash)

Database Recovery

  • Restored production data from backup/sides_20260528 into the live sides database:
    • users: 4 rows (admin, imam14, ijantck, jpskedah)
    • station: 9 rows (KBLG0025KBLG0033)
    • rainfall: 91,829 rows
    • waterlevel: 137,956 rows
    • notification: 128 rows
  • Made users.email column nullable in migration 0001_01_01_000000_create_users_table.php — existing data has NULL emails for admin and jpskedah
  • Reset all sequence counters to 300,000+ to avoid duplicate key errors from concurrent sensor inserts with explicit IDs

Codebase Assessment

  • Created .planning/codebase/ with 7 structured documents:
    • STACK.md — PHP 8.2, Laravel 12, PostgreSQL 18, Docker/Nginx infrastructure
    • INTEGRATIONS.md — Firebase FCM, PostgreSQL, S3 filesystem, database queue/cache/session
    • ARCHITECTURE.md — MVC pattern, raw SQL over Eloquent, Breeze auth, FCM push alerts
    • STRUCTURE.md — Directory tree, 12 migrations, 8+ tables, dual layout system
    • CONVENTIONS.md — Raw SQL patterns, PSR-12, localization (en/bm), Blade conventions
    • TESTING.md — PHPUnit, near-zero coverage (2 example tests only), no CI
    • CONCERNS.md — 26 findings: 3 critical SQL injections, unauthenticated API endpoints, missing indexes, no audit logging, deployment security gaps

Manual-Only Findings (Not Yet Fixed)

These require design decisions or architectural changes:

# Finding Notes
F-03 Unauthenticated API alert endpoint Requires Laravel Sanctum + rate limiting
F-04 API endpoints without authentication Architectural change across subsystems
F-05 API login without token Requires Sanctum integration
F-08 Inverted block/unblock logic Requires UX redesign of checkbox semantics
F-14 Duplicated dashboard query Requires service class extraction
F-20 PostgreSQL data dir path Already fixed in this session
F-21 Docker security (Dozzle shell, Filebrowser root, pgAdmin exposed) Architecture decisions needed
F-22 No Docker health checks Deployment decisions needed
F-25 No audit logging Low severity, requires design
F-26 No API rate limiting Low severity, requires design