Home/Technology

The stack, and the
reasons it looks like this.

We are deliberately boring about tooling. Ten core technologies, run in production long enough that we know their failure modes, assembled into one seven-layer architecture. This page is the whole of it — what each part does, what it replaced, and what it costs us.

10 core technologies · 7 architecture layers · 4 environments

Production stack10 TOOLS · 6 GROUPS
BackendLaravelNestJS
FrontendReactVue
MobileFlutter
DataMySQLRedis
Cloud & DevOpsDockerAWS
E-commerceShopify

The ten

Ten technologies, and what each one replaced.

Every tool here earned its place by displacing something that was slowing us down. Open a row for the argument, the cost we accepted, and how we would get off it.

RefTechnologyLayerWhat it ownsChosen over

Laravel

Why it is here

Business rules, authentication, the admin, queues and scheduled work. Most of what we build starts here, because the framework already contains the eighty percent every project needs and we only write the part that is yours. Long support windows, and the largest PHP hiring pool in India, so the team that inherits it can actually be hired.

What it costs us

PHP handles one request per process, so long-lived connections and heavy real-time work do not belong here. It is also more framework than a pure API needs. We accept the weight for what comes in the box.

Runs atL3 · Application
Pairs withMySQL, Redis, React
Not forwebsockets and streaming
Escape hatchordinary PHP, portable SQL schema
Where you feel itan admin your staff can use in the first weeks

NestJS

Why it is here

Websockets, streaming integrations and workers that need to hold a connection open. It puts opinionated structure on top of Node, so the second developer can find things, and TypeScript runs the whole way from the service to the React screen consuming it.

What it costs us

A second runtime to deploy, patch and monitor. We add it when a workload genuinely needs it, not because the diagram looks better with more boxes on it.

Runs atL3 · Application
Pairs withReact, Redis, Laravel
Not forCRUD Laravel already owns
Escape hatchplain Node behind the same contract
Where you feel ita live screen that updates without a refresh

React

Why it is here

Dashboards, admin panels and anything carrying real state across many screens. It has the largest component ecosystem and the largest hiring pool, so whatever the interface needs, a maintained library already exists and someone we have not met can pick the codebase up.

What it costs us

Bundle size. We budget it and measure it on a mid-range Android phone on a weak connection, rather than assuming it away on a developer's laptop.

Runs atL1 · Client
Pairs withLaravel, NestJS
Not fora brochure site that could be static
Escape hatchplain REST behind it, interface replaceable
Where you feel itone screen that holds a day of work without reloading

Vue.js

Why it is here

One interactive screen added to a server-rendered application that is otherwise fine. It drops into a Blade page a component at a time, which gets a modern interface into an older system without betting the whole budget on a rewrite nobody asked for.

What it costs us

Two frontend frameworks in the practice instead of one. The rule that keeps it honest: one per project, never both in the same codebase.

Runs atL1 · Client
Pairs withLaravel, Blade
Not fora large app with many screens
Escape hatchthe server-rendered page still works
Where you feel ita modern screen inside the system you already know

Flutter

Why it is here

Apps where the same feature set has to exist on iOS and Android. It draws its own widgets, so the interface behaves the same on a five-year-old Android handset as on a new iPhone, and one team ships to both stores on one release cycle instead of two.

What it costs us

A larger install size, and a native bridge written by hand whenever we reach hardware the plugin ecosystem does not already cover.

Runs atL1 · Client
Pairs withLaravel, REST APIs
Not forapps built on platform-specific hardware
Escape hatchthe same documented API anyone would use
Where you feel itthe same release on both stores in the same week

MySQL

Why it is here

The data your business would still need if every application were deleted. Business data is relational — invoices belong to customers, appointments belong to doctors — and constraints and transactions belong in the database rather than in hope and application code.

What it costs us

Schema changes need a migration and a plan. We treat that as a feature rather than a tax: the shape of your data is reviewed before it changes, not after.

Runs atL5 · Data
Pairs withLaravel, Redis
Not forfree-form documents with no stable shape
Escape hatchstandard SQL; a dump is the whole export
Where you feel ita report that reconciles, because the database refused the bad write

Redis

Why it is here

