Build1 distinct publisher3 min readUpdated
A dev.to build log splits storefront from admin on authentication grounds, not bundle grounds. The stronger version of the argument is about which database records are allowed to be shared.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
A developer writing on dev.to has published the build log for an e-commerce system shipped as one monorepo containing three deployables: a Next.js 16 storefront, a Next.js 16 admin dashboard, and a NestJS API [1]. The part worth arguing about is not the bundle arithmetic, it is the author's claim that keeping staff and customers in one app drags you toward a single User model carrying an isAdmin boolean, and that role-based access control built on top of a boolean is how privilege escalation bugs happen [7].
The default in this stack is one app with /admin routes behind a guard, and the author says he rejected it [3]. The performance case he makes first is the familiar one. The storefront is public, SEO-critical and aggressively cached, while the admin is authenticated on every request, data-heavy and never indexed [4]. Share a build and the storefront ships Recharts, the data grids and the rest of the admin client bundle to visitors who will never sign in [5].
That argument is real but weak, because bundles can be split without splitting apps. The load-bearing claim is the second one: in his design, customers and staff are separate tables with separate token payloads and separate refresh lifetimes [6]. Note what that buys. A boolean column can be flipped by any code path that can write to the user row, and every query that forgets a where clause returns both populations. Two tables mean the storefront's token cannot name a staff identity at all, because the identity does not exist in the table the storefront reads. The author presents this as a design principle rather than as a postmortem of a specific breach [7], so treat it as reasoning, not as evidence.
The same instinct shows up in the order model, which is where it gets easier to check. Because guest checkout was a requirement, order.userId is nullable and the order carries its own contact and shipping snapshot, rather than every guest purchase minting a phantom user row that corrupts customer analytics [10]. The shipping address on an order is a copy, not a foreign key, so editing a saved address later does not rewrite historical orders [11]. Line items denormalise product name, variant and unit price at purchase time, because prices change and invoices should not [12]. That is the same refusal as the auth split: do not let one row serve two lifetimes.
The stated cost is three ports in local development, a shared types package, and CORS configuration you have to actually think about [8]. Only one of those three is dev-only; the types package and the CORS surface are permanent [22]. Guest order lookup is order number plus checkout email, rate-limited so it does not become an enumeration oracle [13], which is the kind of detail that suggests the threat model was applied past the login screen.
What to watch is drift. Two identity tables with different refresh lifetimes [6] means two auth implementations to patch, and the shared types package [8] is the seam where the separation will quietly leak back. On the AI side, the controls to check are the per-account server-side quotas on image generation and the cache keyed on garment plus model pair, which the author says covers most traffic [19][20].
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
A developer, Mohamed Djoudir, writing on dev.to, describes shipping a production e-commerce system as a single monorepo containing a Next.js 16 storefront, a Next.js 16 admin dashboard, and a NestJS API.
The author states the obvious approach is one Next.js app with /admin routes behind a guard, and that he split it into three instead.
Per the author, the storefront is public, SEO-critical and cached aggressively, while the admin is authenticated on every request, data-heavy, and never indexed.
The author states that sharing a build means the storefront pays for Recharts, the data grids, and the admin's client bundle even when nobody signs in.
The author states that splitting made auth honest: customers and staff are different tables with different token payloads and different refresh lifetimes.
The author lists the cost of the split as three ports in development, a shared types package, and CORS configuration that has to be thought about, and concludes it was worth it.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Single self-authored account, no artifacts
All claims trace to one dev.to build log written by the system's own developer. The architectural and data-model decisions are described precisely and internally consistently, which supports what the author built, but nothing is independently verifiable: no repository, bundle measurements, security review, rate-limit or quota values, and no traffic numbers behind the 'most of the traffic' and conversion assertions. The headline generalisation about isAdmin and privilege escalation is offered as design reasoning with no incident or audit evidence.
One self-reported deployment
The only adoption signal is the author's own statement that the system was shipped to production. There is no evidence of external users, merchants, downloads, contributors or other teams adopting the storefront/admin split pattern, and the pattern itself is presented as a personal design conclusion rather than something with a measured user base.
Security framing outruns the evidence
The engineering choices are described modestly and with their costs, which keeps most of the piece close to its evidence. The overstatement is concentrated in the generalising claims: that a shared app 'inevitably' produces an isAdmin boolean and that this is how privilege escalation happens, plus unmeasured assertions that a shared build meaningfully taxes the storefront, that cached pairs are most of the traffic, and that account creation kills conversion. These are plausible but unquantified, and they are doing the persuasive work.
Personal credibility incentive, no disclosed commercial tie
The author is documenting his own system on a developer publishing platform, which creates a straightforward reputational incentive to present the architecture as validated and the disputed decisions as settled ('Worth it'). No vendor sponsorship, employer, funding relationship or product being sold is disclosed, and model providers are described as interchangeable config with bring-your-own-key rather than promoted, so there is no evident third-party commercial pressure in the supplied material.
Confident about the account, not about the generalisation
Confidence is high that the source says what the claims report and that the described design is coherent and specific enough to reproduce. Confidence is low that the conclusions generalise: one unverified deployment, one publisher, no measurements, and the central security argument rests on assertion. Assessment is limited to what the single supplied item supports.
build
Count invalid JSON as a failed classification, and model choice becomes a reliability problem1 distinct publisher
build
First-turn evals test the safest part of your product, a 90,000-exchange audit finds1 distinct publisher
build
Agent Plugins 1.0.0 standardises file paths. Anthropic still owns the behaviour.1 distinct publisher
build
A build step instead of a backend: 1,025 records, 8 locales, no runtime API1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 15, 2026