This file provides guidance to WARP (warp.dev) when working with code in this repository.
100-Year SaaS is a minimalist, boring-on-purpose Go application designed for extreme durability and simplicity. The project follows the principles of protocols over frameworks, using HTTP, HTML, and SQL with a single-binary approach that can run for decades with minimal maintenance.
Status: This is a complete, production-ready SaaS platform with authentication, multi-tenancy, analytics, subscriptions, background jobs, rate limiting, and email notifications. All features are maintenance-free and use only SQLite + standard library.
- Install Go: Download and install Go 1.22 or later from https://golang.org/dl/
- Install dependencies:
go mod tidy - Run the application:
- On Windows:
.\run.ps1 - On Unix/Linux/macOS:
make run
- On Windows:
- Open your browser: Navigate to http://localhost:8080
- Start adding items: Use the simple web interface to create and manage items
This is a full-stack web application with a simple 3-tier architecture:
[Static HTML/CSS/JS] → [Caddy Proxy] → [Go HTTP Server] → [SQLite Database]
Key Components:
- Go Server (
cmd/server/main.go): Single binary HTTP server with embedded static files and database migrations - SQLite Database (
internal/db/schema.sql): Single-file ACID database with idempotent migrations, includes all SaaS tables - Static Frontend (
web/): Vanilla HTML/CSS/JS with no build tools or frameworks - Caddy Proxy (
Caddyfile): Auto-HTTPS reverse proxy for production deployment - Docker Support: Multi-stage Dockerfile using distroless base for minimal attack surface
SaaS Features (Zero Maintenance):
- Authentication (
internal/auth/): User registration, login, session management with auto-cleanup - Multi-tenancy (
internal/saas/): Complete tenant isolation, subscription limits, role-based access - Analytics (
internal/analytics/): Usage tracking, reporting, real-time stats with automatic data rotation - Background Jobs (
internal/jobs/): SQLite-based job queue with retries and scheduled tasks - Rate Limiting (
internal/http/): In-memory token bucket algorithm with auto-cleanup - Email Service (
internal/email/): SMTP-based notifications with template system
# Run the application locally (Unix/Linux/macOS)
make run
# Alternative: DB_PATH=data/app.db APP_SECRET=local go run ./cmd/server
# Run on Windows PowerShell
.\run.ps1
# Alternative: $env:DB_PATH="data/app.db"; $env:APP_SECRET="local"; go run ./cmd/server
# Build production binary (Unix/Linux/macOS)
make build
# Alternative: CGO_ENABLED=0 go build -o bin/app ./cmd/server
# Build on Windows PowerShell
.\build.ps1
# Alternative: $env:CGO_ENABLED="0"; go build -o bin/app.exe ./cmd/server
# Format Go code
make fmt
# Alternative: gofmt -s -w .
# Clean up dependencies
make tidy
# Alternative: go mod tidy# Build Docker image
docker build -t 100y-saas .
# Run with persistent data volume
docker run -p 8080:8080 -v $(pwd)/data:/data 100y-saas# Run Caddy for auto-HTTPS (after building the Go binary)
caddy run --config Caddyfile# Manual backup
./backup.sh
# Or with custom paths
DB_PATH=data/app.db BACKUP_DIR=backups ./backup.shEmbedded Assets Pattern: Static files and SQL migrations are embedded in the Go binary using //go:embed, eliminating deployment complexity.
Idempotent Migrations: Database schema changes use CREATE TABLE IF NOT EXISTS and INSERT OR IGNORE patterns to safely run on every startup.
Zero-Dependency Frontend: No build tools, bundlers, or frameworks - just vanilla HTML/CSS/JS that works everywhere.
Single-Binary Deployment: Everything needed to run the application is contained in one executable file.
Environment-Based Configuration: Uses environment variables with sensible defaults (DB_PATH, APP_SECRET).
- Keep all HTTP handlers in the main.go file for simplicity
- Use standard library types (
http.Handler,sql.DB) over abstractions - Embed all assets and migrations directly in the binary
- Prefer explicit SQL queries over ORMs
- HMAC-signed cookies for session management
- Security headers set by default (
X-Content-Type-Options,X-Frame-Options, etc.) - Content Security Policy restricts to same-origin resources
- Non-root user execution in Docker
- All data is exportable via
/exportendpoint (returns CSV) - SQLite database is a single file that can be copied/backed up easily
- No vendor lock-in - uses standard SQL and file formats
DB_PATH: Path to SQLite database file (default:data/app.db)APP_SECRET: Secret key for cookie signing (default:change-me- must change in production)
- Add handler function following the
itemsHandlerpattern - Register route in main function:
mux.HandleFunc("/api/newroute", app.newHandler) - Update database schema in
internal/db/schema.sqlif needed
- Add
CREATE TABLE IF NOT EXISTSstatement toschema.sql - Update the
metatable schema version if needed - Add corresponding Go structs and handlers
- Build binary:
make build - Copy
bin/app,Caddyfile, and createdata/directory to server - Set
APP_SECRETenvironment variable to a random string - Run Caddy and the Go binary as separate processes or use Docker
- Use the provided
backup.shscript - Schedule via cron:
15 2 * * * /path/to/backup.sh - Store backups in separate location from primary database
- SQLite supports online backups without stopping the application
- User Management: Registration, login, session-based authentication
- Tenant Isolation: Complete data separation between organizations
- Subscription Limits: Automatic enforcement of item/user limits per plan
- Role-based Access: Owner/member roles within tenants
- Event Tracking: All user actions automatically tracked
- Usage Reports: Daily/monthly summaries, top users, event timelines
- Real-time Dashboard: Live stats without external services
- Data Retention: Automatic cleanup after 90 days
- SQLite-based Queue: No Redis or external queue required
- Automatic Retries: Exponential backoff for failed jobs
- Built-in Tasks: Session cleanup, analytics rotation, email sending
- Custom Jobs: Easy to add new background processing
- In-memory Limiting: Token bucket algorithm with auto-cleanup
- Flexible Keys: IP, user, or tenant-based rate limiting
- No External Store: Uses application memory, scales with instances
- Standard SMTP: Uses Go's built-in email capabilities
- Template System: Welcome emails, password resets, limit warnings
- Development Mode: Logs instead of sending during development
- Zero Dependencies: No external email services required
- Zero Maintenance: All features self-manage and auto-cleanup
- Single Database: Everything stored in one SQLite file
- No External Services: Completely self-contained
- Complete Data Ownership: No vendor lock-in or data sharing
- Predictable Costs: No per-request or usage-based pricing
📖 See SAAS_FEATURES_GUIDE.md for detailed implementation guide and examples