multi-tenancy-template
Spider-Gazelle Multitenancy Starter
Production-ready Spider-Gazelle template with PostgreSQL, multi-tenant organizations, and OAuth authentication.
Features
- PostgreSQL with migrations
- Multi-tenant organizations with permissions (Admin, Manager, User, Viewer)
- Authentication: username/password, Google OAuth, Microsoft OAuth
- OAuth token storage and refresh
- Organization invites and domain mapping
- Docker support
Quick Start
shards install
cp .env.example .env
# Edit .env with your PG_DATABASE_URL
crystal run src/app.cr
# Visit http://localhost:3000
Authentication
Username/Password
user = Models::User.new(name: "John", email: "john@example.com")
user.password = "secure_password"
user.save!
Or use crystal run create_test_user.cr
OAuth Setup
Google:
- Create OAuth credentials at Google Cloud Console
- Add redirect URI:
http://localhost:3000/auth/oauth/google/callback - Set
GOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRETin.env
Microsoft:
- Register app at Azure Portal
- Add redirect URI:
http://localhost:3000/auth/oauth/microsoft/callback - Set
MICROSOFT_CLIENT_IDandMICROSOFT_CLIENT_SECRETin.env
API Documentation
Generate OpenAPI docs:
crystal run src/app.cr -- --docs -f openapi.yml
Usage in Controllers
class MyController < App::Base
base "/organizations"
@[AC::Route::Filter(:before_action)]
private def authenticate
require_auth!
end
@[AC::Route::Filter(:before_action)]
private def find_organization(id : String)
@current_org = Models::Organization.find!(UUID.new(id))
end
getter! current_org : Models::Organization
@[AC::Route::Filter(:before_action)]
private def require_admin
require_permission!(current_org, Permissions::Admin)
end
@[AC::Route::GET("/:id/resources")]
def index : Array(Models::Resource)
Models::Resource.where(organization_id: current_org.id).to_a
end
end
Permission Levels
- Admin - Full control
- Manager - Manage members and resources
- User - Create and manage own resources
- Viewer - Read-only access
Database Schema
users- User accounts with password hashauth- OAuth provider linkages and tokensorganizations- Tenant organizations with subdomainorganization_users- Membership with permissionsorganization_invites- Pending invitationsdomains- Custom domain mappings
Environment Variables
Required:
PG_DATABASE_URL- PostgreSQL connection string
Optional:
SG_ENV- Environment (development/production)SG_SERVER_HOST- Server host (default: 127.0.0.1)SG_SERVER_PORT- Server port (default: 3000)COOKIE_SESSION_SECRET- Session encryption keyGOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRETMICROSOFT_CLIENT_ID/MICROSOFT_CLIENT_SECRETMICROSOFT_TENANT_ID- For single-tenant Microsoft apps
Testing
crystal spec
# or
./test
License
Do What the Fuck You Want To Public License
Repository
multi-tenancy-template
Owner
Statistic
- 0
- 0
- 0
- 0
- 6
- about 3 hours ago
- April 4, 2025
License
Do What The F*ck You Want To Public License
Links
Synced at
Wed, 03 Dec 2025 00:29:05 GMT
Languages