Organizing Metadata for Large Projects
Organizing Metadata for Large Projects
When building enterprise-scale applications with ObjectQL, proper metadata organization becomes critical. This guide demonstrates best practices for structuring your object definitions, actions, hooks, and translations in a maintainable way.
The Challenge
As your application grows beyond 30-50 objects, a flat file structure becomes problematic:
Problems with Flat Structure:
- ❌ Hard to find related objects
- ❌ Merge conflicts when multiple teams work simultaneously
- ❌ Unclear ownership boundaries
- ❌ Can't deploy modules independently
- ❌ Difficult to understand relationships
Recommended Structure: Domain-Driven Modules
For applications with 30+ objects and multiple teams, organize by business domain:
Real-World Example
See the complete working example at:
This demonstrates:
- ✅ 20+ objects organized across 5 modules
- ✅ Domain-driven structure (CRM, HR, Finance, Project)
- ✅ Cross-module relationships
- ✅ Extension pattern for customization
- ✅ Comprehensive indexing strategy
- ✅ Multi-language support (en, zh-CN)
- ✅ Module documentation
Module Anatomy
Each module follows a consistent pattern:
Module Documentation Template
Each module should have a README explaining:
- Overview - What business domain it covers
- Objects - List of objects with descriptions
- Relationships - How objects relate to each other
- Team Ownership - Who maintains this module
- Dependencies - What other modules/objects it depends on
- Usage Examples - Common query patterns
Object Naming Conventions
File-Based Naming
ObjectQL uses filename-based identification. The object name is automatically inferred from the filename (without the .object.yml extension), eliminating redundancy.
Examples:
crm_account.object.yml→ Object name:crm_accountfinance_invoice.object.yml→ Object name:finance_invoiceproject_task.object.yml→ Object name:project_task
Inside the file, you no longer need to specify name: crm_account - it's inferred from the filename!
Prefixing Strategy
For large projects with multiple modules, use prefixes in your filenames to avoid name collisions:
When to prefix:
- ✅ Multi-module applications (30+ objects)
- ✅ Plugin architectures
- ✅ When similar concepts exist across domains
When NOT to prefix:
- ❌ Core shared objects (
user.object.yml,organization.object.yml) - ❌ Small applications (< 30 objects)
- ❌ When it reduces clarity
Dependency Management
Dependency Layers
Cross-Module References
When modules need to reference each other's objects:
Best Practices:
- Document cross-module dependencies in module README
- Avoid circular dependencies
- Use core objects to break dependency cycles
- Consider extracting shared concepts to core layer
Index Strategy by Module
Different modules have different performance requirements:
High-Traffic Modules (CRM, Sales)
Low-Traffic Modules (Admin, Config)
Extension Pattern
Use extensions to customize objects without modifying source files.
Original (core/objects/user.object.yml):
Extension (extensions/user.extension.object.yml):
Result: ObjectQL merges both definitions, adding employee_id and making email required.
Internationalization at Scale
Three-Layer i18n Strategy
Directory Structure
Migration Path
From Flat to Modular
Step 1: Analyze Group existing objects by business domain.
Step 2: Plan Create module structure, decide on prefixes.
Step 3: Migrate Gradually
Step 4: Update References Update imports and references to use new module structure.
Step 5: Clean Up Remove legacy flat structure once migration is complete.
Project Size Guidelines
| Size | Objects | Teams | Recommended Structure |
|---|---|---|---|
| Small | 1-30 | 1 | Flat objects/ directory |
| Medium | 30-100 | 2-3 | Domain modules |
| Large | 100-500 | 5-10 | Modules + plugins |
| Enterprise | 500+ | 10+ | Monorepo with packages |
Testing Strategy
Module Tests
Object Schema Tests
Complete Working Example
Explore the full example with 20+ objects:
The example includes:
- Core module (user, organization, attachment)
- CRM module (account, contact, opportunity, lead)
- HR module (employee, department, position, timesheet)
- Finance module (invoice, payment, expense, budget)
- Project module (project, task, milestone, timesheet entry)
- Extensions pattern
- Multi-language support
- Comprehensive documentation
Key Takeaways
- Start simple - Don't over-engineer for small projects
- Think in domains - Organize by business capability, not technical layers
- Document boundaries - Make module ownership and dependencies explicit
- Plan for scale - Use prefixes and modules when you hit 30-50 objects
- Test modules - Each module should be testable independently
- Version control - Use module-level versioning for independent deployments
See Also
- Data Modeling Guide
- Plugin Development
- Logic Hooks
- See examples in the repository under
examples/directory