Taiwan Data Science Co. · Aug 2018 – Mar 2022

WiSide — Crowd Intelligence Platform

I owned the application and output layers of a Wi-Fi crowd-counting platform that reached 314+ scanners across Taiwan

113,000
NYE 2020 attendees detected
314+
Scanners deployed
22+
Industry exhibitions

Problem

Cities running large outdoor events want a crowd number they can act on while the event is still happening. CCTV counting is expensive and slow to deploy, and it collects far more than a headcount. Our constraint was to count people at scale while collecting nothing personal about any of them.

Architecture

flowchart LR
  subgraph Edge[Edge layer]
    Sensors[Edge Wi-Fi scanners x314+]
  end
  subgraph Storage[Storage layer]
    LS[Logstash ingest]
    ES[(Elasticsearch)]
    KB[Kibana]
  end
  subgraph App[Application layer]
    Web["WiSide site<br/>Laravel + Vue.js"]
  end
  subgraph Out[Output]
    Dash[Real-time dashboard]
    Rep[Event report]
  end
  Sensors -->|MAC hash| LS
  LS --> ES
  ES --> KB
  ES --> Web
  Web --> Dash
  Web --> Rep

My role

I owned the Laravel + Vue.js management backend and the output layer: the real-time dashboard and the event reports. The hardware team and the ELK pipeline team sat on either side of me, and the first thing I pushed for was pinning the query contract before either side started iterating. Hardware iterations are constant on a product like this, and without that contract every one of them would have turned into a backend rewrite. I also designed the data view model for multiple events running at the same time, which is the case that breaks naive dashboards.

Impact

Lessons

I ran WiSide’s application layer and output layer solo. The edge scanners and the ELK pipeline were other people’s work, which meant I lived at the boundary between layers I didn’t control on either side. That taught me something I’ve kept: define the interface contracts first, then let both sides evolve against the contract instead of against each other.

The scanner protocol and the ELK query schema were versioned independently. When the ELK team later upgraded the server, the change got absorbed at the interface layer and the application logic never moved. I’d been designing for now until that project; owning two layers without owning the ones above or below is where I started designing for change.