{"id":6559,"date":"2026-07-05T07:27:59","date_gmt":"2026-07-05T00:27:59","guid":{"rendered":"https:\/\/daiilynews.cu.ma\/?p=6559"},"modified":"2026-07-05T07:27:59","modified_gmt":"2026-07-05T00:27:59","slug":"dev-log-2026-07-04","status":"publish","type":"post","link":"https:\/\/daiilynews.cu.ma\/?p=6559","title":{"rendered":"Dev Log: 2026-07-04"},"content":{"rendered":"<p> <br \/>\n<\/p>\n<p>  TL;DR<\/p>\n<p>Two Laravel backends started serving Flutter apps on the same day \u2014 an events platform (auth, orders, offline check-in) and a helpdesk product (ops mode for agents).<\/p>\n<p>gatherhub-web moved to plans-only pricing with a comparison matrix driven by one data file.<br \/>\nA hardening pass: payment-safe queues, gateway reconciliation, one heavyweight dependency dropped.<\/p>\n<p>  Two mobile APIs in one day<\/p>\n<p>Coincidence, but a useful one: two products I&#8217;m building both needed their Laravel backends to serve mobile apps this week.<\/p>\n<p>The events platform got the full foundation \u2014 token auth (login\/refresh\/logout\/me), participant orders, mobile payment with status polling, push-device registration, and an offline-first staff check-in flow. That last one is the interesting bit; I wrote it up as its own post.<\/p>\n<p>The helpdesk product went the other way: its API was client-only, and today it became role-aware. The same endpoints now serve ops agents working tickets from their phones, with abilities deciding what each role sees. One API surface, two personas, no duplicated \/admin routes.<\/p>\n<p>The lesson that repeated in both: API Resources are the contract. The moment a mobile dev consumes your endpoint, every field you accidentally leak becomes a field you can&#8217;t remove.<\/p>\n<p>  Plans-only pricing (public)<\/p>\n<p>gatherhub-web, the Next.js marketing site, dropped \u00e0-la-carte feature pricing for three plans and gained a plan comparison matrix. Everything renders from a single plans.ts \u2014 the matrix, the pricing cards, the enterprise page \u2014 so the marketing site can&#8217;t drift from what&#8217;s actually sold. A pricing page is a contract too; it deserves a single source of truth as much as your API does.<\/p>\n<p>  Hardening pass<\/p>\n<p>Change<br \/>\nWhy<\/p>\n<p>Bulk email blasts isolated to their own queue<br \/>\none big send must never delay a payment webhook<\/p>\n<p>Reconciliation command for stuck pending orders<br \/>\nwebhooks fail silently; polling the gateway is the safety net<\/p>\n<p>maatwebsite\/excel \u2192 spatie\/simple-excel for exports<br \/>\nstreams rows instead of building sheets in memory, smaller dependency surface<\/p>\n<p>Publish readiness enforced on every transition path<br \/>\none invariant in one place, not per-controller checks<\/p>\n<p>  Takeaway<\/p>\n<p>Everything today was the same disease in different organs: drift from a single source of truth. plans.ts on the site, Resources in the API, one readiness gate in the backend. Same medicine everywhere.<br \/>\n<br \/><br \/>\n<br \/><a href=\"https:\/\/dev.to\/nasrulhazim\/dev-log-2026-07-04-4i2h\">Source link <\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>TL;DR Two Laravel backends started serving Flutter apps on the same day \u2014 an events platform (auth, orders, offline check-in) and a helpdesk product (ops mode for agents). gatherhub-web moved to plans-only pricing with a comparison matrix driven by one data file. A hardening pass: payment-safe queues, gateway reconciliation, one heavyweight dependency dropped. Two mobile [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":6560,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[676],"tags":[951,761,765,762,763,764,2099,1093,760,824],"class_list":["post-6559","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tech-ai","tag-architecture","tag-coding","tag-community","tag-development","tag-engineering","tag-inclusive","tag-laravel","tag-php","tag-software","tag-webdev"],"_links":{"self":[{"href":"https:\/\/daiilynews.cu.ma\/index.php?rest_route=\/wp\/v2\/posts\/6559","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/daiilynews.cu.ma\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/daiilynews.cu.ma\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/daiilynews.cu.ma\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/daiilynews.cu.ma\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=6559"}],"version-history":[{"count":0,"href":"https:\/\/daiilynews.cu.ma\/index.php?rest_route=\/wp\/v2\/posts\/6559\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/daiilynews.cu.ma\/index.php?rest_route=\/wp\/v2\/media\/6560"}],"wp:attachment":[{"href":"https:\/\/daiilynews.cu.ma\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=6559"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/daiilynews.cu.ma\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=6559"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/daiilynews.cu.ma\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=6559"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}