1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

3つの数字」で考える14日納品のアーキテクチャ判断 — $0 / 14日 / コード100%譲渡 をコードでどう担保するか

1
Posted at

x-ad.jpg

「3つの数字」で考える14日納品のアーキテクチャ判断

私たちのチームでは、すべてのソフトウェアプロジェクトを 3つの数字 で説明しています。

  • $0 — 初回プロジェクトの請求額
  • 14日 — キックオフから本番納品までの日数
  • 100% — クライアントの GitHub に譲渡するソースコードの割合

この記事では、この3つの数字を マーケティング上のスローガン ではなく、エンジニアリング上の制約
として扱うとき、アーキテクチャと開発フローにどんな影響が出るかを書きます。

結論先出し — 3つの数字を「コード」で担保する5原則

  1. $0 を成立させるには「営業工程をコードに置き換える」 — 自動スコーピング、テンプレ・スキャフォールド、デモ環境の自動生成
  2. 14日 を成立させるには「Day 0 で全テーブル定義を完了させる」 — スキーマ後付けは時間的に不可能
  3. 14日 × 本番品質 を成立させるには「型システムと CI を厳格化する」 — 人間のレビュー時間を最小化
  4. 100% 譲渡を成立させるには「自社固有ライブラリ依存を作らない」 — オープンソース・標準的なスタックを優先
  5. MVPではない を成立させるには「Day 12 を専用QAデーにする」 — 機能追加ではなく品質確認のための1日

順に、コードと判断根拠を見ていきます。


  1. $0 の成立条件 — 営業工程をコードに置き換える

伝統的な開発会社は売上の 25〜40%
を営業・提案・契約のプロセスに使います。この工程を残したまま「初回無料」をやると、単純に赤字になります。

私たちは 営業の代わりにコードを書いた だけです。

1-1. 自動スコーピング — スプレッドシートではなく型で定義

❌ Bad: Word ドキュメントの SOW を毎回手作業で書く

  • ユーザー登録機能
  • マイページ機能
  • 管理画面
  • 決済機能
  • …

✅ Good: TypeScript の型としてスコープを定義する

// 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), // 必ず含める
}),
payments: z.object({
provider: z.enum(['stripe', 'paypal', 'none']),
recurring: z.boolean(),
invoices: z.boolean(),
}),
dashboards: z.array(
z.object({
name: z.string(),
widgets: z.array(z.enum(['table', 'chart', 'kpi', 'export'])),
}),
),
// …以下、機能ごとに型で定義
});

export type ProjectScopeT = z.infer;

これにより:

  • 「スコープに入っているか」が コンパイル時に検証可能
  • スキャフォールド・テスト・ドキュメント生成がすべて 同じ型を参照
  • 営業時間を コード生成時間 に置き換えられる

1-2. デモ環境の自動プロビジョニング

$0 で動くものを見せるには、デモ環境を 手作業で立てない ことが必須です。

// scripts/provision-demo.ts
async function provisionDemo(scope: ProjectScopeT) {
const projectId = generateProjectId();
await Promise.all([
createSupabaseProject(projectId, scope),
createVercelDeployment(projectId, scope),
createStripeTestKeys(projectId),
seedDemoData(projectId, scope),
]);
return { previewUrl: https://${projectId}.demo.example.dev };
}

この provision-demo が 5分以内 に完了することが、$0 を成立させる前提条件です。


  1. 14日 の成立条件 — Day 0 で全テーブル定義を完了させる

❌ Bad: 機能ごとにスキーマを後から足していく

// Day 1
const users = pgTable('users', { id, email });
// Day 5
const posts = pgTable('posts', { id, userId, content });
// Day 9 — ⚠ ここで「メンバーシップが必要」と判明
// → users と posts の両方にマイグレーションが発生
// → 既にできているフロントエンドの再修正が発生

このパターンは Day 9 のスキーマ変更が 3〜5 日分の作り直し を引き起こし、14日スケジュールが破綻します。

✅ Good: Day 0 で全テーブルを定義する

// schema/index.ts — Day 0 で完成させる
import { pgTable, uuid, text, timestamp, integer, boolean, 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'),
emailVerifiedAt: timestamp('email_verified_at'),
createdAt: timestamp('created_at').notNull().defaultNow(),
});

// …以下、全テーブルを Day 0 で完成

Day 0 でスキーマを固定するメリット

┌──────────────────────┬───────────────────┬────────────────────────┐
│ 項目 │ Day 0 確定 │ 後付け │
├──────────────────────┼───────────────────┼────────────────────────┤
│ マイグレーション回数 │ 1〜2回 │ 10回以上 │
├──────────────────────┼───────────────────┼────────────────────────┤
│ フロント再修正コスト │ ほぼ0 │ スキーマ変更ごとに発生 │
├──────────────────────┼───────────────────┼────────────────────────┤
│ デプロイダウンタイム │ 0 │ 移行ごとに発生 │
├──────────────────────┼───────────────────┼────────────────────────┤
│ 認知負荷 │ 1回で全体を考える │ 毎日「次は何を直す?」 │
└──────────────────────┴───────────────────┴────────────────────────┘

