What It Is#
Saimin 2 is a browser-based recreation of Saimin Chat System — a real multi-user BBS that ran on an Apple II+ in Aiea, Hawaii in the 1980s and early 1990s. Five phone lines, 300 baud, a small community of regulars who dialed in to chat in real time.
The recreation preserves the original user experience exactly: a character-mode terminal in the browser, 15 numbered lines, the same community moderation mechanics, the same time-allocation model, and the same welcome screen. When the lines are full, you get a system-busy message. That is the entire feature set, by design.
Site: saimin2.com
Stack#
Frontend: xterm.js in the browser over a WebSocket connection. VT100/ANSI character-mode terminal rendering. No web framework, no SPA — the interface is the terminal.
Backend: Python 3.12 and FastAPI with native asyncio WebSocket support. All 15 connections are managed by a single in-process event loop. Ephemeral session state — line assignments, session handles, strike counts, authentication flags — lives in process memory and resets on restart, preserving the original BBS behavior.
Data: SQLite in WAL mode via aiosqlite, managed with Alembic migrations. The entire persistent dataset — member records, time balance ledger, message boards, audit log — is a single file on a PersistentVolumeClaim.
Billing: Stripe Checkout for membership subscriptions. Card data never contacts BBS infrastructure. Webhooks trigger member provisioning and status updates.
Deployment: Single Kubernetes pod with a PersistentVolumeClaim for the SQLite file. Monthly time-credit allocation runs as a Kubernetes CronJob.
Notable Decisions#
SQLite over PostgreSQL (ADR-012): The original Saimin ran on a single machine with a floppy disk as its store. An embedded SQLite file is closer to that model and eliminates an entire infrastructure component. The WAL mode write throughput is adequate for 15 concurrent users; the Alembic migration path handles schema evolution. An earlier PostgreSQL deployment was replaced by ADR-012.
Single-process asyncio, no external message broker: Chat fan-out is handled entirely in-process. At 15 connections, the complexity of Redis pub/sub or a message queue produces no benefit and considerable operational cost. The design ceiling is explicit — this system is not built to scale beyond 15 lines — so the architecture reflects that constraint rather than hedging against it.
No web framework on the frontend: The client is xterm.js wired to a WebSocket. No React, no SPA, no client-side routing. The interface is the terminal; that is the product.
Enterprise Architecture Methodology#
The project is unusual in that the entire architecture was designed before any application code was written.
The governance framework includes:
- TOGAF 10 methodology (adapted for project scale, not strict compliance)
- Architecture Review Board with formal ADR (Architecture Decision Record) process — 12 ADRs ratified as of the architecture phase
- Business capability model — 19 capability domains across four BIAN-inspired tiers
- Full requirements documentation — Business Requirements Document, Functional Requirements Specification, Non-Functional Requirements, and UAT Protocol
- Traceability matrix linking business objectives through requirements to capabilities and ADRs
- EA Landscape Register and formal project engagement model
The architecture documentation is published openly on saimin2.com. This makes the project interesting in two directions: as a faithful BBS recreation, and as a live example of what formal EA governance looks like applied at community scale.
Community Governance#
Saimin 2 is designed to be self-governing. The ARB is in bootstrap configuration during build. As the system moves to live operation and a member community forms, governance is intended to transition to member voting — on architecture direction, features, and community rules — replicating how the original Saimin community governed itself. The governance framework was designed with that transition in mind from the start.
Membership fees cover hosting costs. Any surplus at year end is donated to charity.