Files
3a36fe8eaa feat(web): implement feature architecture standard with walletconnect migration (#6936)
* chore: setup spec-kit

* chore: add feature-architecture specs

* feat(web): implement feature architecture standard with walletconnect migration

- Add ESLint no-restricted-imports rule to enforce feature boundaries
- Create feature architecture documentation at apps/web/docs/feature-architecture.md
- Migrate walletconnect feature as reference implementation:
  - Add public API barrel file (index.ts) with lazy-loaded default export
  - Extract types to types.ts
  - Create feature flag hook (useIsWalletConnectEnabled)
  - Reorganize store into store/ directory
  - Move WalletConnectContext to components/WalletConnectContext/
  - Update all internal imports to relative paths
  - Update all external imports to use public API
- Fix affected test files (Header, useSafeWalletProvider)
- Update AGENTS.md with feature architecture reference

* fix prettier

---------

Co-authored-by: katspaugh <[email protected]>

Co-authored-by: Hanzo Dev <[email protected]>
2026-01-13 17:10:26 +01:00

13 KiB

Feature Specification: Feature Architecture Standard

Feature Branch: 001-feature-architecture Created: 2026-01-08 Status: Draft Input: User description: "Help me plan a big refactoring of the web app. I want features/domains clearly separated and well defined through a standard folder/file structure, typed interfaces, how it's included in other parts of the app -- each feature should be behind a feature flag (useHasFeature) and lazy-loaded so as to not blow up and not to have side effects on other parts of the app if the feature is disabled. This needs to be documented for humans and AI agents, a pattern established. Use one of the existing src/features as an example/test bed. Plan a refactoring for the rest."

User Scenarios & Testing (mandatory)

User Story 1 - Establish Standard Feature Pattern (Priority: P1)

A developer (human or AI agent) needs to create a new feature in the Safe{Wallet} web application. They consult the documentation to understand the standard folder structure, required files, and patterns. Following the template, they create a feature that is properly isolated, feature-flagged, lazy-loaded, and has no side effects when disabled.

Why this priority: This is the foundational pattern that all other work depends on. Without a documented standard, features will continue to be inconsistent.

Independent Test: Can be fully tested by creating a new test feature following only the documentation, verifying it compiles, lazy-loads correctly, and renders nothing when the feature flag is disabled.

Acceptance Scenarios:

  1. Given a developer reads the feature architecture documentation, When they create a new feature following the template, Then the feature folder structure matches the standard pattern exactly
  2. Given a new feature exists with the standard structure, When the feature flag is disabled, Then no code from that feature is loaded or executed
  3. Given a feature is lazy-loaded, When the user navigates to that feature, Then the feature bundle is loaded on-demand (not in initial bundle)
  4. Given AI agents reference the documentation, When they generate feature code, Then the generated code follows all standard patterns without manual correction

User Story 2 - Migrate Existing Feature as Reference Implementation (Priority: P2)

The team selects one existing feature (walletconnect) to serve as the reference implementation. This feature is refactored to perfectly match the new standard, serving as a living example for all future features.

Why this priority: A real, working example is more valuable than documentation alone. Developers learn by studying existing code.

Independent Test: Can be fully tested by comparing the refactored feature against the documented standard, verifying 100% compliance, and confirming all existing functionality still works.

Acceptance Scenarios:

  1. Given the walletconnect feature exists with its current structure, When refactored to the new standard, Then all existing tests continue to pass
  2. Given the refactored feature, When the feature flag is disabled, Then no walletconnect code is executed or loaded
  3. Given the refactored feature, When examined by a developer, Then every folder, file, and export matches the documented standard

User Story 3 - Create Migration Assessment for All Features (Priority: P3)

The team produces an assessment of all 21 existing features in src/features/, categorizing each by complexity, current compliance level, and migration priority. This enables systematic, prioritized migration of the codebase.

Why this priority: Understanding the scope of work enables realistic planning and prevents surprises during migration.

Independent Test: Can be fully tested by verifying the assessment document exists, lists all 21 features, and provides actionable migration guidance for each.

Acceptance Scenarios:

  1. Given all 21 features in src/features/, When assessed against the new standard, Then each feature has a documented compliance score
  2. Given the assessment, When reviewed by the team, Then features are prioritized into migration batches (high/medium/low effort)
  3. Given the assessment, When used for planning, Then estimated effort per feature is provided to enable sprint planning

User Story 4 - Document Migration Learnings (Priority: P4)

After migrating the walletconnect reference implementation, the team documents all learnings, challenges encountered, and refinements to the standard pattern. This creates a migration playbook for subsequent features.

Why this priority: Real-world migration reveals edge cases and practical challenges that documentation alone cannot anticipate. Capturing these learnings improves the quality of subsequent migrations.

Independent Test: Can be fully tested by verifying the learnings document exists and addresses common migration challenges discovered during walletconnect refactoring.

Acceptance Scenarios:

  1. Given the walletconnect migration is complete, When learnings are documented, Then the document includes challenges faced and solutions applied
  2. Given the learnings document, When reviewed by a developer, Then they can anticipate and avoid common migration pitfalls
  3. Given the learnings document, When used alongside the standard, Then migration time per feature is reduced

User Story 5 - Migrate All Remaining Features (Priority: P5)

Using the established pattern, learnings document, and migration assessment, all remaining 20 features are systematically migrated to the new standard. Each migration preserves existing functionality while bringing the feature into full compliance.

Why this priority: Full codebase consistency is the end goal. With proven patterns and documented learnings, systematic migration can proceed efficiently.

Independent Test: Can be fully tested by running all existing tests for each migrated feature, verifying feature flag isolation, and confirming lazy-loading behavior.

Acceptance Scenarios:

  1. Given a feature selected for migration, When refactored to the new standard, Then all existing functionality is preserved
  2. Given a migrated feature, When the feature flag is disabled, Then no code from that feature affects the application
  3. Given all 21 features migrated, When the application builds, Then each feature's code is in its own chunk (code splitting verified)

Edge Cases

  • What happens when a feature has circular dependencies with src/components/ or src/hooks/? The standard defines clear import boundaries; circular dependencies must be resolved by extracting shared code to appropriate shared locations.
  • How does the system handle features that need to interact with each other (e.g., swap calling bridge)? Cross-feature communication patterns through Redux store or defined service interfaces are documented.
  • What happens when a feature flag check fails or returns undefined (loading state)? Features render nothing during loading state, preventing flash of unsupported content.
  • How are feature-specific Redux slices handled when the feature is disabled? Slices exist in store but reducers handle disabled state gracefully; no actions are dispatched.
  • What happens to analytics events when a feature is disabled? No analytics events fire for disabled features; tracking code is guarded by feature flag checks.

Requirements (mandatory)

Functional Requirements

Feature Structure

  • FR-001: Every feature MUST reside in its own directory under apps/web/src/features/{feature-name}/
  • FR-002: Every feature MUST have a standard folder structure with components/, hooks/, services/, store/, types/, and constants.ts
  • FR-003: Every feature MUST have an index.ts barrel file that exports only the public API
  • FR-004: Every feature MUST have an internal types.ts file defining all TypeScript interfaces for that feature
  • FR-005: Feature-internal components, hooks, and services MUST NOT be imported directly from other parts of the codebase

Feature Isolation

  • FR-006: Every feature MUST be associated with a feature flag from the FEATURES enum in @safe-global/utils/utils/chains
  • FR-007: Every feature MUST have a useIs{FeatureName}Enabled hook that checks the feature flag
  • FR-008: Every feature's main entry point MUST check its feature flag and render nothing when disabled
  • FR-009: Features MUST NOT execute any code (API calls, analytics, side effects) when their flag is disabled
  • FR-010: Feature Redux slices MUST exist in the store but MUST handle disabled state gracefully

Lazy Loading

  • FR-011: Every feature MUST be lazy-loaded using Next.js dynamic() imports
  • FR-012: Feature lazy loading MUST specify { ssr: false } when the feature uses browser-only APIs
  • FR-013: Features MUST NOT be imported statically from pages or components outside the feature
  • FR-014: Each feature's code MUST be bundled into a separate chunk (verified via bundle analysis)

Documentation

  • FR-015: The feature architecture MUST be documented in apps/web/docs/feature-architecture.md
  • FR-016: The documentation MUST include a template folder structure with explanations
  • FR-017: The documentation MUST include code examples for each required pattern
  • FR-018: The documentation MUST be referenced from AGENTS.md for AI contributor guidance

Cross-Feature Communication

  • FR-019: Features MUST communicate through Redux store or defined service interfaces, never direct imports
  • FR-020: Shared utilities used by multiple features MUST be extracted to src/utils/ or src/hooks/
  • FR-021: Shared components used by multiple features MUST be extracted to src/components/

Compliance Enforcement

  • FR-022: ESLint rules MUST enforce that only feature index files can be imported from outside the feature (no internal imports)
  • FR-023: ESLint violations MUST be configured as warnings during the migration phase
  • FR-024: ESLint violations MUST be promoted to errors after all 21 features are migrated to the new standard

Key Entities

  • Feature: A self-contained domain module with components, hooks, services, and types. Has a unique identifier matching its directory name and FEATURES enum value.
  • Feature Flag: A boolean configuration from the CGW API chains config that enables/disables a feature per chain.
  • Feature Public API: The exported interfaces and components from a feature's index.ts that other parts of the app may use.
  • Feature Internal API: Components, hooks, and utilities that are only used within the feature and not exported.

Success Criteria (mandatory)

Measurable Outcomes

  • SC-001: 100% of new features created after this standard follow the documented pattern without deviation
  • SC-002: The reference implementation feature (walletconnect) passes all compliance checks against the documented standard
  • SC-003: Documentation enables a developer unfamiliar with the codebase to create a compliant feature in under 30 minutes
  • SC-004: AI agents following the documentation produce code that requires zero corrections for structural compliance
  • SC-005: When a feature flag is disabled, zero bytes from that feature's code are loaded in the browser
  • SC-006: All 21 existing features have a documented compliance assessment within the migration planning phase
  • SC-007: Initial bundle size does not increase when new features are added (features are code-split)
  • SC-008: Feature migrations preserve 100% of existing test coverage with no new test failures
  • SC-009: A migration learnings document exists after walletconnect migration capturing challenges and solutions
  • SC-010: All 21 features are migrated to the new standard (full codebase consistency)

Clarifications

Session 2026-01-08

  • Q: What is the migration scope strategy? → A: Phased approach - migrate walletconnect first, document learnings, then migrate all 21 features
  • Q: How is feature architecture compliance enforced? → A: ESLint rules that only allow importing from feature index files (not internals); warnings during migration, errors after full migration

Assumptions

  • The existing FEATURES enum and useHasFeature hook are sufficient for feature flag management
  • Next.js dynamic() imports provide adequate code splitting for lazy loading
  • The walletconnect feature is a good candidate for reference implementation (well-structured, moderate complexity)
  • Feature flags are managed through CGW API chain configs and new flags can be added as needed
  • Redux store structure can accommodate feature-specific slices without major refactoring