Every Role I've Played — Junior to CTO, What I Actually Did at Each Level

I shipped real features to real users. I broke production and fixed it alone at 2 AM. I built a mobile banking app with 680K downloads, a mining fleet system saving $200K/year, and a field operations platform for 4.1M users. This is what mid-level engineering actually looks like — the projects, the metrics, and the production incidents that made me a real engineer.

"Mid-level is where you stop writing code that works and start writing code that survives." — Me, after the 14th production rollback
The mid-level years transform you from "someone who can code" to "someone who can ship." The shift is fundamental: you stop being evaluated on whether your code runs. You're evaluated on whether your code survives production — at scale, under load, when things go wrong at 3 AM.
Before (Junior): "Can you write code that works?" Now (Mid): "Can you own a feature end-to-end — design, build, test, deploy, monitor, debug, and iterate — without someone holding your hand?"
Role: Solo Backend Engineer Stack: Go, Flutter, ISO 8583, PostgreSQL Scale: 680K+ Google Play downloads, zero downtime during Eid transaction rush
This was my first "real" production system. Not a WordPress site. Not a CRUD app. A mobile banking application that had to integrate directly with a bank's core system via ISO 8583 protocol.
What happened: During the Eid al-Fitr holiday (highest transaction volume of the year), the ISO 8583 bridge started timing out on 30% of requests. The bank's mainframe was responding correctly — our bridge was the bottleneck.
Root cause: We were opening a new TCP connection for every ISO message. At 500+ concurrent requests, the connection pool exhausted. The fix was implementing persistent connections with health checks.
Lesson: Protocol-level integration isn't "just another API." ISO 8583 has quirks around connection management, byte ordering, and field encoding that will destroy you if you treat it like REST.
What happened: Payment reminders stopped sending. 0% delivery rate for 6 hours. Users missed payment deadlines and were charged late fees.
Root cause: Firebase Cloud Messaging tokens expire every 30 days. We stored tokens on first login but never refreshed them. Simple fix — but took 6 hours to diagnose because the error logs were buried in Firebase's dashboard, not our monitoring.
Lesson: External service dependencies need health checks in YOUR monitoring, not theirs. If you depend on Firebase, monitor Firebase.
| Metric | Before | After |
|---|---|---|
| App downloads | 0 | 680K+ |
| Transaction processing time | 3-5 business days (manual) | Real-time |
| Late payment rate | 22% | 18% |
| System uptime | N/A (new system) | 99.7% |
Role: Full-Stack Engineer Stack: Go microservices, React PWA, MQTT, PostgreSQL Scale: 3 provinces, 100+ trucks, 50K telemetry events/second
This was my introduction to IoT — and everything I thought I knew about "reliable systems" got tested against reality: remote mining sites with intermittent satellite connectivity, GPS trackers that report garbage data, and users who've never used a smartphone before.
We bought 50 GPS trackers from a reputable vendor. 12 of them reported coordinates that were physically impossible — trucks "teleporting" 500 meters in 2 seconds. After 2 weeks of debugging our code, we discovered: the trackers were configured to report at 1Hz (once per second), but when they lost satellite lock, they'd buffer readings and dump them all at once when reconnected. Our system interpreted the burst as real-time data.
Fix: Server-side velocity validation. If a coordinate change implies >120 km/h for a mining truck, flag it and use the last known good position. Saved us from chasing phantom trucks for a month.
Mining sites in remote Kalimantan have connectivity that makes 3G look like fiber. We designed for "eventual connectivity" — MQTT with QoS 1, local SQLite buffer on edge gateways, batch upload when the satellite link comes back. The architecture worked, but we underestimated how long the "offline window" actually was: sometimes 6-8 hours.
Lesson: Design for the worst-case offline window, not the average. Your users won't care that "on average" connectivity is good if their 8-hour shift ends without data sync.
| Metric | Before | After |
|---|---|---|
| Truck utilization | 65% | 79% |
| Fuel theft incidents | Unknown (undetected) | Detected in month one |
| Annual savings | — | Rp 3.2B ($200K) |
| HSE report turnaround | 5 days (paper) | Real-time (digital) |
Role: Solo Full-Stack Engineer Stack: Go monolith, Flutter mobile, SQLite, MQTT Scale: 4.1M end-users, built solo in 30 days
This was the project that taught me the difference between "building" and "owning." When you're the only developer, there's no backend team to blame when the database is slow. No frontend team to fix the UI. No DevOps team to handle deployment.
| Metric | Before | After |
|---|---|---|
| Data loss rate | 23% | 0% |
| End-users served | 0 | 4.1M |
| Time to build | N/A | 30 days (MVP) |
| Financing decision time | 3-5 business days | Real-time |
| Portfolio Item | Did I Do It? | Notes |
|---|---|---|
| 2-3 work case studies | ✅ | SiTepat, HPU, Tepati — all with measurable impact |
| Measurable metrics | ✅ | 680K downloads, 65→79% utilization, 23% data loss eliminated |
| Open source contribution | ❌ | Biggest career gap — started too late |
| Technical articles | ⚠️ | Wrote internal documentation, never published publicly |
| Production incident handling | ✅ | Survived 4 major incidents, learned more from them than any feature |
Mid-level is the most underrated career stage. It's where you accumulate the production scars that make your senior portfolio authentic. Every incident, every rollback, every 2 AM fix — that's not trauma. That's content.



