Last Updated: 2025-12-31
Status: ✅ Complete This guide explains how to use
custom_fields JSONB columns to extend Encore OS business entities with organization-specific metadata.
1. Purpose & Design Philosophy
Why Custom Fields?
Organizations have diverse workflows that can’t be predicted upfront:- Recovery housing orgs may track custom resident phases, external case IDs, or funding sources
- Healthcare providers may need custom credential categories, shift codes, or billing codes
- Multi-site operators may have site-specific identifiers, reporting codes, or compliance flags
custom_fields provides a type-safe, tenant-isolated extension point.
What Custom Fields Are NOT
- NOT a replacement for core schema design: Frequently-queried fields should be proper columns
- NOT a dumping ground: Use for organization-specific business data, not technical config
- NOT a security bypass:
custom_fieldsinherits table’s RLS policies
2. When to Use Custom Fields
Decision Tree
Examples by Category
3. Implementation Patterns
3.1 Adding Custom Fields to New Tables
Migration Template:3.2 Adding Custom Fields to Existing Tables
Migration Template:3.3 Backend: Querying Custom Fields (TypeScript + Supabase)
Basic Queries:3.4 Frontend: Rendering Custom Fields (React)
Type-Safe Custom Fields:4. Performance Considerations
When to Add GIN Indexes
Default: No index required for occasional queries. Add GIN index if:- Frequently filtering by custom_fields (e.g., dashboard queries)
- Complex JSONB queries (containment, existence checks)
- Query performance p95 > 500ms with EXPLAIN showing sequential scans
5. Security & RLS
Key Principle
custom_fields inherits table’s RLS policies. No separate RLS required.
Example:
What NOT to Store
Prohibited in custom_fields:- ❌ Passwords, API keys, secrets
- ❌ Social Security Numbers, full credit card numbers
- ❌ Unencrypted PHI (medical diagnoses, treatment notes)
- ❌ Data requiring separate access control from parent entity
- ✅ Badge numbers, employee IDs (non-sensitive identifiers)
- ✅ External system IDs (integration references)
- ✅ Workflow metadata (priority, status, dates)
- ✅ Business codes (cost centers, project codes, shift codes)
6. Testing Custom Fields
Unit Tests
RLS Tests
7. Migration Checklist
When adding custom_fields to a table:- Add column:
ADD COLUMN IF NOT EXISTS custom_fields JSONB DEFAULT '{}' NOT NULL - Add comment with 3-5 example use cases
- Verify RLS policies cover custom_fields (inherited automatically)
- Update TypeScript types if defining known custom fields
- Add integration tests for custom_fields persistence
- Add RLS tests for custom_fields tenant isolation
- Document in
specs/IMPLEMENTATION_LOG.md - Consider GIN index if frequently querying (defer until performance issue)
8. Common Patterns by Module
Platform Foundation (PF)
pf_profiles:Forms & Workflow (FW)
fw_form_submissions:Workforce & HR (HR)
hr_employees:9. Troubleshooting
Issue: Query Performance Slow
Symptom: Queries filtering by custom_fields take >500ms Solution:- Check EXPLAIN ANALYZE for sequential scans
- Add GIN index if frequently querying:
- Consider promoting frequently-queried field to proper column
Issue: Custom Fields Not Persisting
Symptom: Updates to custom_fields don’t save Debugging:- Check RLS policies allow UPDATE on table
- Verify column exists:
SELECT custom_fields FROM {table} LIMIT 1 - Check for TypeScript type errors in mutation
Issue: RLS Blocking Custom Fields Access
Symptom: Can’t read custom_fields even though user should have access Debugging:- Verify table has RLS policies
- Test with service role key (bypasses RLS) to confirm data exists
- Check RLS policies include necessary conditions
- Remember: custom_fields inherits table RLS, no separate policy needed
10. Future Enhancements
Planned:- Custom fields UI builder for admins (per-organization field definitions)
- Validation rules for custom fields (e.g., badge_number must match regex)
- Custom fields search across all tables
- Custom fields analytics/reporting
- Export custom fields schema per organization
- ❌ Promoting all custom fields to columns (defeats extensibility purpose)
- ❌ Custom RLS per custom field (inherits table RLS)
- ❌ Cross-organization custom field sharing (violates tenant isolation)
End of Custom Fields Guide