Organizations¶
Organizations represent tenants in a multi-tenant application.
Schema¶
The cf_organizations table contains:
| Field | Type | Description |
|---|---|---|
id |
UUID | Primary key |
name |
string | Display name |
slug |
string | URL-safe identifier |
logo_url |
string | Organization logo |
settings |
JSON | Custom configuration |
plan |
enum | Subscription tier |
active |
bool | Organization status |
created_at |
time | Creation timestamp |
updated_at |
time | Last modification |
Plans¶
Organizations have subscription plans:
free- Free tierstarter- Entry-level paidpro- Professional tierenterprise- Enterprise tier
Creating Organizations¶
org, err := client.Organization.Create().
SetName("Acme Corporation").
SetSlug("acme-corp").
SetPlan("pro").
SetSettings(map[string]any{
"timezone": "America/New_York",
"features": []string{"advanced_analytics"},
}).
Save(ctx)
Slugs¶
Slugs must be unique and URL-safe:
import "github.com/gosimple/slug"
orgSlug := slug.Make("Acme Corporation") // "acme-corporation"
org, err := client.Organization.Create().
SetName("Acme Corporation").
SetSlug(orgSlug).
Save(ctx)
Querying Organizations¶
By Slug¶
User's Organizations¶
orgs, err := client.Organization.Query().
Where(organization.HasMembershipsWith(
membership.UserIDEQ(userID),
)).
All(ctx)
With Members¶
org, err := client.Organization.Query().
Where(organization.IDEQ(orgID)).
WithMemberships(func(q *ent.MembershipQuery) {
q.WithUser()
}).
Only(ctx)
for _, m := range org.Edges.Memberships {
fmt.Printf("User: %s, Role: %s\n", m.Edges.User.Name, m.Role)
}
Settings¶
Organization settings store custom configuration:
// Update settings
org, err := client.Organization.UpdateOneID(orgID).
SetSettings(map[string]any{
"timezone": "Europe/London",
"branding": map[string]any{
"primary_color": "#3B82F6",
"logo_url": "https://example.com/logo.png",
},
}).
Save(ctx)
// Read settings
timezone := org.Settings["timezone"].(string)
Feature Checks by Plan¶
func canUseFeature(org *ent.Organization, feature string) bool {
switch org.Plan {
case "enterprise":
return true // All features
case "pro":
return feature != "sso" && feature != "audit_logs"
case "starter":
return feature == "basic_analytics"
default:
return false
}
}
Organization Edges¶
Organizations have relationships to:
| Edge | Target | Description |
|---|---|---|
memberships |
Membership | Organization members |
api_keys |
APIKey | Organization API keys |
oauth_apps |
OAuthApp | OAuth apps owned by org |
service_accounts |
ServiceAccount | Service accounts |
Multi-Tenant Queries¶
Scope All Queries to Organization¶
func getUsersInOrg(ctx context.Context, client *ent.Client, orgID uuid.UUID) ([]*ent.User, error) {
return client.User.Query().
Where(user.HasMembershipsWith(
membership.OrganizationIDEQ(orgID),
)).
All(ctx)
}
Organization Context¶
Store organization ID in context for automatic scoping:
type contextKey string
const orgKey contextKey = "organization_id"
func WithOrganization(ctx context.Context, orgID uuid.UUID) context.Context {
return context.WithValue(ctx, orgKey, orgID)
}
func OrganizationFromContext(ctx context.Context) uuid.UUID {
orgID, _ := ctx.Value(orgKey).(uuid.UUID)
return orgID
}