Overview
SnackBase enables Software-as-a-Service (SaaS) applications by allowing multiple independent tenants (accounts) to coexist in a single database while maintaining complete data isolation.Key Characteristics
Account Model
What is an Account?
An Account (also called a “tenant” or “organization”) represents an isolated workspace containing:- Users who belong to the account
- Collections (data schemas) defined for the account
- Records (actual data) created by the account’s users
- Roles and permissions specific to the account
- Groups for organizing users
- Configuration overrides for providers (auth, email, storage)
Account Hierarchy
Data Isolation
How Isolation Works
Most tables in SnackBase include anaccount_id column that references the accounts table:
Tables WITHOUT account_id (Global Tables)
The following tables do not have anaccount_id column because they define global structures shared by all accounts:
Automatic Filtering
SnackBase automatically filters all queries byaccount_id. Users never see data from other accounts.
Example API Request:
account_id—it’s automatically added based on their authentication context.
Enforcement Layers
Isolation is enforced at multiple layers for defense-in-depth:Two-Tier Architecture
SnackBase uses a two-tier table architecture that’s critical to understand:Tier 1: Core System Tables
These tables define the platform structure and are shared across all accounts:
Important: Schema changes to these tables only happen via SnackBase releases.
Tier 2: User-Created Collections
User collections are single physical tables shared by ALL accounts:
Critical Concept: When you create a collection named “posts”, you’re creating:
- A schema definition in the
collectionstable (metadata) - A physical table named
col_posts(if it doesn’t exist) - All accounts’ post data goes into this single shared table
Physical Table Naming Convention
Collection tables are prefixed withcol_ to avoid conflicts with system tables:
This prefix:
- Prevents naming conflicts with system tables
- Makes it clear which tables are user-created collections
- Allows easy identification of collection tables in database dumps
Why This Architecture?
Account Identifiers
Accounts have three distinct identifiers that serve different purposes:Identifier Comparison
Account ID (UUID)
The internal primary key for accounts is a standard UUID:- Purpose: Primary key, used in foreign key references
- Format: Standard UUID v4 (36 characters)
- Used by:
account_idcolumns in all tenant-scoped tables - Human-readable: No (designed for systems, not humans)
Account Code (XX####)
The human-readable identifier for accounts:- Letters (XX): Random uppercase letters A-Z
- Digits (####): Sequential number starting from 0001
- Total Capacity: 6,760,000 unique codes (26×26×10,000)
- Reserved Range: SY#### (skipped during generation)
Account Code Generation
Account codes are generated sequentially from the highest existing code:- Codes are never reused
- Sequential generation ensures predictability
- SY#### range is permanently reserved
- System account uses SY0000
Identifier Usage
System Account vs User Accounts
System Account (SY0000)
The system account is a special reserved account for superadmin operations:
Superadmin users are linked to the system account and have:
- Access to ALL accounts
- Ability to create/manage accounts
- Ability to manage global collections
- System-wide visibility (can pass
account_id=Noneto see all data)
User Accounts
User accounts are regular tenant accounts created by superadmins:
Regular users (even with “admin” role) are linked to a specific account and have:
- Access ONLY to their account
- No cross-account visibility
- Full CRUD within their account (based on permissions)
Multi-Account Users
Enterprise Multi-Account Model
SnackBase supports enterprise multi-account scenarios where a single user can belong to multiple accounts with different roles and permissions.User Identity
A user’s identity is defined by the (email, account_id) tuple:[email protected]) can exist in multiple accounts with different roles.
Password Scope
Passwords are per-account, not per-email. This means:[email protected]in accountAB1001has passwordPassword1![email protected]in accountXY2048has passwordPassword2!- These are different credentials even though the email is the same
Login Flow
When logging in, users must specify their account: Option 1: Account in URLConfiguration Hierarchy
SnackBase uses a hierarchical configuration model for provider settings (authentication, email, storage, etc.):Two-Level Hierarchy
Configuration Resolution
When resolving a provider configuration:- Check account-level config for the specific account
- If not found, use system-level default
- Merge with fallback values for any missing keys
Use Cases
Key Points
- System-level configs use the nil UUID (
00000000-0000-0000-0000-000000000000) - Account-level configs use the account’s UUID as
account_id - Resolution is cached for 5 minutes for performance
- Built-in providers are marked with
is_builtinflag (cannot be deleted)
Implications for Developers
When Building Applications
Understanding multi-tenancy is critical when building on SnackBase:1. Never Store Account ID Manually
2. Account Isolation is Automatic
You don’t need to write WHERE clauses for account filtering:3. Cross-Account Queries Are Impossible
By design, you cannot query across accounts:account_id=None to bypass filtering:
4. Collections Are Global
When creating a collection, remember:- The collection schema is shared across ALL accounts
- The physical table (
col_<name>) is shared across ALL accounts - Each account only sees their own data (via
account_idfiltering)