# Feature Architecture Standard **Status**: team standard **Reference implementation**: `src/features/recent-projects` This document defines the default architecture for medium and large features in this repository. ## Goals - keep business rules isolated from Electron-specific runtime details - make features easier to scale, test, and review - keep renderer code closer to browser and Tauri portability - enforce architecture with tooling, not only with code review comments ## Canonical Template ```text src/features// index.ts contracts/ index.ts core/ domain/ application/ main/ index.ts composition/ application/ adapters/ input/ output/ infrastructure/ preload/ index.ts renderer/ index.ts ``` Use this template by default when a feature: - spans more than one process boundary - introduces its own use case or business policy - needs its own transport bridge or integration surface - is expected to grow with new providers, sources, or presentation flows `index.ts` and `main/application/` are optional. Add them only when they have a clear public or runtime-orchestration role. ## Layer Responsibilities ### `index.ts` Optional root public barrel for the feature. Use it for: - stable type re-exports from `contracts/` - small pure facades that are intentionally shared across layers - feature factories when the root barrel is intentionally main-owned and imported only from main-process code Not allowed: - accidental wildcard exports from implementation folders - mixing browser-safe exports with main-only exports without making process ownership obvious - replacing the layer entrypoints when callers need a process-specific surface ### `contracts/` Cross-process public API for the feature. Allowed content: - DTOs - API fragment types - IPC or route constants Not allowed: - store access - Electron APIs - business orchestration ### `core/domain/` Pure business rules and invariants. Examples: - merge policies - provider-agnostic models - selection rules - dedupe logic Not allowed: - infrastructure access - framework access - side effects ### `core/application/` Use cases and ports. Examples: - orchestration flow - output ports - cache ports - source ports - response models Not allowed: - Electron, Fastify, React, Zustand, child processes ### `main/composition/` Feature composition root in the main process. Responsibilities: - instantiate infrastructure - wire adapters - wire use cases - expose a small facade to app shell entrypoints ### `main/adapters/input/` Driving adapters for the main process. Examples: - IPC handlers - HTTP route registration Responsibilities: - translate transport input into use case calls - keep transport concerns out of use cases ### `main/application/` Optional main-process application services. Use this only when code is too runtime-aware for `core/application`, but is not a transport adapter or low-level infrastructure helper. Examples: - main-only readers that orchestrate runtime services - process-aware tracking or coordination helpers Not allowed: - IPC or HTTP handler registration - renderer or preload dependencies - pure domain policy that belongs in `core/domain` ### `main/adapters/output/` Driven adapters that implement application ports. Examples: - presenters - source adapters Responsibilities: - translate between external data and core models - stay thin around infrastructure helpers ### `main/infrastructure/` Concrete technical implementation details. Examples: - file system adapters - JSON-RPC transport clients - binary discovery - cache implementation - git identity helpers Responsibilities: - know about runtime, process, OS, or protocol details ### `preload/` Thin transport bridge between renderer and main. Responsibilities: - expose a feature API fragment - depend on `contracts/` Not allowed: - main composition code - renderer logic ### `renderer/` Feature presentation and interaction. Recommended structure: ```text renderer/ index.ts adapters/ hooks/ ui/ utils/ ``` Responsibilities: - `ui/` renders - `hooks/` orchestrate interaction and transport usage - `adapters/` transform DTOs into view models - `utils/` contain small pure renderer helpers ## Import Rules ### Public entrypoints only Outside the feature, import only: - `@features/` when the feature owns a deliberate root public barrel - `@features//contracts` - `@features//main` - `@features//preload` - `@features//renderer` Do not deep-import feature internals from app shell or from other features. Layer entrypoints should be explicit `index.ts` files that export only supported surface area. Focused tests may import internals when they are testing that unit directly, but production integration code should not. ### Core isolation `core/domain` must not import: - `@main/*` - `@renderer/*` - `@preload/*` - adapters - infrastructure - Electron APIs - Fastify - child process modules `core/application` must not import: - `@features//main/**` - `@features//renderer/**` - `@main/*` - `@renderer/*` - `@preload/*` - Electron APIs - Fastify - child process modules ### UI isolation `renderer/ui` must not import: - `@renderer/api` - `@renderer/store` - `@main/*` - Electron APIs Push transport and store access into feature hooks or adapters. ## Browser and Tauri Friendly Guidance The default transport direction should be: `renderer -> feature contracts -> app api abstraction -> preload/http adapter` This keeps renderer code closer to: - browser mode through HTTP adapters - a future Tauri bridge - alternative shells with minimal feature rewrites To keep that path clean: - never call `window.electronAPI` directly inside feature UI or hooks - go through shared renderer API adapters - keep Electron-specific concerns in `main/` and `preload/` - keep business rules in `core/` ## When To Use The Full Slice Use the full template when a feature has: - its own business rules - its own merge or filtering policy - transport wiring - more than one adapter - a roadmap beyond a one-off screen tweak ## When A Thin Slice Is Enough A smaller feature may skip `core/` and `preload/` when it is: - purely presentational - only reshaping already-owned data - not adding a new use case - not adding a new transport boundary If the feature still owns meaningful pure semantics or projection rules, keep `core/` and skip only the process layers you do not need. Example: - `src/features/agent-graph` keeps `core/domain` and `renderer`, but does not add fake `main/` or `preload/` folders because the transport boundary lives elsewhere. ## Current Feature Shape Examples Use these local examples before inventing a new variant: - `src/features/recent-projects` - full cross-process reference with `contracts`, `core`, `main`, `preload`, and `renderer`. - `src/features/member-work-sync` - full cross-process feature with a root public barrel and broader main-process infrastructure. - `src/features/member-log-stream` - full cross-process feature that uses `main/application/` for main-only runtime orchestration. - `src/features/agent-graph` - thin renderer integration with `core/domain` and `renderer`, no fake process layers. - `src/features/codex-model-catalog` and `src/features/team-runtime-lanes` - process-limited features that omit renderer or preload layers when they do not own that boundary. ## Definition Of Done For A Reference Feature A feature is reference-quality when: - structure matches the full or thin template chosen for the feature - core is side-effect free - app shell imports only public entrypoints - renderer UI is dumb and presentational - at least the main domain and application rules are tested when those layers exist - architecture is enforced by lint rules - feature has a concise standard or plan doc if it introduces a new pattern ## Recommended Test Coverage For medium and large features, cover at least: - domain policy tests - application use case tests - critical renderer interaction utilities - one adapter-level mapping test ## Recent Projects As The Reference `src/features/recent-projects` is the first slice that follows this standard end-to-end. Use it as the example for: - contracts ownership - core/application separation - composition-root wiring - renderer dumb UI + hook orchestration - browser-friendly transport direction - feature-level lint guard rails ## Agent Graph As The Thin-Slice Reference `src/features/agent-graph` is the thin-slice example for a renderer integration feature built on top of a reusable package. Use it as the example for: - keeping pure graph semantics in `core/domain` - exposing a renderer-only public entrypoint - integrating `packages/agent-graph` without inventing fake process layers - migrating legacy `src/renderer/features/*` code into the canonical feature root