Domain Driven Design (DDD) Pattern for Our Agency
We organize code by domain boundaries — each domain represents a core business concept and contains all related logic, UI, data, and tests in one place. This makes scaling and maintenance straightforward.
Domain Folder Structure Explained
index.ts — The Barrel File
Acts as the public API for the domain. Controls what other parts of the app can import from this domain, enforcing clear boundaries.
composables/
Houses Vue composables related to the domain. These are reusable reactive hooks used inside Vue components (setup context).
services/
This is where the business logic lives — all domain-specific rules, workflows, and processes.
Also contains model.ts which defines the domain’s data shapes and validation schemas.
Example:
// services/model.ts
export interface User {
id: string
email: string
active: boolean
// etc.
}data/
The data access layer — acts as an API between the database (e.g. Firebase) and the domain.
Provides standard CRUD-like methods abstracted away from the rest of the domain, so changes to DB tech won’t ripple through your business logic.
const UserData = {
set: (userId: string, data: Partial<User>) => {
;/_ update DB _/
},
get: (userId: string) => {
;/_ fetch from DB _/
},
has: (userId: string) => {
;/_ check existence _/
},
delete: (userId: string) => {
;/_ remove from DB _/
},
}types/
Contains domain-specific TypeScript types, interfaces, and DTOs (data transfer objects). Keeps your domain strongly typed and consistent.
tests/
Unit and integration tests specific to the domain. Keeps tests close to the domain code for easy maintenance.
Summary
- Domains are self-contained feature modules with all related code.
index.tscontrols the domain’s external API (export only what’s needed).- Services contain business rules without leaking infrastructure code.
- Data abstracts database operations for flexibility and isolation.
- Keeps code modular, testable, and scalable — perfect for SaaS agencies. s