Mengapa Stack Ini?
Setiap komponen dipilih karena alasan spesifik:
- Next.js 14 (App Router) โ SSR bawaan = SEO optimal, Time to First Byte cepat, deploy ke Vercel zero-config dengan CDN global. Vercel dibuat oleh tim Next.js sendiri, sinerginya sempurna
- FastAPI (Python) โ Auto-generated Swagger docs, async native dengan asyncio, type hints yang memaksa kode bersih, dan ekosistem Python yang unbeatable untuk AI/ML integration
- PostgreSQL โ ACID compliance, JSON native (JSONB), schema-per-tenant multi-tenancy yang elegan, dan ekosistem tools terbaik di antara semua SQL database
Struktur Proyek Standard Kami
saas-project/ โโโ frontend/ # Next.js 14 โ โโโ app/ โ โ โโโ (dashboard)/ # Route group: halaman setelah login โ โ โ โโโ layout.tsx # Dashboard layout + auth check โ โ โ โโโ page.tsx # Main dashboard โ โ โ โโโ settings/ โ โ โโโ (auth)/ # Route group: login, register โ โ โ โโโ login/ โ โ โ โโโ register/ โ โ โโโ api/ # Next.js API Routes (BFF pattern) โ โโโ components/ โ โ โโโ ui/ # Reusable UI components โ โ โโโ features/ # Feature-specific components โ โโโ lib/ โ โโโ api.ts # API client โ โโโ utils.ts โ โโโ backend/ # FastAPI โ โโโ app/ โ โ โโโ api/v1/ โ โ โ โโโ auth.py โ โ โ โโโ users.py โ โ โ โโโ tenants.py โ โ โโโ models/ # SQLAlchemy ORM models โ โ โโโ schemas/ # Pydantic request/response schemas โ โ โโโ core/ โ โ โโโ config.py # Settings dari .env โ โ โโโ security.py # JWT, password hashing โ โ โโโ database.py # DB connection โ โโโ alembic/ # Database migrations โ โโโ docker-compose.yml # Local development
Auth Pattern yang Aman: HTTP-only Cookie
Jangan gunakan localStorage untuk JWT โ ini kerentanan XSS yang umum. Gunakan HTTP-only cookie:
# FastAPI โ set cookie setelah login berhasil
@router.post("/auth/login")
async def login(credentials: LoginSchema, response: Response, db: Session = Depends(get_db)):
user = authenticate_user(db, credentials.email, credentials.password)
if not user:
raise HTTPException(status_code=401, detail="Invalid credentials")
access_token = create_access_token(data={"sub": str(user.id)})
response.set_cookie(
key="auth_token",
value=access_token,
httponly=True, # JavaScript tidak bisa akses
secure=True, # HTTPS only
samesite="strict", # CSRF protection
max_age=7 * 24 * 3600 # 7 hari
)
return {"status": "ok", "user_id": user.id}Multi-tenant dengan Schema PostgreSQL
Untuk setiap tenant baru, kita buat schema PostgreSQL tersendiri. Data benar-benar terisolasi tanpa perlu database terpisah:
-- PENTING: gunakan %1$I (positional) bukan %I saja
-- Bug umum yang susah di-debug!
CREATE OR REPLACE FUNCTION provision_tenant(tenant_slug TEXT)
RETURNS void AS $$
BEGIN
-- Buat schema baru
EXECUTE format('CREATE SCHEMA IF NOT EXISTS %1$I', tenant_slug);
-- Buat tabel utama
EXECUTE format('
CREATE TABLE %1$I.users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email TEXT UNIQUE NOT NULL,
role TEXT DEFAULT ''member'',
created_at TIMESTAMPTZ DEFAULT NOW()
)
', tenant_slug);
EXECUTE format('
CREATE TABLE %1$I.transactions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
amount DECIMAL(15,2) NOT NULL,
description TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
)
', tenant_slug);
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;Deployment: Vercel + VPS
Frontend โ Vercel
Setup paling sederhana untuk Next.js. Connect GitHub repo, set environment variables, done. Preview deployment otomatis untuk setiap PR โ sangat membantu untuk review dengan klien.
# vercel.json โ konfigurasi minimal
{
"buildCommand": "npm run build",
"outputDirectory": ".next",
"env": {
"NEXT_PUBLIC_API_URL": "https://api.yourdomain.com"
}
}Backend โ VPS dengan Nginx + PM2
Kami menggunakan VPS IDCloudHost Singapore (latensi rendah ke Indonesia). Setup standar:
# ecosystem.config.js untuk PM2
module.exports = {
apps: [{
name: 'saas-backend',
script: 'uvicorn',
args: 'app.main:app --host 0.0.0.0 --port 8000 --workers 2',
interpreter: '/path/to/venv/bin/python',
env: { NODE_ENV: 'production' },
error_file: './logs/err.log',
out_file: './logs/out.log'
}]
}
# Nginx config
server {
server_name api.yourdomain.com;
location / {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}Tips penting untuk Vercel deployment: Kalau ada config.js atau file yang perlu dimodifikasi saat build, gunakan buildCommand di vercel.json dengan sed injection daripada memodifikasi file langsung. Ini menghindari masalah file reverting ke versi lama setelah deployment.
Kapan Tidak Pakai Stack Ini?
- Proyek sederhana tanpa AI/ML: Next.js fullstack dengan API Routes saja sudah cukup. Tidak perlu FastAPI terpisah
- Tim sudah expert PHP/Laravel: Jangan paksa ganti stack. Laravel + Vue/React lebih masuk akal
- Budget sangat terbatas: Supabase (BaaS) kurangi overhead backend signifikan. Trade-off: vendor lock-in
- Prototype cepat: T3 Stack (Next.js + tRPC + Prisma) lebih cepat untuk proof of concept