Everything that is expensive to compute and cheap to remember: sessions, cached views, rate limits and the queue behind background work. It is the cheapest performance available — put it in front of the slow read and the slow page stops being slow, for the price of a small instance.

What it costs us

It is memory, so it is never the truth. Anything held only in Redis is allowed to disappear, which means everything in it has to be re-derivable from MySQL, and we design it that way from the first week.

Runs atL5 · Data
Pairs withMySQL, Laravel, NestJS
Not foranything that must survive a restart alone
Escape hatchdrop the cache; the app answers, slower
Where you feel itthe slow page stops being slow

Docker

Why it is here

The unit we build, test, ship and roll back. The same image runs on a laptop, in the pipeline and in production, so a new developer is useful on day one instead of day four, and rebuilding a server is a command rather than a weekend of archaeology.

What it costs us

A slower first build, images to store and patch, and one more thing a new developer has to learn on day one. It pays for itself the first time a server has to be rebuilt under pressure.

Runs atL7 · Platform
Pairs withAWS, the delivery pipeline
Not fora static site that is three files and a CDN
Escape hatchthe image runs on any container host
Where you feel ita new developer useful on day one, not day four

AWS

Why it is here

Compute, managed database, object storage and CDN, in regions close to Indian users. The managed services are precisely the ones we would otherwise run badly ourselves — database backups, storage durability, certificate renewal. We would rather buy those than be responsible for them at two in the morning.

What it costs us

Vendor surface. We hold it down deliberately: infrastructure described in code, data in open formats, the application in a container. Leaving becomes a project rather than a rebuild.

Runs atL7 · Platform
Pairs withDocker, MySQL, Redis
Not fora workload that fits one small managed host
Escape hatchcontainers plus a SQL dump move anywhere
Where you feel ita failed disk that is somebody else’s two in the morning, not yours

Shopify

Why it is here

Commerce where the hard part is the catalogue, not the code. Nobody should be maintaining their own checkout: payments, tax and card compliance are Shopify's problem, and the catalogue, the storefront and the integrations back into your own systems are ours.

What it costs us

Their platform, their limits and their fees. The checkout is not ours to change. When the business logic outgrows the platform, the logic moves into Laravel and Shopify stays the till.

Runs atL1 · L3
Pairs withLaravel, MySQL
Not formarketplaces with many sellers
Escape hatchcatalogue and orders via the Admin API
Where you feel itcard compliance that is not your problem

Request path

Follow one request, end to end.

A page request takes one of three routes depending on what is already cached and whether it writes. Pick one and the live path lights up; the rest of the system stays visible but dimmed.

CLIENT EDGE APPLICATION DATA ASYNC BROWSERweb · mobile · admin CDN + TLScache · WAF NGINX · PHP-FPMone worker, one request MIDDLEWAREsession · auth · limits CONTROLLERbusiness rules RESPONSErendered · compressed REDISsession · cache · TTL MYSQLindexed read · transaction QUEUERedis · job accepted OBJECT STOREfiles · exports WORKERemail · SMS · PDF

Swipe to follow the request →

  • 01DNS resolves to the CDN and the nearest edge answers.Edge
  • 02Images, CSS and JavaScript come from the edge cache. Your server is never asked.Edge
  • 03The HTML request forwards to Nginx, with TLS already terminated.Edge
  • 04The session cookie is read and the user resolved from Redis.App
  • 05Middleware settles role and rate limit before any business code runs.App
  • 06The cached view fragment is found in Redis and returned.Data
  • 07The response is serialised and compressed on the way out.App
  • 08No database query was made on this request at all.Data
  • 01Same edge, same TLS, same Nginx worker. Only the cache state is different.Edge
  • 02Session and permission resolve from Redis exactly as before.App
  • 03Redis is asked for the view fragment and does not have it.Data
  • 04The controller runs the business rule that needs the data.App
  • 05One indexed query to MySQL, planned as one query rather than thirty.Data
  • 06The result is written back to Redis with a time to live.Data
  • 07The page renders and the user sees the same result, slightly later.App
  • 08The next identical request takes the path above.Data
  • 01The form posts through the edge, where rate limits and filtering apply first.Edge
  • 02Every field is validated at the boundary, before anything is persisted.App
  • 03A policy check authorises this user against this specific record.App
  • 04The write runs inside one transaction: all of it, or none of it.Data
  • 05The privileged action is written to the audit log with who and when.Data
  • 06Stale cache keys are dropped so the next read cannot serve old data.Data
  • 07Email, SMS, PDFs and exports go on the queue. The user gets an answer now.Async
  • 08A worker takes the job, retries with backoff, and writes the file to object storage.Async

