Index / Work
Adriatic Sea — Oceanographic station network · Croatian Hydrographic Institute
Environmental monitoring platform

Adriatic SeaOceanographic station network · Croatian Hydrographic Institute

A monitoring platform built for the Croatian Hydrographic Institute that collects, manages and publishes oceanographic and meteorological data from a network of stations along the Adriatic coast. It ingests raw instrument files, stores measurements per station, drives a threshold alarm system, and serves live-updating station pages and a JSON / GeoJSON map API. Work done for the Institute — the platform and its data are the Institute's.

Adriatic Sea is a platform I built for the Croatian Hydrographic Institute to run its network of coastal monitoring stations. It is a Yii 2 advanced-template application: an authenticated admin backend where staff manage stations, upload instrument data and configure alarms, a public portal that shows designated stations to anyone, and a JSON / GeoJSON API that feeds a live map of the Adriatic coast.

The data model is shaped by the instruments. Five station types — tide, wave, wind, pressure and meteorological — each write into their own per-station database table, so wildly different measurements coexist without a sprawling shared schema. Tide readings are calibrated against managed mareo zero reference levels before they are shown, a threshold alarm system flags out-of-range values with colour coding and email alerts, and the whole interface runs bilingually in Croatian and English.

The public station pages stay current through interval polling rather than server push: a 30-second countdown drives an incremental fetch that asks the server only for measurements newer than the last point already on the chart, and a freshness indicator warns when a station’s latest reading is more than fifteen minutes old. It’s the right amount of machinery for data that arrives on a steady cadence.

This is work done for the Institute, not a personal project — the platform, the station network and the data belong to the Croatian Hydrographic Institute. The counts and capabilities above are taken directly from the source, and where the codebase carries a dependency it does not actually use, it has been left out rather than claimed.

RoleFull-stack development (work for the Institute)
Year2017
Core stackYii 2 · PHP · MySQL
SurfaceAdmin backend + public portal + map API
OwnerCroatian Hydrographic Institute
Public map of the Adriatic coast with live tide, wave, wind and pressure station markers
Screenshot soon
Ingestion

Raw instrument files, parsed into per-station tables

Each station uploads measurement files (CSV / DAT) which are parsed and written into a database table named for that station and type. A tide station writes to its own tide table, a wave station to its own wave table, so heterogeneous instruments coexist without one giant shared schema.

  • Table name resolved per station from type: {designation}_tide_data, _wave_data, _wind_data, _pressure_data, _meteo_data
  • Five instrument families: tide, wave, wind, pressure, meteorological
  • File upload and date-range views handled in the admin backend
Screenshot soon
Live map API

A JSON / GeoJSON feed for the public coastal map

A frontend API endpoint walks every station flagged for export, pulls its latest measurement with raw SQL tuned per instrument type, and returns it as JSON or as a GeoJSON FeatureCollection ready to drop onto a Leaflet-style map.

  • Latest tide / wave / wind / pressure value per station, formatted server-side
  • Tide stations also return the next predicted high/low (extrema) relative to mareo zero
  • GeoJSON Feature geometry + properties built per station for direct map consumption
Screenshot soon
Live updates

Station pages that refresh themselves every 30 seconds

A station's page doesn't sit still: a 30-second countdown drives a polling loop that asks the server only for measurements newer than the last point already plotted, appends them to the chart, and updates the latest-reading and server-time readouts. It's deliberate interval polling, not server push — simple, robust, and right-sized for the data's cadence.

  • Visible 30-second countdown re-fetches on each cycle (common.js dataCounter)
  • Incremental fetch: posts the last plotted timestamp and receives only newer rows
  • Flags the reading stale (warning state) when the latest data is over 15 minutes old
Screenshot soon
Alarms

Threshold alerts with colour coding

Operators define named alarms per station and measured field — a threshold value, a colour, and whether it is a minimum or a maximum. When a station's readings cross the line, the alarm surfaces visually and notifications go out by email.

  • Per-station, per-field threshold with a min/max flag (Alarms model)
  • Hex colour code per alarm for at-a-glance severity
  • Email delivery via SwiftMailer
Screenshot soon
Tide datums

Mareo zero references for honest tide levels

Tide readings are meaningless without a datum. The platform manages mareo zero reference levels per station, so a raw sensor value is calibrated to a real, comparable tide level before it is shown or exported.

  • MareoZeroes reference values stored per station and code (e.g. H0)
  • Measured and predicted levels computed relative to the station's zero
  • Keeps stations on different physical datums comparable
Screenshot soon
Access & audit

Contract-based access and a public portal

Behind login, a role system ties users to the stations they are entitled to via contracts, with actions written to an audit log. In front of it, a public portal exposes only the stations marked public — read-only, no account required.

  • Superadmin and user roles; contract-based station entitlements
  • Audit logging of administrative actions
  • Unauthenticated public view of designated stations
Screenshot soon
Export & i18n

Data export and a bilingual interface

Historical measurements can be filtered by date range and exported to delimited text for downstream scientific use, and the whole interface runs in Croatian and English from a single i18n source.

  • Per-type export models (Tide / Wave / Wind / Pressure) to delimited text
  • Date-range filtering over a station's full history
  • hr-HR and en-US from one set of message files
Architecture

A three-tier Yii 2 application over a MySQL store of per-station tables, publishing a map-ready API for a public portal.

Client
Admin backend + public portal
Authenticated admin (stations, uploads, alarms, users) and an unauthenticated public live view of designated stations.
Application
Yii 2 — backend / frontend / console
MVC tiers sharing common models; the frontend serves the public portal and the JSON / GeoJSON map API.
Ingestion
Instrument-file parsing
Uploaded CSV / DAT files are parsed and written into the per-station data table for their type.
Data
MySQL · per-station tables
Each station + type owns its own table; mareo-zero references and alarms calibrate and watch the readings.
Challenges solved
01

Storing five instrument families without one unwieldy schema

Problem

Tide, wave, wind, pressure and meteorological instruments emit completely different measurements. A single shared measurements table would be a sparse, type-checked mess, and every query would have to branch on station type anyway.

Solution

Each station writes to its own table, named from its designation and type (e.g. {code}_tide_data). The Stations model resolves the right table name on demand, so the rest of the app treats a station as a typed source and reads exactly the columns that instrument produces.

02

Turning raw sensor values into a public live map

Problem

The coastal map needs the latest reading per station, formatted and meaningful, but the readings live in many type-specific tables and tide values are useless without their datum.

Solution

A single API endpoint iterates exportable stations, runs per-type SQL for the latest measurement, and — for tide — calibrates against the station's mareo zero and computes the next predicted extrema. The result is emitted as JSON or a GeoJSON FeatureCollection the map can render directly.

03

One platform, two audiences, one source of truth

Problem

Scientists at the Institute need full administrative control and entitlement boundaries; the public needs a safe, read-only window — without standing up a second application or duplicating data.

Solution

Yii 2's advanced template splits an authenticated backend from a public frontend over shared common models. Contract-based access and audit logging fence the admin side, while the public portal and map API expose only stations explicitly flagged public — same data, two doors.

How it's built
Application
Yii 2 (Advanced Template), PHP, MVC across backend / frontend / console tiers
Data
MySQL, Per-station dynamic tables, Raw instrument-file ingestion (CSV / DAT)
Output & API
JSON API, GeoJSON FeatureCollection, Delimited-text export, SwiftMailer alerts
Platform & quality
Role-based access (RBAC), Audit logging, Bilingual i18n, Vagrant dev environment

Sensor files in, a calibrated public coastal map out — built for the Institute that owns it.