Mesai Defteri: overtime tracking that follows the law
Flutter · Android · Google Play · 88 tests




The problem
Turkish labor law counts overtime against a 45-hour week, not a monthly total. Someone who works 52 hours one week and 35 the next looks normal on a monthly sum, yet is owed 7 hours of overtime. Many overtime apps miss this.
What I built
Workers enter each shift as a start and end time with a break. The app shows weekly overtime, night hours and the pay they are owed, with the law article behind each number (Labor Law 4857, articles 41, 47, 63 and 69). Data stays on the phone: no account, no server.
Key decisions
- The math lives alone. One pure Dart module holds every rule and knows nothing about widgets. Screens depend on it, never the other way round, so the core claim of the app is testable in isolation.
- Edge cases first. Shifts that cross midnight, night work between 20:00 and 06:00, the 11-hour daily cap, the 270-hour yearly cap. Each is a named test.
- Errors that explain themselves. A missing time, a reversed range or a break longer than the shift each gets its own error type, so the screen can say how to fix it.
- Tablets are first-class. A wide layout puts the breakdown and settings side by side. Testing on a 7-inch tablet showed the 600 dp breakpoint was wrong in portrait; I moved it and added golden screenshots so it stays fixed.
The release-build crash
The first production build crashed before the first screen. R8, Android’s code shrinker, had removed the database class of WorkManager, a library pulled in by the ads SDK. Debug builds are not shrunk, so tests and manual checks never saw it.
I read the stack trace, added a keep rule to the ProGuard configuration, and walked the release build through every screen on a real device. Every release is now tested as a release build before upload.
Proof
- 88 automated tests, including 16 golden screenshots for phone and tablet.
- Published on Google Play through a Fastlane lane, store listing and Data Safety form included.
- Turkish time pickers and dialogs through Flutter’s localization, so no “OK / Cancel” leaks into a Turkish interface.
Stack: Flutter, Dart, shared_preferences, intl, Google Mobile Ads, Fastlane
Need this kind of work on your app? Email muhammedsaidcakir@msclabs.tr.