Synchronous path in accent · queued work in teal · dimmed nodes are not on this route

System thinking

Complex problems deserve better systems.

A reference architecture we adapt, not a template we apply. Select a layer to see what it owns and what we build it with.

Layer 1 — Experience

Client

Every surface a person actually touches. Responsive, fast on mid-range Android devices, and designed so the common task is one tap away rather than three menus deep.

Responsibilities

  • Responsive across devices
  • Offline-tolerant behaviour
  • Accessible interactions

Typically built with

ReactVue.jsFlutter
Position in stack

Layer 2 — Ingress

Delivery Edge

Caching, certificates and basic protection at the front door. Cheap to run, and the single biggest lever on how fast a site feels outside a metro city.

Responsibilities

  • Asset caching
  • TLS & redirects
  • Rate limiting

Typically built with

CloudflareNginxLet’s Encrypt
Position in stack

Layer 3 — Core

Application

Where the business rules live. One well-structured application beats four services when the team is small — we split it only when a part genuinely needs its own release cycle.

Responsibilities

  • Business rules & validation
  • Roles & permissions
  • Audit logging

Typically built with

LaravelNestJSNode.js
Position in stack

Layer 4 — Contract

API Layer

A versioned contract between the app and everything else — mobile clients, partner systems, payment gateways. Documented, so the next integration does not need a meeting.

Responsibilities

  • Versioned endpoints
  • Predictable error shapes
  • Third-party integrations

Typically built with

RESTGraphQLOpenAPI
Position in stack

Layer 5 — State

Data

Relational where the data is relational. Cache and queues in front of the slow paths, and backups that have actually been restored at least once.

Responsibilities

  • Schema & migrations
  • Caching & queues
  • Tested backups

Typically built with

MySQLPostgreSQLRedis
Position in stack

Layer 6 — Analytics

Reporting

Reporting that reads the same governed data as the rest of the system — the numbers a manager asks for every Monday, on screen and as a scheduled export, instead of a query someone runs by hand.

Responsibilities

  • One source of truth
  • Scheduled delivery
  • Auditable figures

Typically built with

SQL viewsAnalyticsScheduled jobs
Position in stack

Layer 7 — Operations

Platform

Cuts across everything above. Reproducible environments, one deployment pipeline, and alerts that reach a person before a client does.

Responsibilities

  • Repeatable deployments
  • Staging parity
  • Monitoring & alerting

Typically built with

DockerGitHub ActionsUptime alerts
Position in stack

Environments & delivery

Four environments, one pipeline.

Code moves in one direction through gates that either pass or stop the build. Nothing reaches production that has not already been the same container image in three cheaper places.

01

Commit

GateLinters and static analysis pass before the commit lands.

02

Review

GateOne reviewer. No direct pushes to main, including ours.

03

Build

GateTest suite green, dependency audit clean, image published.

04

Staging

GateMigrations run and the smoke check answers.

05

Sign-off

GateYou have used it on the staging URL and approved it.

06

Production

GateManual approval, health check green, rollback ready.

01Local
02Pipeline
03Staging
04Production
Runs on
Docker on the developer's machine
A clean container per run, built from the repository
The same image as production, on smaller hardware
AWS, running the exact image the pipeline built
Data
Seeded fixtures, deliberately ugly ones
A fresh database built from migrations every run
The production shape with the personal data removed
Real, and backed up nightly
Who ships
Anyone, constantly
Every push, automatically; nobody decides
Every merge to main, automatically
A named person, from a tagged release
Secrets
Example values in the repository
Injected by the pipeline, never committed
Injected at deploy
Injected at deploy, rotated at handover
Gate to leave
Tests and linters pass before the commit
Build succeeds, tests green, image published
You have used it and signed off the demo
Health check green, or the previous image goes back
Breaking it means
Seconds
A red build and a message in the channel
A bug fixed before you ever see it
An incident, and a rollback

