AI agent skill · by @LedgerHQ
Structure Flow
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.
Archived 2026-10-23 · Source updated 2026-10-12 · License: MIT. Check the original repository for the latest version.
SKILL.md instructions
# 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/<app>` | Screens, global routing, store composition, analytics host wiring, observability, app glue | Reusable feature internals | | User-visible capability | `features/flow/<feature>` | Business-aware UI, user journeys, local state, flow routing | App-specific screen composition | | Capability shared across flows | `features/platform/<feature>` | 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/<entity>` | Runtime schema, inferred type, defaults, mocks, selectors, slice | Network calls and feature state | | Network/data access | `domain/api/<name>` | API contracts, calls, transformations, RTK Query, thunks | UI and app composition | | Business-agnostic primitive or component | `shared/<name>` | Generic schemas, utilities, Redux primitives, and components without domain or feature knowledge | Domain or app knowledge | | Development-only tooling | `support/<name>` | 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/<feature>/src/ ├── components/ # shared by several steps ├── hooks/ ├── router/ # flow-local routing only ├── state/ # feature-scoped state ├── steps/<StepName>/ │ ├── 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/<entity>/src/ ├── schema.ts ├── schema.mock.ts ├── selectors.ts ├── slice.ts └── index.ts domain/api/<name>/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/<name>` | `@shared/<name>` | | `domain/entity/<name>` | `@domain/entity-<name>` | | `domain/api/<name>` | `@domain/api-<name>` | | `features/platform/<name>` | `@features/platform-<name>` | | `features/flow/<name>` | `@features/flow-<name>` | | `support/<name>` | `@support/<name>` | ## 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).