Designing SaaS Commerce with State Machines [Part 11]

What You Will Learn Why “string status” breaks down in SaaS commerce Implementation patterns for embedding state machines into Go domain models Design techniques for coordinating multiple state machines Handling edge cases: partial payments, expiration, and optimistic locking The Status Column from Hell When building web applications, you will almost certainly encounter “status” columns. Order status, invoice status, user account status. What starts as a simple active / inactive boolean grows into pending, processing, completed, cancelled, refunded… as the service evolves. ...

February 23, 2026 · 13 分 · ko-chan

SaaSの商取引をステートマシンで設計する [第11回]

この記事で得られること SaaSの商取引で「文字列ステータス」が破綻する理由 Goでステートマシンをドメインモデルに組み込む実装パターン 複数のステートマシンが連携するときの設計手法 部分支払い・期限切れ・楽観的ロックなどのエッジケース対処 statusカラムの地獄 Webアプリケーションを作っていると、ほぼ確実に「ステータス」カラムに出会う。注文の状態、請求書の状態、ユーザーアカウントの状態。最初は active / inactive の2値で済んでいたものが、サービスの成長とともに pending, processing, completed, cancelled, refunded… と増殖していく。 筆者が開発しているSaaS(マルチテナント型サブスクリプション管理システム)では、見積(Quote)、注文(Order)、請求書(Invoice)、決済(Payment)のそれぞれにステータスがある。 最初はシンプルだ。 1 2 3 4 5 CREATE TABLE invoices ( id UUID PRIMARY KEY, status VARCHAR(20) NOT NULL DEFAULT 'draft', ... ); アプリケーション側ではこうなる。 1 2 3 4 5 6 // よくある実装 func (s *InvoiceService) MarkPaid(id uuid.UUID) error { invoice, _ := s.repo.Get(id) invoice.Status = "paid" // ← 文字列を直接代入 return s.repo.Update(invoice) } これは動く。しかし、サービスが成長するにつれて問題が出る。 ...

February 23, 2026 · 7 分 · ko-chan

PostgreSQL RLS for Multi-Tenant Isolation: Protecting 4-Tier Data as a Solo Developer [Part 4]

What You’ll Learn Comparison of data isolation patterns for multi-tenant SaaS Practical usage of PostgreSQL Row-Level Security (RLS) RLS policy design for 4-tier hierarchy (System/Provider/Reseller/Consumer) Setting RLS context with Go + pgx Detecting RLS leaks through testing Introduction As introduced in Part 1, Saru is a multi-tenant SaaS with a 4-tier account structure. System Admin (manages the entire SMS platform) └── Provider (offers services) ├── Reseller (sells services) │ └── Consumer (purchases/manages) └── Consumer (direct sales) In this structure, data isolation is critical. ...

January 15, 2026 · 11 分 · ko-chan

PostgreSQL RLSでマルチテナント分離:4階層のデータを1人で守る【第4回】

この記事で得られること マルチテナントSaaSにおけるデータ分離パターンの比較 PostgreSQL Row-Level Security(RLS)の実践的な使い方 4階層(System/Provider/Reseller/Consumer)のRLSポリシー設計 Go + pgx でRLSコンテキストを設定する方法 テストでRLS漏れを検知する手法 はじめに 第1回で紹介した通り、Saruは4階層のアカウント構造を持つマルチテナントSaaSだ。 System Admin(SMSプラットフォーム全体を管理) └── Provider(サービスを提供) ├── Reseller(サービスを販売) │ └── Consumer(購入・管理) └── Consumer(直販) この構造では、データの分離が極めて重要になる。 Provider A の顧客データを Provider B が見てはいけない Reseller A の販売実績を Reseller B が見てはいけない Consumer A のサブスクリプション情報を Consumer B が見てはいけない これをアプリケーション層で完全に防ぐのは難しい。WHERE句の書き忘れや権限チェックの漏れは、ソロ開発では特に起こりやすい。 そこで PostgreSQL Row-Level Security(RLS) を採用した。 1. マルチテナントの分離パターン比較 マルチテナントのデータ分離には主に3つのアプローチがある。 パターン比較表 パターン 分離レベル 実装コスト 運用コスト スケーラビリティ Database per Tenant 最高(物理分離) 高い 高い 性能分離◎、運用面△ Schema per Tenant 高い(論理分離) 中程度 中程度(自動化必須) 中程度 Shared Schema + RLS 高い(設計次第) 低い 低い 高い(設計次第) Database per Tenant テナントごとに独立したデータベースを持つ。 ...

January 15, 2026 · 7 分 · ko-chan