Reusable, copy-paste backend services for mobile apps. Zero hosting fees tier, minimal friction.
| Layer | Choice | Rationale |
|---|---|---|
| Runtime | Go | 50-100ms cold starts, cheap compute, type safety |
| Hosting | Google Cloud Run | Scale to zero, free tier, no server management |
| Database | Firestore | Document DB, free tier, Firebase ecosystem |
| Auth | Firebase Auth | Built-in magic link (email link sign-in), OAuth, no extra email service |
| Firebase (built-in) | Magic links handled by Firebase Auth, no verification fees |
- One instance per app (copy-paste, separate Firebase projects)
- No multi-tenant complexity
- Breaking changes don't cascade across apps
Thin wrapper around Firebase Auth. Firebase handles:
- Magic link generation & email delivery
- Google OAuth (when needed)
- Token issuance & refresh
User Service handles:
- Custom claims (roles, org membership)
- User metadata in Firestore
- Token verification for other services
Organization/team management.
{
"id": "firebase-uid",
"email": "user@example.com",
"createdAt": timestamp,
"updatedAt": timestamp,
"metadata": { ... } // app-specific only
}
{
"id": "firebase-generated",
"name": "Acme Corp",
"slug": "acme-corp",
"createdAt": timestamp,
"updatedAt": timestamp,
"metadata": { ... } // app-specific only
}
Join table for user-org relationships. Single source of truth.
{
"id": "auto-generated",
"userId": "firebase-uid",
"orgId": "org-id",
"role": "admin" | "member",
"active": true,
"joinedAt": timestamp,
"updatedAt": timestamp,
"metadata": { ... } // app-specific only
}
Firestore indexes needed:
userId(query: "all orgs for user X")orgId(query: "all members of org X")orgId + role(query: "all admins of org X")
Enforces slug uniqueness (Firestore has no unique constraints).
{
"orgId": "org-id"
}
Create slug doc in transaction with org creation. If slug exists, transaction fails.
1. Mobile app → Firebase SDK: signInWithEmailLink(email)
2. Firebase → sends magic link email
3. User clicks link → deep link opens app (Android App Links / iOS Universal Links)
4. App → Firebase SDK: complete sign-in with link
5. App receives Firebase ID token
6. App → Backend: requests with ID token in Authorization header
7. Backend → verifies token via Firebase Admin SDK
- Pure REST API (no web frontend)
- Firebase ID token in
Authorization: Bearer <token>header - All documents have
metadatafield for app-specific flexibility - Contracts defined on Kotlin side
- Services are stateless, all state in Firestore
- Why: Single source of truth, no dual-write consistency issues
- Trade-off: Extra query to get org members (vs embedded)
- Worth it: Cleaner, familiar pattern, queryable both directions
- Service fields: Real columns (queryable, indexable, typed)
- App-specific fields:
metadataobject (flexible, no backend changes) - Rule: If every app needs it → real column. If app-specific → metadata.
- Problem: Firestore has no unique constraints
- Solution: Separate
slugscollection, transactional create
- Create composite indexes for common query patterns
memberships: userId, orgId, orgId+role- Indexes defined in
firestore.indexes.json, deployed with app
Each service is self-contained. Copy what you need to a new project.
/backend
/services
/user-service
main.go # entrypoint, wires everything up
handlers.go # HTTP handlers
models.go # structs + Firestore ops
/views # optional: QR codes, occasional HTML, etc.
/docs
api.md # API documentation
/org-service
main.go
handlers.go
models.go
/views # optional
/docs
api.md
/shared # copied with services to new projects
/auth
firebase.go # token verification
/firestore
client.go # Firestore client setup
helpers.go # common query patterns
/middleware
logging.go
cors.go
recovery.go
/response
json.go # standard JSON responses, errors
/deploy
firestore.indexes.json
firestore.rules
cloudbuild.yaml # optional: CI/CD
Copy-paste workflow for new app:
- Copy
/sharedfolder - Copy needed services (
/user-service,/org-service, etc.) - Copy
/deployconfig files - Update Firebase project ID
- Deploy
Deployment (Cloud Run source-based, no Dockerfile):
cd services/user-service
gcloud run deploy user-service --source .Cloud Run auto-detects Go and builds it. Add Dockerfile only if you need custom build control.
- Set up Go project structure
- Firebase project setup
- Implement User Service
- Implement Org Service
- Cloud Run deployment config