「設計に時間をかける」ではなく、「設計を1日に圧縮する」 が 14 日納品の前提です。


  1. 14日 × 本番品質 の成立条件 — 型と CI を厳格化する

14日で本番品質を出すには、人間のレビュー時間を最小化する
必要があります。これは「レビューしない」ではなく、「機械が見るところは機械に任せる」 という意味です。

CI で必ず落とすルール(提案)

.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

    # 1. 型チェック (no any, no implicit any, strict mode)
    - run: pnpm tsc --noEmit

    # 2. ESLint (eslint-config-strict + no-explicit-any)
    - run: pnpm lint --max-warnings=0

    # 3. テスト (カバレッジ閾値あり)
    - run: pnpm test --coverage --coverage.threshold.global=80

    # 4. 依存脆弱性スキャン
    - run: pnpm audit --audit-level=moderate

    # 5. E2E (Playwright — 主要ユーザーフローのみ)
    - run: pnpm playwright test --reporter=line

    # 6. ビルド成功確認
    - run: pnpm build

このうち 1つでも red になったら merge できない。これにより、人間レビュアは「設計の妥当性」だけを見ればよくなります。


  1. 100% 譲渡の成立条件 — 自社固有ライブラリを作らない

クライアントのリポジトリに 自社専用ライブラリへの依存
を残すと、譲渡の意味がなくなります。「コードを渡したけど動かすには毎月ライセンス料が要る」は譲渡ではありません。

譲渡可能なスタック選定の基準

┌────────────────┬────────────────────────────────┬────────────────────────────────────────────────────┐
│ カテゴリ │ ✅ 選ぶ │ ❌ 避ける │
├────────────────┼────────────────────────────────┼────────────────────────────────────────────────────┤
│ フレームワーク │ Next.js / Remix / Hono │ 自社製フレームワーク │
├────────────────┼────────────────────────────────┼────────────────────────────────────────────────────┤
│ ORM │ Drizzle / Prisma │ 自社製ORM │
├────────────────┼────────────────────────────────┼────────────────────────────────────────────────────┤
│ 認証 │ NextAuth / Lucia / Better Auth │ 自社製認証SDK │
├────────────────┼────────────────────────────────┼────────────────────────────────────────────────────┤
│ デプロイ │ Vercel / Fly / Railway │ 自社製プラットフォーム │
├────────────────┼────────────────────────────────┼────────────────────────────────────────────────────┤
│ UI │ shadcn/ui / Tailwind │ 自社製コンポーネントライブラリ(クローズドソース) │
└────────────────┴────────────────────────────────┴────────────────────────────────────────────────────┘

譲渡後、クライアントが どの開発会社・どのエンジニアでも保守できる ことが、100% の本質です。


  1. MVPではない の成立条件 — Day 12 を専用QAデーにする

Day 0〜11 で機能を全部作っても、Day 12 を 「機能追加禁止 / QAだけ」 に固定しないと「動くMVP」止まりになります。

Day 12 QA チェックリスト(抜粋)

  • モバイル: 360px / 768px / 1024px / 1440px の全幅で全画面確認
  • フォーム: バリデーション境界値(空、最大長、不正値)
  • 認証: トークン期限切れ後のリダイレクト
  • 決済: 失敗パターン(カード拒否、3DS、Webhook 二重送信)
  • エラー: 404 / 500 / ネットワーク切断時の画面
  • パフォーマンス: Lighthouse 90 以上、TTI < 2.5s
  • アクセシビリティ: axe で violations: 0
  • セキュリティ: OWASP Top 10 簡易チェック

このうち1つでも red の状態で Day 14 納品はしません。「MVPだから後で直す」は許容しない が 14 日納品 ×
本番品質を成立させる最後のピースです。


まとめ

「初回無料」「14日納品」「コード100%譲渡」をマーケティング上のスローガンとして掲げる会社はいくつかあります。ただし
3つを同時に成立させようとすると、技術スタックと開発フローの両方を再設計する必要 があります。

┌──────┬────────────────────────────────┐
│ 数字 │ コード上の制約 │
├──────┼────────────────────────────────┤
│ $0 │ 営業工程を自動化する │
├──────┼────────────────────────────────┤
│ 14日 │ Day 0 でスキーマ完成、CI厳格化 │
├──────┼────────────────────────────────┤
│ 100% │ 自社固有依存を作らない │
└──────┴────────────────────────────────┘

この3つを成立させる開発チームの実装例として、私たちは Fluxez というプロジェクトを運営しています。GitHub
にコード例とテンプレートを公開しているので、興味があれば見てみてください。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?