Skip to content

refactor: vertical-slice feature folders (Notifications pilot)#200

Open
antosubash wants to merge 13 commits into
mainfrom
worktree-explore-feature-folders
Open

refactor: vertical-slice feature folders (Notifications pilot)#200
antosubash wants to merge 13 commits into
mainfrom
worktree-explore-feature-folders

Conversation

@antosubash
Copy link
Copy Markdown
Owner

Summary

  • Migrate the Notifications module to a vertical-slice layout: Features/<Op>/ co-locates each API endpoint with its partial-class fragment of NotificationService; cross-cutting Channels/, Jobs/, EntityConfigurations/, and Services/ consolidate under Infrastructure/; Pages/ (IViewEndpoint + React) intentionally untouched.
  • Add reusable migration tooling: scripts/feature-folder-migrate.mjs consumes a per-module TSV manifest and performs git mv + namespace rewrite. 11 unit tests cover deriveNamespace, rewriteNamespace, and parseManifest. Smoke-tested end to end.
  • Slice the feature-scoped QueryNotificationsRequest into Contracts/Features/Notifications/List/. Entity types and cross-feature DTOs stay at Contracts root to avoid EF migration-snapshot churn (documented as a follow-up decision in the spec).
  • Amend the design spec (C1 partial-class namespace exception, C5 shared-fixture placement) and capture pilot findings in tasks/lessons.md — including the migration script's limitation on pre-existing partial-class fragments.

See docs/superpowers/specs/2026-05-14-vertical-slice-feature-folders-design.md for the design and docs/superpowers/plans/2026-05-14-vertical-slice-notifications-pilot.md for the executed plan.

Test Plan

  • `dotnet build` — 0 errors (full solution)
  • `dotnet test` — 995 pass, 0 fail
  • `npm run validate-pages` — clean
  • `npm run build:dev` — all workspaces build, including `@simplemodule/notifications`
  • `npm run check` — no new issues outside generated `routes.ts`
  • Inspect generator output: confirm endpoints emit `SimpleModule.Notifications.Features.Notifications.` namespaces (not stale `Endpoints.*`)
  • Manual smoke: load `/notifications` as an authenticated user; verify inbox renders and the four API endpoints (`GET /api/notifications/`, `GET /api/notifications/unread-count`, `POST /api/notifications/{id}/read`, `POST /api/notifications/read-all`) work

antosubash added 13 commits May 14, 2026 20:42
Captures the target module layout (Features/<Agg>/<Op>/), the
partial-class split that preserves SM0025/SM0026, the rule for
Contracts/Shared vs feature-scoped DTOs, and the pilot-first
migration plan starting with the Notifications module.
Phase 0 (migration script + tests) and Phase 1 (Notifications module
conversion to Features/Infrastructure/ layout with partial-class
NotificationService split). Covers the spec exception for partial-class
namespaces that emerged during plan review.
…e/ subfolder

Move NotificationsDbContext, NotificationService, Notifier, NotificationsLog,
Channels/*, EntityConfigurations/*, and Jobs/* into Infrastructure/ to start
the feature-folder migration. Update internal using statements; no public
contract changes. See spec: docs/superpowers/specs/2026-05-14-vertical-slice-feature-folders-design.md
Endpoints/Notifications/* moved to Features/Notifications/<Op>/. The feature-
scoped QueryNotificationsRequest moved to Contracts/Features/Notifications/List/.
Entity, value-object, and channel-payload contracts remain at Contracts root
to avoid migration-snapshot churn (revisit in a follow-up phase).
…artials

NotificationService becomes a sealed partial class. Each cross-module contract
method (ListAsync, GetUnreadCountAsync, GetByIdAsync, MarkReadAsync,
MarkAllReadAsync) moves to a fragment file co-located with its feature folder.
The root partial in Infrastructure/ retains the constructor and implements
clause. Partial fragments deliberately keep the owning class's namespace
(Infrastructure) rather than matching folder; their *folder* identifies
the slice.
Replace Unit/NotificationServiceTests.cs with per-feature files under
Features/Notifications/<Op>/, sharing a NotificationServiceTestFixture base.
Cross-cutting tests (NotifierTests, TestBackgroundJobs) remain in Unit/.
Add lesson: migration script must not be used on pre-existing partial-class
fragment files (would silently break partial-class semantics by rewriting
the fragment's namespace to match folder).

Amend spec C5: shared test fixtures live at the aggregate folder level,
not inside any single operation folder.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant