- Updated ESLint configuration to enforce stricter import rules for the @customer-portal/domain package, promoting better import hygiene and preventing deep imports. - Refactored various files across the BFF and portal applications to comply with the new import rules, ensuring that only the appropriate modules are imported from the domain. - Cleaned up unused imports and optimized code structure for improved maintainability and clarity. - Updated documentation to reflect changes in import practices and domain structure.
188 lines
6.2 KiB
Markdown
188 lines
6.2 KiB
Markdown
# Domain Toolkit
|
|
|
|
Utility functions and helpers for the domain layer. This package contains **utilities only**, not validation.
|
|
|
|
## Purpose
|
|
|
|
The toolkit provides pure utility functions for common operations like:
|
|
|
|
- String manipulation
|
|
- Date/time formatting
|
|
- Currency formatting
|
|
- URL parsing and manipulation
|
|
- Type guards and assertions
|
|
|
|
**Important**: For validation functions (e.g., `isValidEmail`, `isValidUuid`), use `packages/domain/common/validation.ts` instead.
|
|
|
|
## Structure
|
|
|
|
```
|
|
toolkit/
|
|
├── formatting/ # Formatting utilities
|
|
│ ├── currency.ts # Currency formatting (e.g., formatCurrency)
|
|
│ ├── date.ts # Date formatting (e.g., formatDate, formatRelativeTime)
|
|
│ ├── phone.ts # Phone number formatting
|
|
│ └── text.ts # Text manipulation (e.g., truncate, capitalize)
|
|
│
|
|
├── typing/ # Type utilities
|
|
│ ├── assertions.ts # Type assertions (e.g., assertNonNull)
|
|
│ ├── guards.ts # Type guards (e.g., isString, isNumber)
|
|
│ └── helpers.ts # Type helper functions
|
|
│
|
|
└── validation/ # Validation utilities (NOT validation itself)
|
|
├── email.ts # Email utilities (getEmailDomain, normalizeEmail)
|
|
├── url.ts # URL utilities (ensureProtocol, getHostname)
|
|
├── string.ts # String utilities (isEmpty, hasMinLength)
|
|
└── helpers.ts # Validation helpers (sanitizePagination, isInRange)
|
|
```
|
|
|
|
## Important Distinction: Validation vs Utilities
|
|
|
|
### ❌ Validation (NOT in toolkit)
|
|
|
|
Validation determines if input is valid or invalid:
|
|
|
|
```typescript
|
|
// These are VALIDATION functions → Use common/validation.ts
|
|
isValidEmail(email); // Returns true/false
|
|
isValidUuid(id); // Returns true/false
|
|
isValidUrl(url); // Returns true/false
|
|
validateUrlOrThrow(url); // Throws if invalid
|
|
```
|
|
|
|
**Location**: `packages/domain/common/validation.ts`
|
|
|
|
### ✅ Utilities (IN toolkit)
|
|
|
|
Utilities transform, extract, or manipulate data:
|
|
|
|
```typescript
|
|
// These are UTILITY functions → Use toolkit
|
|
getEmailDomain(email); // Extracts domain from email
|
|
normalizeEmail(email); // Lowercases and trims
|
|
ensureProtocol(url); // Adds https:// if missing
|
|
getHostname(url); // Extracts hostname
|
|
```
|
|
|
|
**Location**: `packages/domain/toolkit/`
|
|
|
|
## Usage Examples
|
|
|
|
### Formatting
|
|
|
|
```typescript
|
|
import { Formatting } from "@customer-portal/domain/toolkit";
|
|
|
|
const price = Formatting.formatCurrency(1000, "JPY"); // "¥1,000"
|
|
const date = Formatting.formatDate(new Date()); // "2025-10-08"
|
|
```
|
|
|
|
### Type Guards
|
|
|
|
```typescript
|
|
import { Typing } from "@customer-portal/domain/toolkit";
|
|
|
|
if (Typing.isString(value)) {
|
|
// TypeScript knows value is string here
|
|
console.log(value.toUpperCase());
|
|
}
|
|
```
|
|
|
|
### URL Utilities
|
|
|
|
```typescript
|
|
import { Validation } from "@customer-portal/domain/toolkit";
|
|
|
|
const fullUrl = Validation.ensureProtocol("example.com"); // "https://example.com"
|
|
const host = Validation.getHostname("https://example.com/path"); // "example.com"
|
|
```
|
|
|
|
### Email Utilities
|
|
|
|
```typescript
|
|
import { Validation } from "@customer-portal/domain/toolkit";
|
|
|
|
const domain = Validation.getEmailDomain("user@example.com"); // "example.com"
|
|
const normalized = Validation.normalizeEmail(" User@Example.COM "); // "user@example.com"
|
|
```
|
|
|
|
## When to Use What
|
|
|
|
| Task | Use | Example |
|
|
| --------------------- | ---------------------- | ------------------------------------------ |
|
|
| Validate email format | `common/validation.ts` | `isValidEmail(email)` |
|
|
| Extract email domain | `toolkit` | `Validation.getEmailDomain(email)` |
|
|
| Validate URL format | `common/validation.ts` | `isValidUrl(url)` |
|
|
| Add protocol to URL | `toolkit` | `Validation.ensureProtocol(url)` |
|
|
| Format currency | `toolkit` | `Formatting.formatCurrency(amount, "JPY")` |
|
|
| Format date | `toolkit` | `Formatting.formatDate(date)` |
|
|
|
|
## Best Practices
|
|
|
|
1. **Use validation functions for validation**
|
|
|
|
```typescript
|
|
// ✅ Good
|
|
import { isValidEmail } from "@customer-portal/domain/common/validation";
|
|
if (!isValidEmail(email)) throw new Error("Invalid email");
|
|
|
|
// ❌ Bad - don't write custom validation
|
|
if (!email.includes("@")) throw new Error("Invalid email");
|
|
```
|
|
|
|
2. **Use utility functions for transformations**
|
|
|
|
```typescript
|
|
// ✅ Good
|
|
import { Validation } from "@customer-portal/domain/toolkit";
|
|
const clean = Validation.normalizeEmail(email);
|
|
|
|
// ❌ Bad - don't duplicate utility logic
|
|
const clean = email.trim().toLowerCase();
|
|
```
|
|
|
|
3. **Don't mix validation and utilities**
|
|
|
|
```typescript
|
|
// ❌ Bad - mixing concerns
|
|
function processEmail(email: string) {
|
|
if (!email.includes("@")) return null; // Validation
|
|
return email.toLowerCase(); // Utility
|
|
}
|
|
|
|
// ✅ Good - separate concerns
|
|
import { isValidEmail } from "@customer-portal/domain/common/validation";
|
|
import { Validation } from "@customer-portal/domain/toolkit";
|
|
|
|
function processEmail(email: string) {
|
|
if (!isValidEmail(email)) return null;
|
|
return Validation.normalizeEmail(email);
|
|
}
|
|
```
|
|
|
|
## Migration Notes
|
|
|
|
If you're refactoring existing code:
|
|
|
|
1. **Validation functions** → Move to `common/validation.ts`
|
|
2. **Utility functions** → Keep in or move to `toolkit/`
|
|
3. **Business logic** → Move to domain-specific `validation.ts` files
|
|
|
|
## Related Documentation
|
|
|
|
- [Validation Patterns Guide](../../../docs/validation/VALIDATION_PATTERNS.md) - How to implement validation
|
|
- [Domain Layer Design](../../../docs/DOMAIN-LAYER-DESIGN.md) - Overall domain architecture
|
|
- [Common Validation](../common/validation.ts) - Validation functions
|
|
|
|
## Questions?
|
|
|
|
If you're unsure whether something belongs in toolkit or common/validation:
|
|
|
|
- **Ask**: "Does this determine if input is valid/invalid?"
|
|
- YES → It's validation → Use `common/validation.ts`
|
|
- NO → It's a utility → Use `toolkit/`
|
|
|
|
- **Ask**: "Does this transform or extract data?"
|
|
- YES → It's a utility → Use `toolkit/`
|
|
- NO → Might be validation → Use `common/validation.ts`
|