--- name: structure-flow description: Place and organize Ledger Wallet code in the monorepo layers. Use when creating, moving, or reviewing code under apps, features, domain, shared, or support; deciding which layer owns a concern; structuring packages and flow steps; or checking package names, dependency boundaries, platform variants, and legacy imports. --- # Structure And Flow Use the lowest layer that can own the concern without depending on a higher layer. Read [the canonical architecture guide](../../../docs/monorepo-architecture.md) and [the package creation checklist](../../../docs/new-library.md) before creating a package. Upstream source: [Structure & Flow](https://ledgerhq.atlassian.net/wiki/spaces/WXP/pages/6111232117) ## Choose The Owner | Concern | Location | Owns | Does not own | | ---------------------------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------- | | Platform entry point | `apps/` | Screens, global routing, store composition, analytics host wiring, observability, app glue | Reusable feature internals | | User-visible capability | `features/flow/` | Business-aware UI, user journeys, local state, flow routing | App-specific screen composition | | Capability shared across flows | `features/platform/` | Hooks, selectors, NFR rules, React glue, and components shared by several flows or use cases | Single-flow internals and fully generic components | | Business object | `domain/entity/` | Runtime schema, inferred type, defaults, mocks, selectors, slice | Network calls and feature state | | Network/data access | `domain/api/` | API contracts, calls, transformations, RTK Query, thunks | UI and app composition | | Business-agnostic primitive or component | `shared/` | Generic schemas, utilities, Redux primitives, and components without domain or feature knowledge | Domain or app knowledge | | Development-only tooling | `support/` | Shared test, TypeScript, lint, and format configuration | Runtime code | Use these distinctions: - Keep feature-scoped state in its `features/flow` package; do not promote it to an entity. - Keep an element in `features/flow` when it belongs to one flow or use case. - Move a feature-level element to `features/platform` when several flows or use cases need it, especially when it connects them to the domain. - Keep fully generic, business-agnostic elements in `shared` or the existing design-system package. - Keep app screens in each app. Let them compose exported flow entry points. - Keep `.web` and `.native` variants beside each other inside the owning feature. ## Organize The Package Every unit is a private package with `package.json`, `src/`, explicit exports, and no cross-package relative imports. ```text features/flow//src/ ├── components/ # shared by several steps ├── hooks/ ├── router/ # flow-local routing only ├── state/ # feature-scoped state ├── steps// │ ├── components/ # used only by this step │ ├── viewModel.ts # state and orchestration │ ├── view.ts # rendering and callbacks │ ├── view.test.ts │ └── index.ts ├── utils/ └── index.ts # minimal public API domain/entity//src/ ├── schema.ts ├── schema.mock.ts ├── selectors.ts ├── slice.ts └── index.ts domain/api//src/ ├── api.ts └── index.ts ``` Colocate tests with the files they cover. Add folders only when they group files that change together. Every `index.ts` above is a **barrel**: only `export * from "./x"` lines, with private code kept in an `internals` location. See [package-public-api](../package-public-api/SKILL.md) for the rules and the `lint:structure` check that enforces them. ## Respect Boundaries Dependencies flow downward: ```text apps → features/flow → features/platform → domain → shared ``` More precisely: | Source | May depend on | | ------------------- | -------------------------------------------------------------- | | `shared` | `shared` | | `domain/entity` | `domain/entity`, `shared` | | `domain/api` | `domain/api`, `domain/entity`, `shared` | | `features/platform` | `features/platform`, `domain`, `shared` | | `features/flow` | `features/flow`, `features/platform`, `domain`, `shared` | | `apps` | Any new-architecture layer | | `support` | Development tooling only; consume it through `devDependencies` | - Never import internal legacy `libs/*` packages from `shared`, `domain`, or `features`. - Let legacy code consume new architecture only as migration glue. - Inject private new-architecture packages into published legacy packages at the app composition root. - Import another package through its npm name, never through a relative path. - Let Nx infer tags from paths; do not add manual tags unless local tooling requires them. ## Name Packages | Location | Package name | | -------------------------- | --------------------------- | | `shared/` | `@shared/` | | `domain/entity/` | `@domain/entity-` | | `domain/api/` | `@domain/api-` | | `features/platform/` | `@features/platform-` | | `features/flow/` | `@features/flow-` | | `support/` | `@support/` | ## Review - Confirm the concern sits in the lowest valid layer. - Confirm folders express ownership and colocation, not arbitrary categories. - Confirm apps only compose reusable flows and platform concerns. - Confirm feature, entity, API, and development-only state have distinct owners. - Confirm imports follow the dependency table and package public APIs. - Confirm every `index.*` is a pure barrel and no package re-exports another — see [package-public-api](../package-public-api/SKILL.md).