Overview
In traditional databases, you define tables with schemas. In SnackBase, you define Collections, which:- Store schema metadata in the
collectionstable - Create/update physical tables dynamically
- Auto-generate REST API endpoints
- Provide validation and type safety
- Support relationships between collections
- Protect sensitive data with PII masking
What is a Collection?
A Collection is a named data schema with fields, types, and configuration options.Collection Structure
Components of a Collection
| Component | Purpose | Example |
|---|---|---|
| name | Unique identifier, becomes table name | posts → col_posts table |
| description | Human-readable description | ”Blog posts and articles” |
| schema | Field definitions with types and validation | See field types below |
| account_id | Owner account (for collection management) | AB1001 |
| migration_revision | Tracks which migration created/modified the collection | 20250101_create_posts |
Collection vs Table
Understanding the distinction is critical:The Confusion
How It Actually Works
When you create a collection namedposts:
- Schema Definition: Stored in
collectionstable (metadata) - Table Creation: Physical
col_poststable created (if doesn’t exist) - API Generation:
/api/v1/records/postsendpoints registered - Usage: All accounts use the same physical table
Table Naming Convention
Critical: Collection tables are prefixed withcol_ to avoid conflicts with system tables.
| Collection Name | Physical Table Name |
|---|---|
posts | col_posts |
products | col_products |
users | col_users |
Why This Design?
| Approach | Pros | Cons | SnackBase |
|---|---|---|---|
| Table per Account | Complete isolation | Thousands of tables, complex migrations | ❌ |
| Database per Account | Maximum isolation | Complex operations, resource intensive | ❌ |
| Shared Table | Simple, scalable, efficient | Requires account filtering | ✅ Chosen |
Field Types
Collections support multiple field types with built-in validation.Available Field Types
| Type | Description | Database Type | Example |
|---|---|---|---|
| text | Single-line text | VARCHAR | Name, title |
| number | Numeric value | NUMERIC | Price, quantity |
| boolean | True/false | BOOLEAN | is_published |
| datetime | Date/time with validation | TIMESTAMP | published_at, created_at |
| Email with validation | VARCHAR | [email protected] | |
| url | URL with validation | VARCHAR | https://example.com |
| json | JSON data | JSONB | metadata |
| reference | Reference to another collection | VARCHAR (FK) | user_id |
| file | File upload reference | VARCHAR | avatar_url |
Field Configuration
Each field type has specific configuration options:Text Field
Number Field
DateTime Field
Email Field
URL Field
JSON Field
Reference Field
File Field
Dynamic Table Generation
SnackBase dynamically creates and modifies database tables based on collection schemas.Table Creation Flow
Built-in Fields
Every collection table includes automatic fields you don’t need to define:| Field | Type | Description | Auto-Managed |
|---|---|---|---|
id | VARCHAR | Unique record ID | ✅ Auto-generated |
account_id | VARCHAR(10) | Account isolation | ✅ Automatic |
created_at | TIMESTAMP | Creation timestamp | ✅ Auto-set |
created_by | VARCHAR(50) | Creator user ID | ✅ Auto-set |
updated_at | TIMESTAMP | Last update timestamp | ✅ Auto-updated |
updated_by | VARCHAR(50) | Last updater user ID | ✅ Auto-updated |
Indexes and Constraints
SnackBase automatically creates:Auto-Generated APIs
Each collection automatically gets a complete REST API.Generated Endpoints
For a collection namedposts:
| Method | Endpoint | Description | Permission |
|---|---|---|---|
| GET | /api/v1/records/posts | List all records (with filtering) | posts:read |
| POST | /api/v1/records/posts | Create a new record | posts:create |
| GET | /api/v1/records/posts/:id | Get single record | posts:read |
| PATCH | /api/v1/records/posts/:id | Partial update record | posts:update |
| PUT | /api/v1/records/posts/:id | Full update record | posts:update |
| DELETE | /api/v1/records/posts/:id | Delete record | posts:delete |
| POST | /api/v1/records/posts/bulk | Bulk operations | posts:create/update/delete |
API Usage Examples
Query Filtering
List endpoints support powerful filtering:PII Masking
SnackBase provides automatic PII (Personally Identifiable Information) masking to protect sensitive user data.How PII Masking Works
PII fields are automatically masked for users who don’t have thepii_access group membership:
PII Mask Types
| Mask Type | Description | Example |
|---|---|---|
| Shows first character and domain | j***@example.com | |
| ssn | Shows only format | ***-**-**** |
| phone | Shows last 4 digits | ***-***-1234 |
| name | Shows first name initial and last initial | John D. |
| full | Completely hides value | ****** |
| custom | Custom mask pattern | Configurable |
Configuring PII Fields
To enable PII masking on a field, use thepii_mask configuration:
Reference Fields
Reference fields allow you to create relationships between collections using foreign keys.Reference Field Configuration
on_delete Actions
| Action | Description | Use Case |
|---|---|---|
| cascade | Delete referenced record when target is deleted | Dependent data (order items → orders) |
| set_null | Set field to NULL when target is deleted | Optional relationships |
| restrict | Prevent deletion if referenced | Critical references (users → orders) |
Reference Field Example
Reference Validation
When creating or updating records with reference fields:Schema Evolution
Collections can evolve over time with schema updates.Supported Changes
| Change | Supported | Notes |
|---|---|---|
| Add new field | ✅ Yes | New field added to table |
| Remove field | ❌ No | Field deletion is NOT allowed |
| Rename field | ❌ No | Must create new field instead |
| Change type | ❌ No | Type changes are NOT allowed |
| Modify field options | ✅ Yes | Adding options is supported |
Schema Update Flow
Schema Evolution Rules
Field Addition (Only supported operation):Best Practices
1. Naming Conventions
Use lowercase, plural names for collections:| Good | Bad |
|---|---|
posts | Posts |
users | user |
blog_posts | BlogPosts |
order_items | order-items |
2. Field Naming
Use snake_case for field names:3. Use Appropriate Field Types
Choose the most specific type for your data:4. Use JSON for Flexible Data
For metadata or varying structures:5. Plan Schema Evolution
Design schemas with evolution in mind:- Only add new fields (deletion and type changes are not allowed)
- Use
required: falsefor fields that might be optional later - Document schema changes in migration revisions
- Test schema updates in development first
6. Use PII Masking for Sensitive Data
Protect user privacy with automatic PII masking:7. Choose Appropriate on_delete Actions
Select the right action for reference fields:| Scenario | Action |
|---|---|
| Optional relationships (posts → authors) | set_null |
| Dependent data (order items → orders) | cascade |
| Critical references (prevent deletion) | restrict |
8. Avoid Too Many Collections
Each collection creates a table. Consider:- Can related data be in the same collection?
- Would JSON fields work better for varying schemas?
- Do you really need separate tables?
blog_posts and news_posts, use posts with a category field.
Summary
| Concept | Key Takeaway |
|---|---|
| Collection Definition | Named schema with fields, stored in collections table |
| Collection vs Table | Collections are metadata; ONE shared table per collection for ALL accounts |
| Table Naming | Tables prefixed with col_ (e.g., col_posts) |
| Field Types | 9 types available (text, number, boolean, datetime, email, url, json, reference, file) |
| Dynamic Tables | Tables created/modified automatically based on schema |
| Auto-Generated APIs | REST endpoints at /api/v1/records/{collection} |
| PII Masking | Automatic masking for sensitive data (email, ssn, phone, name) |
| Reference Fields | Foreign key relationships with on_delete actions |
| Schema Evolution | Only adding fields is allowed; deletion and type changes are NOT supported |
| Migration Tracking | migration_revision field tracks schema changes |
| Best Practices | Use lowercase plurals, snake_case fields, plan for evolution |