DEV Community

Koustubh
Koustubh

Posted on

Part 2: Building Station Station - A Real-World SDD Case Study

In Part 1, I introduced Spec-Driven Development and explained how it provides a structured alternative to the AI chat trial-and-error loop. Now let's get concrete. This is the story of building Station Station—a real application that solves a real problem I face as a Melbourne train commuter working hybrid.

This isn't a contrived demo or a toy project. It's a fully functional web application I use regularly, built in about 3 days using the agent-os SDD workflow, now live at https://koustubh25.github.io/station-station/. In this part, I'll walk you through the problem it solves, the technical architecture, the 8-feature roadmap we shipped, and the real challenges we encountered along the way.

The Problem: Hybrid Work Compliance Meets Train Commuting

My company, like many post-pandemic workplaces, has a hybrid policy: 50% office attendance required. Sounds reasonable, right? But here's the catch—there's no automated way to track whether I'm meeting that threshold.

My manager periodically notifies me of my compliance status—"You're at 42% this month, need to increase office days"—but by then, I'm already behind. I have no visibility into my attendance until someone tells me I'm non-compliant.

The real problem isn't just manual tracking—it's reactive tracking. I want to proactively manage my hybrid schedule: "It's mid-month and I'm at 48%, so I should go to the office this week to stay on track." Or "I'm at 55%, so I can safely work from home the rest of the month."

This kind of strategic planning requires real-time visibility into my attendance data, not periodic manager notifications. The advantages of tracking this myself:

  • Autonomy: Control my schedule instead of reacting to manager feedback
  • Strategic planning: Make informed WFH decisions based on current compliance
  • Avoid surprises: Never get caught off-guard by non-compliance notifications
  • Flexibility: Balance office days with personal needs (appointments, errands, weather)

This is exactly the kind of repetitive, rule-based task that should be automated. But the Myki portal doesn't offer attendance tracking—it's designed for viewing transactions, not inferring work patterns. No third-party tools exist because the Myki API is undocumented and protected by Cloudflare bot detection.

Perfect problem space for a personal automation project.

The Solution: Automated Attendance Tracking from Transit Data

Station Station automatically determines office attendance by analyzing Myki transaction data. The core logic is simple: if I tapped on or off at my designated work station on any given day, that counts as an office day. The application handles the complexity of data extraction, date calculations, and visualization.

Here's the architecture:

Data Extraction Layer (Python + Playwright)

  • Headless browser automation bypasses Cloudflare Turnstile bot detection using browser profile trust signals
  • Authenticated session extracts cookies and Bearer tokens for API calls
  • Transaction history retrieved for user-specified date ranges
  • Data parsed and normalized into structured JSON format

Processing Layer (Python)

  • Attendance logic analyzes transactions to identify work station visits
  • Configurable rules support:
    • Work days: Default Monday-Friday, customizable per user
    • Skip dates: Exclude specific dates (sick leave, planned vacation, public holidays)
    • Manual attendance dates: Override for days you attended work without taking the train (drove to work, carpooled, etc.)
  • Monthly aggregations calculate attendance statistics and percentages
  • JSON storage provides data persistence with optional GitHub backup for version history

Presentation Layer (React + Tailwind CSS v4)

  • Interactive calendar displays attended days with color-coded indicators
  • Monthly bar chart visualizes attendance trends over time
  • Summary dashboard shows attendance percentage, working days, and days attended/missed
  • Date range filtering allows focused analysis of specific periods
  • Public holidays automatically detected and displayed for context
  • Fully responsive design optimized for mobile (my primary use case)

Deployment (GitHub Pages)

  • Static site deployment—no backend hosting required
  • React app consumes JSON data generated by Python backend
  • GitHub Actions automates data updates and deployment
  • Zero ongoing hosting costs

Fully Autonomous Operation

This is the crucial part: once configured, the system runs completely autonomously. Every day, GitHub Actions automatically:

  1. Spins up a Docker container
  2. Authenticates with the Myki portal
  3. Fetches new transaction data
  4. Calculates updated attendance statistics
  5. Commits the updated JSON to the repository
  6. Deploys the refreshed dashboard to GitHub Pages

I don't touch anything. I just open the dashboard URL on my phone each morning and see my current attendance percentage. No manual data entry, no clicking through the Myki portal, no spreadsheet updates. The app handles everything from data extraction to visualization without human intervention.

And it's completely free. GitHub Actions provides 2,000 free minutes per month for private repositories (unlimited for public repos), GitHub Pages hosting is free, and the entire stack runs on free tiers. Zero ongoing costs for a fully automated daily workflow.

The beauty of this architecture is its separation of concerns: Python handles the complex authentication and data extraction (runs locally or in GitHub Actions), React handles the user-friendly visualization (deployed statically), and JSON serves as the contract between them.

The Roadmap: 8 Features Across 3 Phases

Here's exactly what we built, broken down into three logical phases:

Phase 1: Foundation (Authentication & API Discovery)

  1. Myki Authentication & Cloudflare Bypass (Large, 2 days)

    • Browser automation with Playwright to bypass Cloudflare Turnstile detection
    • Profile-based trust signals (copy Chrome profile data) to appear as legitimate user
    • Multi-step authentication flow to extract session cookies and Bearer token
    • Critical blocker—nothing else could work until this was solved
  2. Transaction History API Reverse Engineering (Medium, 1 day)

    • Network traffic analysis to identify undocumented Myki API endpoints
    • Request header mapping (x-ptvwebauth, x-verifytoken, authorization Bearer)
    • Response parsing to extract transaction data
    • Session persistence handling (Bearer token expires after ~20 minutes)

Phase 2: Data Layer (Extraction & Processing)

  1. Myki SDK / Data Retrieval - Browser-based (Medium, 1 day)

    • Browser-based scraping as fallback (API reverse engineering had limitations)
    • Transaction data parsing (station names, timestamps, tap on/off events)
    • Date range query support for historical data retrieval
  2. Card Selection & Date Range Handling (Small, <1 day)

    • Programmatic Myki card selection from user's registered cards
    • Configurable date range parameters for transaction queries
    • Input validation and error handling
  3. Attendance Logic & JSON Storage (Medium, 1 day)

    • Station-based attendance detection (checks if user visited their designated work station)
    • Daily and monthly attendance aggregations
    • Skip dates support for planned absences
    • Manual attendance override for non-PTV commutes (drove to work)
    • Structured JSON output with separate sections for clarity

Phase 3: Integration & UI (Visualization & Configuration)

  1. GitHub Integration for Data Backup (Small, <1 day)

    • Optional GitHub repository integration for data version control
    • Automated commits and pushes via GitHub Actions
    • Historical tracking and audit trail
  2. React Frontend Dashboard (Medium, 1 day)

    • Interactive calendar component with attended days highlighted
    • Monthly statistics bar chart for trend analysis
    • Summary dashboard (attendance %, working days, days attended/missed)
    • Date range filtering with react-datepicker integration
    • Public holidays display using date-holidays library
    • Fully responsive mobile-first design with Tailwind CSS v4
    • Live at: https://koustubh25.github.io/station-station/
  3. Configuration Management & User Setup (Small, <1 day)

    • GitHub secrets for secure credential storage (MYKI_USERNAME, MYKI_PASSWORD, MYKI_CARDNUMBER)
    • Config files for attendance settings (target station, skip dates, manual dates)
    • Multi-user support with user-specific configuration
    • Setup documentation and README

The Cloudflare bypass was the critical path item. Once we solved that authentication challenge on Day 1-2, the rest of the features flowed in rapid succession. This is the power of proper sequencing—identifying technical blockers early and solving them first unlocks everything downstream.

Try It Yourself

The application is live at https://koustubh25.github.io/station-station/. You'll see my actual attendance data (with privacy considerations—no personal identifiers exposed). The dashboard shows:

  • Attendance Calendar: Interactive monthly view with attended days highlighted in green
  • Monthly Statistics: Bar chart showing attendance trends across months
  • Summary Dashboard: At-a-glance metrics (attendance percentage, working days, days attended/missed)
  • Date Range Filtering: Focus on specific periods for detailed analysis
  • Public Holidays: Automatically displayed for context (Victoria, Australia)

The repository is public at https://github.com/koustubh25/station-station (if you want to deploy this yourself—more on that in Part 5). The frontend is fully responsive, so try it on your phone. That's where I use it most—quick morning check to see my monthly progress.

Key Technical Challenges

Let me highlight the three biggest technical challenges we faced. These weren't abstract problems—they were real blockers that required careful problem-solving.

1. Cloudflare Turnstile Bypass

The Myki portal is protected by Cloudflare Turnstile, which actively detects and blocks headless browsers. Our first attempt using standard Playwright headless mode failed immediately with the "Verifying you are human..." overlay blocking form access.

The solution: browser profile trust signals. Playwright launches with an empty Chrome profile directory structure (Cookies, Preferences, History, Web Data, Login Data files), which provides just enough profile metadata to appear as a real browser without containing any actual user data. This runs on GitHub Actions runners, so there's no risk to user credentials—it's a fresh environment each time. Cloudflare recognizes the profile structure as legitimate traffic. Running in headed (visible) mode rather than headless also helps avoid automation detection signals.

This was the critical blocker for the entire project. Without solving Cloudflare bypass, we couldn't access any Myki data. It took domain knowledge of browser fingerprinting and creative problem-solving—not something AI could generate from patterns alone.

2. API Reverse Engineering

The Myki transaction API is completely undocumented. We had to analyze browser network traffic to identify endpoints, required headers, and authentication patterns.

Key discoveries through network analysis:

  • Bearer token location: extracted from authentication response data.token field
  • Required headers: x-ptvwebauth, x-verifytoken, x-passthruauth, authorization: Bearer <token>
  • Token expiration: ~20 minutes, requires re-authentication for long-running sessions
  • Request structure: specific query parameters for date ranges and card selection

Here's a snippet of the authentication configuration:

// myki_config.json structure
{
  "users": {
    "username": {
      "targetStation": "Your Work Station Name",
      "skipDates": ["2025-12-25", "2026-01-01"],
      "startDate": "2025-04-15",
      "manualAttendanceDates": ["2025-11-03"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

AI could implement the API client once we documented these patterns in the spec. But identifying which headers were critical, understanding token lifetime, and mapping the authentication flow required human analysis of network traffic.

3. Transaction Parsing and Attendance Logic

Inferring office attendance from train transactions required clear, simple logic. The core rule: "Did the user visit their work station on this date?"

Our solution:

  • If any transaction on date D involves the user's designated target station, count D as attended
  • Card type, fare type, transaction status - none of that matters for attendance detection
  • Skip dates: Explicitly exclude dates that shouldn't count (sick leave, planned vacation). Public holidays are automatically detected and excluded using Victoria, Australia's holiday calendar. For example, if I'm sick on a Tuesday, I add that date to skipDates so it doesn't count against my attendance percentage.
  • Manual attendance dates: Override for days I attended work but didn't take the train. For instance, if I drove to work or carpooled, there's no Myki transaction, but I still want it counted as an office day. I add that date to manualAttendanceDates.

This handles the edge cases that real-world commuting brings. Some weeks I drive because I need my car for errands after work. Some days I'm sick or on vacation. The configuration system makes it easy to adjust attendance tracking to match reality, not just train transactions.

This domain-specific logic required human understanding of the problem space and business rules. AI could generate the code structure, but the attendance rules came from me knowing how I actually commute and what counts as "attendance."

What We Actually Built

So what does ~3 days of structured development look like in practice? Here's what we ended up with:

The codebase is about 6,000 lines—roughly 3,500 lines of Python for the backend extraction and processing logic, and 2,500 lines of React/CSS for the frontend dashboard. That's 8 UI components, 3 custom React hooks, and a handful of utility modules.

Performance-wise, it's pretty snappy. Lighthouse scores are in the 95+ range across the board (accessibility hits 100). The bundle is 65KB gzipped, loads in under a second on 3G, and becomes interactive in under 2 seconds. Not bad for a dashboard with charts and calendars. The frontend doesn't do any complex calculations—all the heavy lifting (attendance logic, date processing) happens in Python during the data extraction phase. The React app just renders pre-computed JSON.

I built this in about 3 days of active development. That includes writing the specs upfront, breaking down tasks, implementing features, and deploying to GitHub Pages. The upfront time spent on specs definitely paid off—I had way fewer "wait, what was I supposed to build here?" moments compared to my usual side projects.

Is this faster than just prompting Claude directly? Honestly, probably not for the initial code generation. But debugging was way easier because I could reference the spec when something didn't work. And when I came back to add the manual attendance feature a week later, the spec told me exactly where to hook it in. That's where the structured approach actually saves time.

What's Next

We've seen the Station Station project: the problem it solves, the architecture, the 8-feature roadmap, and the technical challenges. We have a live application built in 3 days using agent-os SDD.

But how did we actually build this? How does the agent-os workflow translate requirements into specs, specs into tasks, and tasks into working code? That's what Part 3 will explore in detail.

In Part 3, we'll walk through the complete agent-os workflow: creating a product, shaping specifications, writing detailed specs, breaking down tasks, and implementing features with AI assistance. We'll use actual Station Station examples to show how each phase works and where human review happens.

If you're curious how a structured workflow can make AI assistance predictable instead of frustrating, Part 3 is where we dive deep into the mechanics.

Top comments (0)