Initial commit
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
# Source Directory
|
||||
|
||||
This is the root of the application source code.
|
||||
|
||||
## Structure
|
||||
|
||||
The current codebase still contains an older layer-first layout.
|
||||
The preferred direction for new work is the context-first structure described in the docs:
|
||||
|
||||
- **`contexts/`**: first-class bounded contexts
|
||||
- **`workflows/`**: top-level cross-context orchestration
|
||||
- **`shared/`**: tiny ubiquitous primitives only
|
||||
- **`tasks/`**: optional cross-context workflow steps
|
||||
|
||||
Legacy folders such as `domain/`, `policies/`, `adapters/`, `registries/`, and `layers/` may still exist during the transition.
|
||||
Treat them as migration residue rather than the target architecture.
|
||||
|
||||
For detailed documentation, see [docs/reference/directory-layout.md](../docs/reference/directory-layout.md).
|
||||
@@ -0,0 +1,16 @@
|
||||
# Platform Adapters
|
||||
|
||||
**Content**: Infrastructure implementations of domain interfaces.
|
||||
|
||||
## Rules
|
||||
1. **Implementation**: Implements the interfaces defined in `src/domain/interfaces/`.
|
||||
2. **Impure**: Contains the actual I/O (SQL, Fetch, File System).
|
||||
3. **Dumb**: Should not contain business rules. Just executes the command.
|
||||
|
||||
## Example
|
||||
|
||||
```typescript
|
||||
export const StripeAdapter = Layer.succeed(PaymentRepo, {
|
||||
charge: (amount) => ...
|
||||
})
|
||||
```
|
||||
@@ -0,0 +1,21 @@
|
||||
# Domain Interfaces
|
||||
|
||||
**Content**: Service Contracts (Ports).
|
||||
|
||||
## Rules
|
||||
1. **Definition**: Define the capability using `Context.Tag`.
|
||||
2. **No Implementation**: Do not include implementation details (SQL, HTTP calls) here.
|
||||
3. **Naming**: Use names describing the *capability*, not the tool (e.g., `PaymentRepo`, not `StripeClient`).
|
||||
|
||||
## Example
|
||||
|
||||
```typescript
|
||||
import { Context, Effect } from "effect"
|
||||
|
||||
export class PaymentRepo extends Context.Tag("PaymentRepo")<
|
||||
PaymentRepo,
|
||||
{
|
||||
readonly charge: (amount: number) => Effect.Effect<void, PaymentError>
|
||||
}
|
||||
>() {}
|
||||
```
|
||||
@@ -0,0 +1,20 @@
|
||||
# Domain Models
|
||||
|
||||
**Content**: Data Schemas (Types) and Pure Logic.
|
||||
|
||||
## Rules
|
||||
1. **Co-location**: Define the Schema and the pure functions that operate on it in the same file.
|
||||
2. **Purity**: Functions here must be 100% pure. No side effects.
|
||||
3. **Scope**: Functions here should primarily operate on the entity defined in the file.
|
||||
|
||||
## Example (`Cart.ts`)
|
||||
|
||||
```typescript
|
||||
import { Schema } from "@effect/schema"
|
||||
|
||||
export const Cart = Schema.Struct({ ... })
|
||||
export type Cart = Schema.Schema.Type<typeof Cart>
|
||||
|
||||
// Pure Logic
|
||||
export const isEmpty = (cart: Cart): boolean => cart.items.length === 0
|
||||
```
|
||||
@@ -0,0 +1,3 @@
|
||||
import { Layer } from "effect";
|
||||
|
||||
export const MainLayer = Layer.empty;
|
||||
@@ -0,0 +1,18 @@
|
||||
# Layers (Dependency Injection)
|
||||
|
||||
**Content**: Static Application Wiring.
|
||||
|
||||
## Usage
|
||||
Construct the final application layers here. This is where you decide:
|
||||
"In Production, use Postgres. In Test, use InMemory."
|
||||
|
||||
## Example
|
||||
|
||||
```typescript
|
||||
// Main.layer.ts
|
||||
export const MainLayer = Layer.mergeAll(
|
||||
PostgresLive,
|
||||
StripeLive,
|
||||
// ...
|
||||
)
|
||||
```
|
||||
@@ -0,0 +1,11 @@
|
||||
# Generic Libraries
|
||||
|
||||
**Content**: Internal tools with NO domain knowledge.
|
||||
|
||||
## Usage
|
||||
Put things here that you could theoretically publish to npm as a standalone package.
|
||||
- Neo4j Client wrappers
|
||||
- Custom Git utilities
|
||||
- Date formatting helpers (generic)
|
||||
|
||||
If it imports anything from `src/domain`, it does NOT belong here.
|
||||
@@ -0,0 +1,17 @@
|
||||
# Policies
|
||||
|
||||
**Content**: Business Rules and Decision Logic.
|
||||
|
||||
## Rules
|
||||
1. **Purity**: Must be pure.
|
||||
2. **Context**: Can accept multiple entities and configuration to make a decision.
|
||||
3. **Output**: Returns a Result or a Decision (Enum/Strategy), not a side effect.
|
||||
|
||||
## Example
|
||||
|
||||
```typescript
|
||||
export type PaymentStrategy = 'RETAIL' | 'WHOLESALE'
|
||||
|
||||
export const determinePaymentStrategy = (amount: number): PaymentStrategy =>
|
||||
amount < 1000 ? 'RETAIL' : 'WHOLESALE'
|
||||
```
|
||||
@@ -0,0 +1,14 @@
|
||||
# Registries
|
||||
|
||||
**Content**: Dynamic Runtime Selection Logic.
|
||||
|
||||
## Usage
|
||||
Use this ONLY when you need to select an implementation at runtime based on data (Strategy Pattern).
|
||||
For static wiring (e.g., "Always use Postgres in Prod"), use `src/layers/`.
|
||||
|
||||
## Example
|
||||
|
||||
```typescript
|
||||
export const getPaymentAdapter = (strategy: 'RETAIL' | 'WHOLESALE') =>
|
||||
strategy === 'RETAIL' ? StripeAdapter : BankAdapter
|
||||
```
|
||||
@@ -0,0 +1,18 @@
|
||||
# Workflows
|
||||
|
||||
**Content**: Orchestration Scripts (Transaction Scripts).
|
||||
|
||||
## Rules
|
||||
1. **Orchestration**: Calls Domain Interfaces, Policies, and other Workflows.
|
||||
2. **Impure**: This is where side effects happen (via the Interfaces).
|
||||
3. **Composition**: Use `Effect.gen` to compose steps linearly.
|
||||
|
||||
## Example
|
||||
|
||||
```typescript
|
||||
export const checkout = (cart: Cart) => Effect.gen(function*(_) {
|
||||
const strategy = Policy.determinePaymentStrategy(cart.total)
|
||||
const paymentSvc = yield* _(PaymentRegistry.get(strategy))
|
||||
yield* _(paymentSvc.charge(cart.total))
|
||||
})
|
||||
```
|
||||
Reference in New Issue
Block a user