Log retention settings that quietly become one of your largest bills
CloudWatch log groups left on infinite retention can grow into thousands of rupees per month without any visible traffic increase.
Insights from building and maintaining production systems. We share what we've learned about software development, long-term maintenance, and the philosophy behind our approach.
CloudWatch log groups left on infinite retention can grow into thousands of rupees per month without any visible traffic increase.
The order in which multi-tenant systems usually fail as they approach a thousand users, based on what we see maintaining them.
Source maps uploaded to Sentry turn minified bundle stack traces into readable file and line references for React Native field apps.
A field-services app we ship to iOS and Android needs the keyboard to never cover the input the user is typing into. Here is the approach we use on both platforms.
How we keep tenant-specific feature flags from hardening into divergent code paths that nobody can merge back.
How we handle coupon stacking, shared codes, and edge cases for Indian e-commerce storefronts without losing money or customers.
How we keep AWS least-privilege IAM workable for small teams without a dedicated ops person or permissions bureaucracy.
Handling partial renders, cancellation, and reconnection when piping LLM output into an existing product's frontend.
How we handle background location for field-staff apps on low-end Android hardware without draining battery or triggering Play Store rejections.
How we trace Next.js bundle weight to specific modules and decide which fixes are worth shipping to users on mid-range Android phones.
Building optimistic updates for mid-range Android phones on uneven connections, with rollback that actually tells the user what happened.
Building a self-serve export endpoint into a multi-tenant SaaS so customers can pull their data, and how that changes renewal conversations.
How a small team measures LLM output quality without a research team, using a fixed labelled set and a repeatable scoring script.
Most rewrites are avoidable. We look at the one case where a rewrite was correct and the common cases where fixing in place costs less.
What we do when a customer's connection drops between the payment gateway and the order confirmation page.
The specific Play Store policy clauses that reject our field-staff React Native apps, and what we change to get through review.
How we keep clients informed with a written Friday note and a Monday call block, without a standing meeting nobody needs.
Why viewport breakpoints fail for admin panel widgets reused across layouts, and how container queries fix it without JS.
Why we build ERP and CRM systems around how an organisation actually works, and where we push back when the existing process costs more than it saves.
Designing e-commerce admin interfaces for non-technical staff means removing features they never need and naming things in their vocabulary.
How we handle payment failures in multi-tenant SaaS: retry timing, grace windows, and the decision to actually cut off access.
What we learned wiring a vision model into an accounts-payable workflow, and the three fields where a human still reviews.
How to configure an EC2 autoscaling group for an admissions portal whose traffic jumps 40x for two weeks and stays flat the rest of the year.
How we handle document capture, compression, and resumable uploads for field staff on low-end Android hardware with unreliable connectivity.
Building a live search input that handles slow networks and mid-range phones without showing stale results or flooding the API.
Building an audit log that end users can search and understand, instead of a table only your support team can query.
How we build school ERP systems so grading rules and workflows are documented in the system itself, not in one admin's head.
Our default stack choices and the three places we deliberately reach for something newer or more complex.
How we handle cache invalidation in deploys without wildcard costs or stale-asset tickets.
Why your storefront's shipping charges drift from what the courier actually bills, and how to close the gap without a rate card maintenance nightmare.
Designing fallback behavior for model-backed features before rate limits and outages force you to ship it overnight.
How we run a blameless postmortem when the whole team fits in one room and a formal template would be theatre.
Auth checks in Next.js middleware redirect loops, static asset edge cases, and what we do differently for users on uneven connections.
Managing embedding regeneration when the documents your vector search relies on are edited every week, without rebuilding the entire index.
Generating printable report cards that align on paper for a school's existing hardware, not an idealised spec.
A VPC layout for a single web application that stays manageable without a dedicated ops person watching it.
How we handle partial refunds in e-commerce systems, including the effect on tax, shipping, and the double-entry ledger behind every order.
What you can change in a React Native app over the air, what you can't, and where the App Store draws the line on OTA updates.
Practical rendering strategies for large admin tables on mid-range Android browsers, and when virtualization adds more cost than it saves.
How a small team spends the first week taking over an unfamiliar codebase — reading, mapping, and not touching production.
Building audit logs for school ERP records that inspectors can verify years after the fact requires deciding what is reconstructable and what is not.
How we run additive migrations, backfill, and back-out swaps across tenant databases without taking the app offline.
Building e-commerce search that handles typos, transliteration, and regional names without a heavy infrastructure investment.
How to surface model reasoning to users through structured metadata and confidence scores instead of raw prompt internals.
Storing JWTs in AsyncStorage breaks the secure storage contract on both platforms. Here is what to use instead.
A practical look at which user-facing paths actually suffer from Lambda cold starts and which worries are misplaced.
How we keep a large React admission form responsive on mid-range Android phones by splitting state and deferring validation.
How we score match likelihood in a school CRM so duplicate contacts get flagged but two people with similar names don't get merged.
Which trial conversion features to build early and which to defer until there is actual data telling you otherwise.
A concrete breakdown of what happens under a maintenance arrangement — monitoring, fixes, small changes, and the work that falls outside it.
How we rotate AWS Secrets Manager passwords for RDS instances while the application keeps serving traffic.
A prompt is a build artifact. Treating it like code means you can find what broke and revert without guessing.
Most cart abandonment metrics are noise. Here is the instrumentation you need before the numbers mean anything.
Where you fetch in Next.js App Router matters more than what you fetch, and the wrong choice creates request waterfalls on slow phones.
We measured a React Native FlatList rendering thumbnail images on a 2019 Redmi 7A to find what actually slows down scrolling.
How we handle conversations when a client asks for something that would compromise the system we're building for them.
A model that classifies support tickets needs a threshold below which it stops guessing and hands the ticket to a human queue.
A permission model that stays readable when customers start asking for role variants that were never in the original plan.
Building a school timetable engine that handles shared labs, part-time staff, and principal preferences without producing an unusable schedule.
Which CloudWatch alarms should wake you up and which ones just train the on-call person to mute everything by day three.
Handling deep links when React Native isn't loaded yet and the user is on a low-end Android device with 1GB of RAM.
Rounding rules, field ordering, and tax split logic for generating GST invoices Indian accountants will accept without a callback.
How we structure CSV imports to validate every row upfront and return a per-row error report rather than a single opaque failure.
Wiring React error boundaries to real logging so production crashes on mid-range Android become actionable instead of silent.
How a small, founder-led team decides which projects to take and which to decline before scope outpaces capacity.
How we handle usage metering for multi-tenant SaaS billing, including late-arriving events and reconciliation against Stripe.
Why a string column becomes unmaintainable and how an explicit state machine prevents invalid transitions in e-commerce orders.
A pattern for catching bad LLM output before it touches your tables, and routing rejects without losing the work.
What each APK size reduction costs you when your users are on budget hardware with limited storage and slow connections.
Configuring next/image for mid-range Android on 3G: sizes, priority, and the srcset mistakes that quietly ship oversized files.
Why we route large file uploads directly to S3 and what it costs you in validation when you do.
How we automated tenant onboarding end-to-end so a signup becomes a live workspace without manual database work.
Why fee reconciliation against bank statements fails when parents pay in installments, and how we handle the matching without manual work.
What we write down when shipping software, what stays useful, and what turns stale before the next deployment.
A practical approach to retry logic, link regeneration, and notification cadence for abandoned Indian e-commerce transactions.
What a real restore drill on an automated RDS backup turns up that the backup dashboard never warns you about.
How we cut token spend by routing requests to caches, smaller prompts, and cheaper models where the big one is not needed.
How a small, founder-led team handles estimates before requirements are settled, and what we tell clients about the uncertainty.
A dashboard shows yesterday's order count because the query cache is stale. Here is how we decide between invalidation and refetch.
When your knowledge base has three versions of the same policy and two are wrong, retrieval needs to handle disagreement before it handles relevance.
A teacher sees attendance, an admin sees fee status, a parent sees homework. One record, three views, and the boundaries between them.
What we do to keep field staff notifications arriving on budget Android phones that aggressively kill background processes.
Five AWS charges that quietly accumulate when no one is watching, and how to catch them before the bill arrives.
How we handle the stock race condition that surfaces when a store's traffic spike creates concurrent checkout requests for the final SKU unit.
We update dependencies monthly, skip the risky ones, and track what we deferred so it doesn't become a surprise later.
How we clean years of inconsistent spreadsheet records into structured ERP data without losing the relationships between rows.
A payment gateway retries a webhook after a timeout and your store creates a second order. Here is how we prevent that with a deduplication table.
How to compute the prorated charge for a mid-cycle plan upgrade and present the resulting invoice so the customer understands it.
Replacing fragile regex against free-text LLM output with a JSON schema the model is forced to fill, with notes on cost and validation.
How we handle offline edits in React Native apps when two staff members touch the same record and reconnect at different times.
Validation, pending states, and error handling in Next.js Server Actions for users on mid-range Android phones with uneven data.
Configuring ALB health checks and deregistration delays so ECS rolling deploys drain tasks without dropping in-flight requests.
How we build ERP reports that accountants trust without correcting them in a spreadsheet first.
Postgres RLS is a clean way to isolate SaaS tenants, but transaction-mode pooling drops the session variable it depends on.
The tradeoffs of maintaining what we ship, and how it changes the way we build from day one.
How we handle attendance capture in classrooms with no connectivity and resolve conflicts when the device reconnects.
Learn how we approach building software and the values that guide our work.
Exploring our commitment to long-term software maintenance and support.
Get notified when we publish new insights about software development and building systems that last.
Get in touch