Enterprise-scale starter template for ObjectQL - Advanced metadata organization with modular architecture
npm install @objectql/starter-enterpriseThis example demonstrates best practices for organizing metadata in large-scale ObjectQL projects, suitable for enterprise applications with hundreds of objects and complex business domains.
When building large applications, poor metadata organization leads to:
- Difficulty finding objects - scattered files with no clear structure
- Merge conflicts - multiple teams editing the same files
- Unclear ownership - no way to know which team owns which domain
- Deployment risks - can't deploy modules independently
- Maintenance burden - hard to understand relationships between objects
This example shows a modular, domain-based organization pattern that scales to enterprise needs.
```
src/
โโโ core/ # Shared/Foundation Layer
โ โโโ objects/ # Base objects used across domains
โ โ โโโ user.object.yml
โ โ โโโ organization.object.yml
โ โ โโโ attachment.object.yml
โ โโโ i18n/
โ โ โโโ en/
โ โ โโโ zh-CN/
โ โโโ index.ts
โ
โโโ modules/ # Business Domain Modules
โ โโโ crm/ # Customer Relationship Module
โ โ โโโ objects/
โ โ โ โโโ crm_account.object.yml
โ โ โ โโโ crm_contact.object.yml
โ โ โ โโโ crm_opportunity.object.yml
โ โ โ โโโ crm_lead.object.yml
โ โ โโโ actions/
โ โ โ โโโ convert-lead.action.ts
โ โ โโโ hooks/
โ โ โ โโโ opportunity.hooks.ts
โ โ โโโ i18n/
โ โ โ โโโ en/
โ โ โ โโโ zh-CN/
โ โ โโโ README.md
โ โ โโโ index.ts
โ โ
โ โโโ hr/ # Human Resources Module
โ โ โโโ objects/
โ โ โ โโโ hr_employee.object.yml
โ โ โ โโโ hr_department.object.yml
โ โ โ โโโ hr_position.object.yml
โ โ โ โโโ hr_timesheet.object.yml
โ โ โโโ actions/
โ โ โโโ hooks/
โ โ โโโ i18n/
โ โ โโโ README.md
โ โ โโโ index.ts
โ โ
โ โโโ finance/ # Finance & Accounting Module
โ โ โโโ objects/
โ โ โ โโโ finance_invoice.object.yml
โ โ โ โโโ finance_payment.object.yml
โ โ โ โโโ finance_expense.object.yml
โ โ โ โโโ finance_budget.object.yml
โ โ โโโ actions/
โ โ โโโ hooks/
โ โ โโโ i18n/
โ โ โโโ README.md
โ โ โโโ index.ts
โ โ
โ โโโ project/ # Project Management Module
โ โโโ objects/
โ โ โโโ project_project.object.yml
โ โ โโโ project_task.object.yml
โ โ โโโ project_milestone.object.yml
โ โ โโโ project_timesheet_entry.object.yml
โ โโโ actions/
โ โโโ hooks/
โ โโโ i18n/
โ โโโ README.md
โ โโโ index.ts
โ
โโโ extensions/ # Custom Extensions/Overrides
โ โโโ user.extension.object.yml
โ โโโ README.md
โ
โโโ shared/ # Shared Utilities
โ โโโ constants.ts
โ โโโ validators.ts
โ โโโ utils.ts
โ
โโโ index.ts # Application Entry Point
)
- Business logic (actions & hooks)
- Translations (i18n)
- Documentation$3
`
Application Layer (modules/*)
โ
Foundation Layer (core/*)
โ
External Plugins
`$3
Each module can be owned by a different team:
- modules/crm/ โ Sales Team
- modules/hr/ โ HR Team
- modules/finance/ โ Finance Team$3
Modules can be:
- Developed in parallel
- Tested independently
- Deployed as feature flags
- Extracted to separate packages๐ฆ Module Structure
Each module follows this pattern:
`
modules/[domain]/
โโโ objects/ # Domain object definitions
โโโ actions/ # Custom actions (*.action.ts)
โโโ hooks/ # Lifecycle hooks (*.hooks.ts)
โโโ i18n/ # Module-specific translations
โ โโโ en/
โ โโโ zh-CN/
โโโ README.md # Module documentation
โโโ index.ts # Module exports
`๐ Object Naming Conventions
$3
For large projects, consider prefixing object names:`yaml
โ Bad: Name collision risk
name: taskโ
Good: Clear module ownership
name: project_task
`When to prefix:
- โ
When multiple modules might have similar concepts
- โ
In multi-tenant or plugin architectures
- โ When it's clearly a core shared object (e.g.,
user, organization)$3
`
[object_name].object.yml # Object definition
[object_name].action.ts # Actions for this object
[object_name].hooks.ts # Hooks for this object
[object_name].data.yml # Seed data (optional)
`๐ Internationalization at Scale
$3
1. Core Layer (
core/i18n/)
- Shared objects (user, organization)
- Common UI labels
2. Module Layer (modules/[domain]/i18n/)
- Domain-specific objects
- Business terminology3. Extension Layer (
extensions/i18n/)
- Customer-specific customizations
- Regional variants$3
`
core/i18n/
en/
user.json
organization.json
zh-CN/
user.json
organization.jsonmodules/crm/i18n/
en/
account.json
opportunity.json
zh-CN/
account.json
opportunity.json
`๐ Index & Performance Strategy
$3
For single-column lookups:
`yaml
fields:
email:
type: text
unique: true # Creates unique index
status:
type: select
index: true # Creates regular index
`$3
Define at object root for multi-column queries:
`yaml
indexes:
# For query: WHERE status = 'open' ORDER BY created_at DESC
status_created_idx:
fields: [status, created_at]
# For unique constraint: UNIQUE(company_id, email)
company_email_unique:
fields: [company_id, email]
unique: true
`$3
High-Traffic Modules (CRM, Finance):
- Add indexes on every filter field
- Use composite indexes for common query patterns
- Monitor query performance regularly
Low-Traffic Modules (HR, Admin):
- Basic indexes on primary lookup fields
- Add more as needed based on usage
๐งฉ Extension Pattern
Use extensions to customize objects without modifying core definitions:
Core Definition (
core/objects/user.object.yml):
`yaml
name: user
fields:
name: { type: text }
email: { type: text }
`Extension (
extensions/user.extension.object.yml):
`yaml
name: user # Same name triggers merge
fields:
# Add custom field
employee_id:
type: text
label: Employee ID
# Override existing field
email:
required: true
unique: true
`๐งช Testing Strategy
$3
Test individual object schemas:
`typescript
// modules/crm/objects/__tests__/account.test.ts
describe('Account Object', () => {
it('should have required fields', () => {
const account = loadObject('account');
expect(account.fields.name.required).toBe(true);
});
});
`$3
Test module interactions:
`typescript
// modules/crm/__tests__/integration.test.ts
describe('CRM Module', () => {
it('should convert lead to opportunity', async () => {
// Test cross-object logic
});
});
`๐ Real-World Size Reference
| Project Size | Objects | Modules | Teams | Structure |
|--------------|---------|---------|-------|-----------|
| Small (Startup) | 10-30 | 1-2 | 1 | Flat
/objects/ |
| Medium (Scale-up) | 30-100 | 3-5 | 2-3 | /modules/ by domain |
| Large (Enterprise) | 100-500 | 8-15 | 5-10 | /modules/ + /plugins/ |
| Very Large (Platform) | 500+ | 15+ | 10+ | Monorepo with packages |๐ Migration Path
$3
1. Analyze - Group objects by business domain
2. Create - Create module directories
3. Move - Relocate objects to appropriate modules
4. Test - Verify imports and references still work
5. Document - Update README files
$3
You don't have to reorganize everything at once:
`
src/
โโโ objects/ # Legacy flat structure (deprecated)
โโโ modules/ # New modular structure
โ โโโ crm/ # Start with one module
โโโ index.ts # Loads from both
`๐ก Pro Tips
1. Start Simple - Don't over-engineer for 10 objects. Use modules when you hit 30-50 objects.
2. Document Boundaries - Each module README should explain:
- What business domain it covers
- Key objects and relationships
- Team ownership
- Dependencies on other modules
3. Avoid Circular Dependencies - Use shared objects in
core/ to break cycles.4. Version Control - Use
.gitignore to exclude generated files:
`
dist/
*.generated.ts
node_modules/
`5. Code Generation - Run
objectql generate` to create TypeScript types for each module separately.- Data Modeling Guide
- Plugin Development
- ObjectQL Architecture
This is a living example. If you have suggestions for enterprise-scale patterns, please open an issue or PR!