Swipe the table →

Security & data

Security is part of the build, not a line item after it.

None of this is exotic. It is the ordinary set of controls, applied on every project rather than only on the ones that think to ask for them.

  • TLS everywhere

    Certificates are issued and renewed automatically, HTTP redirects, and there is no mixed content. A failed renewal wakes one of us; it does not greet your customers.

    L2
  • Limits at the edge

    Rate limiting and filtering run before the application spends a process on the request. Login and one-time-password endpoints get tighter limits than the rest.

    L2
  • Validated at the boundary

    Every request is validated and authorised before it reaches business logic. Queries are parameterised, output is escaped, and there is no clever exception.

    L3
  • Roles, not exceptions

    Access is a role rather than a checkbox somebody remembers to tick, and every privileged action is written to an audit log with who did it and when.

    L3
  • Least privilege, by default

    One database user per application, scoped to its own schema, and it cannot drop tables. No shared root credentials, and no personal logins on servers.

    L5
  • Backups that have been restored

    Nightly, taken off the primary, and restored into a scratch environment so we know how many minutes it actually takes. A backup nobody has restored is a hope.

    L5
  • Secrets outside the repository

    Configuration comes from the environment, never from a commit, and keys are rotated when a person leaves the project or the project is handed over.

    L7
  • Updates on a schedule

    Dependency patches are part of the maintenance work, not an emergency response after a vulnerability has acquired a name and a logo.

    L7

When it does go wrong

The plan is not that nothing breaks.

Everything on the left reduces how often. None of it makes the number zero, so the part that actually matters is what happens in the twenty minutes after.

01

It reaches a person first

Monitoring and uptime alerts are wired to us, so the first message about an outage is ours rather than your customer’s.

02

The previous image goes back

Production runs a tagged image the pipeline built, so a rollback is a deploy of the last known good one, not a repair under pressure.

03

It gets written up

What broke, what we changed, and what stops it recurring. In writing, whether or not you asked for it.

How support and maintenance works

Your data, your exit

Leaving should be a project, not a rebuild.

We would rather you stay because the work is good. Every technical decision on this page is made so that staying is a choice — and so that a team who has never met us can take it over without our help.

A portable SQL schema, plain object storage, documented APIs, and an application in a container. A database dump is a valid exit.

Lock-in is a business model. It is not ours.

What you get at handover

  • The source repository with its full history, on your account
  • An infrastructure diagram that matches what is deployed
  • A runbook: deploy, roll back, restore
  • API documentation and versioned contracts
  • An access matrix with your team as the owners
  • Credentials moved into your vault, and ours revoked
  • A recorded walkthrough with the engineers who built it

How we choose

Boring technology, on purpose.

Six rules decide what gets into the stack. A tool has to pass all six, and interesting is not one of the criteria.

01

Proven over novel

We pick tools with long support horizons and large hiring pools. Your platform should outlive whatever is trending this year, and stay maintainable by someone who has never met us.

02

One stack per team

A team that knows one stack deeply ships faster than a team that knows five stacks shallowly — and it is still fast in year three.

03

Escape hatches everywhere

No framework lock-in we cannot unwind. Data in open formats, infrastructure in code, contracts documented. A rewrite should never be the only way out.

04

Managed where it is cheap

Managed databases, queues and CDNs beat running our own, until the bill or the constraint says otherwise. We do not run infrastructure for the pleasure of it.

05

We run what we recommend

EduCore, TreatLoops and Cards are built by the same team on this same stack, which is where a good deal of what we know about running it in production comes from.

06

Upgrades are scheduled work

Dependency and platform updates sit in the maintenance plan, so the version you launch on is not the version you are stuck on three years later.

Where we push back

Four conversations we have had enough times to answer here.

“Can you build it in something we already have a licence for?”

We can learn anything. You should not pay for us to learn it on your project. If the requirement genuinely needs it we will say so, and tell you who does it well.

“Can we start with microservices?”

