DEV Community

Info Inlet
Info Inlet

Posted on

**Three Numbers as Engineering Constraints: $0, 14, 100%**


For about fifteen years, "MVP" has been the universal cover for shipping incomplete software. A login that breaks on mobile, three features that work and two that don't, "we'll harden it later" — all of it gets a free pass under the MVP framing.

We stopped accepting that framing on our team a while ago. But it took us a while to figure out why the MVP framing was so sticky in the first place, and what to replace it with.

The answer turned out to be three numbers. Treated not as marketing claims, but as engineering constraints that force specific architectural decisions.

This post is about those three numbers, and what they actually force in code.


The Three Numbers

  • $0 — the invoice for the first project we do with any client
  • 14 — the number of days from kickoff to a shipped, production-ready product
  • 100% — the percentage of source code that transfers to the client's GitHub org on Day 14

Each one is unusual. Together, they force five engineering decisions that most teams don't make.


Constraint 1: $0 Forces You to Delete the Sales Pipeline

If the first project is free, you cannot afford a traditional sales pipeline. Most agencies spend 25-40% of their revenue on pre-sales work — proposals, RFP responses, discovery sprints, alignment meetings. That cost center has to go.

In practice, this means the sales process gets replaced with code.

// scope/intake.ts
export const ProjectScope = z.object({
  auth: z.object({
    providers: z.array(z.enum(['email', 'google', 'github', 'apple'])),
    mfa: z.boolean(),
    passwordReset: z.literal(true), // always included
  }),
  payments: z.object({
    provider: z.enum(['stripe', 'paypal', 'none']),
    recurring: z.boolean(),
  }),
  dashboards: z.array(
    z.object({
      name: z.string(),
      widgets: z.array(z.enum(['table', 'chart', 'kpi'])),
    }),
  ),
});
export type ProjectScopeT = z.infer<typeof ProjectScope>;
Enter fullscreen mode Exit fullscreen mode

The intake form is a typed schema. Scaffolds, demo seeds, and test suites all consume the same type. What used to be a 90-minute discovery call is now a 15-minute conversation plus a typed object.

The $0 is not generous. It is the result of deleting 25-40% of overhead that did not produce code.


Constraint 2: 14 Forces You to Finalize the Schema on Day 0

If you have 14 days, you cannot afford a single multi-table schema migration mid-build. A migration on Day 9 propagates into the frontend, breaks half-finished forms, and blows the timeline.

This forces the rule: the database schema is finalized on Day 0, before any feature code is written.

// schema/index.ts — completed on Day 0
import { pgTable, uuid, text, timestamp, pgEnum } from 'drizzle-orm/pg-core';

export const roleEnum = pgEnum('role', ['admin', 'member', 'viewer']);
export const planEnum = pgEnum('plan', ['free', 'pro', 'enterprise']);

export const organizations = pgTable('organizations', {
  id: uuid('id').primaryKey().defaultRandom(),
  name: text('name').notNull(),
  plan: planEnum('plan').notNull().default('free'),
  createdAt: timestamp('created_at').notNull().defaultNow(),
});

export const users = pgTable('users', {
  id: uuid('id').primaryKey().defaultRandom(),
  organizationId: uuid('organization_id')
    .notNull()
    .references(() => organizations.id, { onDelete: 'cascade' }),
  email: text('email').notNull().unique(),
  role: roleEnum('role').notNull().default('member'),
  createdAt: timestamp('created_at').notNull().defaultNow(),
});
Enter fullscreen mode Exit fullscreen mode

The schema is reviewed, locked, and merged on Day 0. Feature code begins on Day 1 with the data model already correct.

Most teams resist this because it feels like "designing too much up front." But the alternative — incremental schema discovery across two weeks — costs 5-10x more in rework. The 14-day constraint forces the disciplined version.


Constraint 3: 14 Also Forces You to Make CI Reject Sloppy Work Automatically

14 days does not leave time for "let's discuss this PR in standup." A senior engineer's review time has to be spent on architecture, not on catching missing tests or any types.

The fix: CI rejects everything mechanical, before it ever hits a human reviewer.

# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v3
      - uses: actions/setup-node@v4
        with: { node-version: '20', cache: 'pnpm' }
      - run: pnpm install --frozen-lockfile
      - run: pnpm tsc --noEmit                                 # 1. types strict
      - run: pnpm lint --max-warnings=0                        # 2. no warnings
      - run: pnpm test --coverage --coverage.threshold.global=80
      - run: pnpm audit --audit-level=moderate                 # 3. deps clean
      - run: pnpm playwright test --reporter=line              # 4. e2e
      - run: pnpm build                                        # 5. build green
Enter fullscreen mode Exit fullscreen mode

If any of the six steps go red, the PR cannot merge. Human review then becomes "is this the right architecture" instead of "did you forget to add a test." That's the only way 14 days works.


Constraint 4: 100% Source Code Transfer Forces You to Use Vanilla Stacks

If you have to transfer 100% of the source code to the client on Day 14 — actual repo, actual commit history, actual CI config — you cannot ship code that depends on a proprietary in-house framework. The moment you do, "transferred" becomes a lie.

This forces a specific stack selection rule: vanilla over proprietary, always.

Category ✅ Pick ❌ Avoid
Framework Next.js / Remix / Hono In-house framework
ORM Drizzle / Prisma In-house ORM
Auth Better Auth / Lucia / NextAuth In-house auth SDK
Deploy Vercel / Fly / Railway In-house deploy platform
UI shadcn/ui + Tailwind Closed-source component library

A client should be able to fire us on Day 15 and hand the repo to any senior engineer in the world. That's what 100% actually means.


Constraint 5: "Not an MVP" Forces You to Burn Day 12 on QA, Not Features

If "the real product" is the promise, then somewhere in the 14 days, feature work has to stop and quality work has to take over. We made that day explicit: Day 12 is QA-only. No new features land on Day 12 — only edge-case fixes.

Day 12 — QA checklist (abridged)
[ ] Mobile: 360 / 768 / 1024 / 1440 px, every screen
[ ] Forms: empty / max-length / invalid input boundaries
[ ] Auth: token expiry redirect, refresh flow, session invalidation
[ ] Payments: card decline, 3DS, webhook double-send idempotency
[ ] Error states: 404, 500, offline, slow network
[ ] Performance: Lighthouse ≥ 90, TTI < 2.5s
[ ] A11y: axe violations = 0
[ ] Security: OWASP Top 10 quick pass
Enter fullscreen mode Exit fullscreen mode

Without a dedicated QA day, "real product" silently degrades into "demo-quality MVP." Day 12 is the forcing function.


The Pattern

Each of the three numbers, on its own, looks like a marketing claim. But each one is actually a forcing function that requires a specific engineering decision:

Number Forcing function
$0 Replace sales pipeline with typed scope code
14 Finalize schema on Day 0; CI rejects mechanical issues
100% Vanilla stack only; no in-house framework dependencies
(Not an MVP) Day 12 = QA-only, no new features

Companies that treat these as marketing claims fail at them. Companies that treat them as engineering constraints can actually deliver.


Where We Apply This

We're the team behind Fluxez — a project where the entire engineering organization is built around these three numbers as constraints. The first project a founder does with us is $0, ships in 14 days, and transfers 100% to their GitHub on Day 14.

If you want to see real templates, our scaffold patterns, or the schema-on-Day-0 examples that make this possible, the relevant pieces are on fluxez.com.

Top comments (0)