Search/Make Changes in a Full-Stack Monorepo Without Breaking Shared Packages

Make Changes in a Full-Stack Monorepo Without Breaking Shared Packages

For AI edits in a monorepo of apps and shared packages. It puts each change in the right module, rebuilds generated bundles, keeps each organization's data apart, and hands over a pull request with test results.

To use this AI rule
## Put Each Change in the Module That Owns It Start by mapping the workspace before editing. Distinguish product applications, reusable UI packages, shared business logic, data schemas and migrations, type packages, configuration presets, documentation, deployment assets, and test harnesses. Put feature-specific behavior in the owning application or feature module. Put reusable domain logic and shared types in packages with explicit consumers. Keep infrastructure and deployment collateral separate from runtime source. Colocate unit tests with the stable logic they exercise, while browser-flow specifications belong in the application’s end-to-end area. Do not duplicate shared logic inside an application merely to avoid changing a package. Follow dependency direction and verify every downstream consumer when a shared package changes. ## Rebuild Precompiled Packages and Bypass Stale Caches Identify packages that are precompiled and copied into an application’s public assets. A running application may import the package’s distribution output rather than its source, so a source edit alone may not be observable. After changing a precompiled package or any dependency that affects its bundle: 1. remove only the package’s known distribution outputs and copied artifacts; 2. bypass the build-system cache for the affected dependency graph; 3. rebuild the package through its official workspace task; 4. refresh or disable the browser cache; 5. restart the development server only if the rebuilt asset is still not loaded. Never hand-edit copied bundles or generated artifacts. Treat cache invalidation as part of the verification procedure, not as evidence that the source change failed. ## Follow the Shared Lint and Type Rules Use the repository’s shared lint, formatting, and compiler presets instead of local overrides. Follow the established indentation, line width, quote, semicolon, and import-group rules. Name components and component folders consistently, use lower camel case for functions and variables, and reserve upper snake case for true constants. Put mocks in the designated mock location so resolution and import ordering remain stable. Prefer inferred types where they remain clear, use shared domain types, and avoid untyped escape hatches. Treat component props as immutable. Keep components focused, effects narrow, hook dependencies correct, and memoization justified by measured need rather than habit. ## Keep Server Logic Separate and Build Cache Keys from One Factory Keep route composition, service logic, and feature modules distinct. Server actions should call services and return one consistent success-or-error envelope. Context providers must fail clearly when used outside their provider and must clean up effects using stable snapshots rather than mutable references. Use request-scoped memoization for duplicate work within one request. Use the approved shared cache abstraction or an explicit distributed cache for expensive cross-request work. Do not introduce an unstable framework cache API when the repository has rejected it. Create every cache key through the canonical key factory. The key must include all dimensions that can change the result so users, tenants, environments, locales, or feature modes cannot share incompatible entries. ## Send Text Through Translations and Keep Time Zones Apart from Locale Route all user-facing text through the translation function and follow the established lowercase dotted key convention. Maintain one source-locale file as the only hand-authored translation source. Never manually edit generated locale files; run the localization generator and key validator after changing source text. Render user-facing dates and times through shared helpers. Take display locale from the application’s language source of truth, never from an implicit browser default. Treat locale and time zone as independent: locale controls formatting, while time zone controls the represented moment. Never infer time zone from locale. Preserve existing stored-value semantics unless the product defines a time-zone source of truth. Keep storage, APIs, exports, integrations, and logs in stable non-localized formats such as an explicit UTC or ISO representation. ## Keep Each Organization's Data Apart and Queries Fast Scope every data operation by the repository’s tenant boundary, such as organization and environment. Apply soft-deletion filters consistently so inactive or deleted records do not reappear through alternate query paths. For counts, use a filtered count query rather than offset-style pagination arguments. Run independent count and data queries concurrently. Prefer cursor pagination for large datasets, and include indexed ownership fields when filtering by time. Review schema and migration changes with every affected query path. Data isolation is a cross-cutting invariant: a missing tenant predicate is not a minor performance issue but a potential data-boundary failure. ## Choose Tests by User Risk, Not Coverage Numbers Optimize for confidence rather than a coverage percentage: - Use browser end-to-end tests for critical user journeys, UI regressions, and component behavior. - Use unit tests for stable pure logic such as validators, transformers, evaluators, calculations, and edge cases. - Use manual staging checks for release readiness, with a bug, backport, and retest loop for critical findings. Keep browser tests focused, well named, and explicit about slow suites. Mock network and storage boundaries through shared helpers. Do not add brittle component snapshots, markup assertions, implementation-detail tests, timing hacks, mega-flows, or low-signal tests created only to raise coverage. Run the standard unit suite before review, coverage when critical flows change, and the directly affected end-to-end suite for journey risk. ## Keep Docs and Component Examples Up to Date Follow the documentation system’s file contract, metadata fields, heading rules, and approved step or callout components. Mark restricted-edition content with the standard notice instead of inventing a new badge or wording. Keep component examples beside the component and import through its public entry point. Organize controls into the repository’s standard groups. Cover the default state, disabled state when supported, icon state when supported, all variants, and meaningful edge cases. Before building or reviewing UI, load the design context for the affected surface. Shared design guidance complements code conventions and remains the source of truth for tokens, components, motion, and visual quality. ## Give CI Workflows Only the Permissions They Need Grant automation tokens only the permissions required by each workflow. Begin hosted Linux jobs with the approved runner-hardening step so network and process behavior are constrained before project code executes. Keep dependency locks authoritative and run workspace commands through the package manager selected by the repository. Avoid one-off install or build commands that bypass the task graph, shared environment, or cache metadata. When changing a workflow, verify event triggers, permissions, secrets exposure, cache keys, artifacts, and failure propagation. A green downstream step must not conceal a failed prerequisite. ## Hand Over a Pull Request with Test Results and Screenshots Before completion, remove dead code and unused imports, run the authoritative lint command, and execute the smallest test set that proves the change plus any directly affected broader flow. Keep commits focused and consistent with the repository’s commit convention. A pull request should state the problem, summarize the solution, link the governing issue or specification, and identify migrations or environment changes. Attach visual evidence for UI work and paste the results of relevant lint, test, build, and migration commands. Reviewers should be able to determine what changed, why it belongs in that module, how generated outputs were refreshed, and which risks were verified without reconstructing the work from the diff alone.