Not on day one. One well-structured application, split only when a part earns its own release cycle. Four services and one small team is four deployments to debug and one person to do it.

“Can we use a document database for everything?”

Only where the data is genuinely not relational. Most business data is, and the join you avoid today becomes application code you maintain forever.

“Can we skip staging to hit the date?”

No. The date moves or the scope moves. Staging is the cheapest place left to find the problem, and the alternative is finding it in front of your customers.

See the six practices See what we built with it

Stack fit

Four shapes, and what we would put on each.

The rules above only mean something when they cost us options. Pick the shape closest to your project and this is the stack we would actually propose, including the parts we would leave out.

Internal operations tool

Hundreds of users, not hundreds of thousands. The hard part is not the load; it is that the rules change every month and the admin has to keep up with them.

What decides it here

  • The rules change more often than the screens do
  • One team will maintain it for years
  • Nobody is going to install an app for it
L1
BladeVue.js

One interactive screen at a time, not a second codebase.

L3
Laravel

The admin, the roles and the queues come in the box.

L4
REST

Documented from day one, so a mobile client stays possible.

L5
MySQLRedis

Constraints in the database, sessions and cache in memory.

L7
DockerAWS

One image, one small managed database.

Deliberately not in this one

ReactNestJSFlutter

A second frontend codebase to maintain, for screens Blade already renders. Nothing here holds a connection open, and nobody is installing an app to file a leave request.

See work in this shape

Product on web and both stores

The same feature set has to exist in three places and stay in step through every release. The contract between them becomes the product.

What decides it here

  • Two app stores, on one release cycle
  • Real state carried across many screens
  • A mid-range Android phone is the test device
L1
ReactFlutter

Dashboards on the web, one codebase for both stores.

L3
LaravelNestJS

Laravel for the core; NestJS only where something holds a connection open.

L4
REST, versioned

The contract is the product once three clients depend on it.

L5
MySQLRedis

One system of record, one cache in front of it.

L7
DockerAWS

The same image, plus object storage and a CDN.

Deliberately not in this one

GraphQLA service per featureTwo native teams

Four services and one small team is four deployments to debug and one person to do it. Two native teams is the same feature set built twice, on two schedules.

See work in this shape

Store with a real catalogue

The hard part is the catalogue and the integrations behind it, not the checkout. The checkout is a solved problem you can rent.

What decides it here

  • Payments, tax and card compliance should not be yours
  • The catalogue has to be searchable and stay current
  • The store has to talk to whatever runs behind it
L1
Shopify

The storefront, as a theme rather than a framework.

L3
ShopifyLaravel

Checkout stays theirs; logic that outgrows the platform moves to ours.

L4
Admin APIWebhooks

Order events into the rest of your stack, as they happen.

L5
MySQLRedis

The catalogue lives in Shopify; your orders live where your business can query them.

L7
DockerAWS

For the integration side. The store itself is hosted by the platform.

Deliberately not in this one

A custom cartOur own compliance scopeNestJS

Nobody should be maintaining their own checkout, or their own card compliance. Building one moves a solved problem onto your balance sheet and keeps it there.

See work in this shape

A system we cannot rewrite yet

It works, it is load-bearing, and a big-bang rewrite is the most expensive way to find out what it actually did. So it gets replaced a piece at a time, while it keeps running.

What decides it here

  • The business cannot stop while it is replaced
  • The data is already somewhere, and it is not moving first
  • Each replaced piece proves itself before the next one starts
L1
Vue.js

Added to the pages you already have, one screen at a time.

L3
Laravel

New rules in a service beside the old application, not instead of it.

L4
One documented contract

Between the old system and the new one, written down before either moves.

L5
MySQLRedis

Your existing schema, respected and migrated. The cache goes in front of the slow reads first.

L7
DockerAWS

The first thing we containerise is what you already run, so it can be rebuilt at all.

Deliberately not in this one

A full rewriteA second databaseReact

Two systems of record is the failure mode, not the plan. A rewrite is the most expensive way to end up where you started, and it is not one you asked for.

How modernisation runs

Have a difficult problem?

Let’s turn it into a product worth building.

Start a Conversation contact@scorptechsolutions.com

Free consultation · reply in one business day · +91 91733 99077