Repository navigation
Add Module Constitution and trim CLAUDE.md - #15
Merged
Merged
Conversation
antosubash
force-pushed
the
claude/serene-wilson
branch
2 times, most recently
from
March 27, 2026 21:19
d5894c8 to
ef9b44f
Compare
Key findings: 3 modules violate contracts pattern by referencing Users implementation directly, unified HostDbContext creates tight database coupling, event bus lacks background dispatch, and Admin module has mixed responsibilities.
1. Extract ApplicationUser/ApplicationRole to Users.Contracts
- Moved Identity entities from SimpleModule.Users.Entities to
SimpleModule.Users.Contracts namespace
- Admin, OpenIddict, Permissions now reference Users.Contracts
instead of Users implementation (fixes SM0011 violations)
- Added GetRoleIdsByNamesAsync to IUserContracts to eliminate
OpenIddict's direct UsersDbContext dependency
- Updated all migration snapshots for new entity namespace
2. Add duplicate view page name detection (SM0015)
- Source generator now detects when two IViewEndpoint classes
produce the same page name, preventing silent client-side 404s
3. Add background event dispatch to IEventBus
- New PublishInBackground<T> method for fire-and-forget events
- BackgroundEventChannel + BackgroundEventDispatcher hosted service
- Eliminates need for modules to reinvent the pattern (as AuditLogs did)
- AuditingEventBus updated to forward background dispatch
The TypeScript page registry validation cannot be done at compile time by the Roslyn generator (it has no access to .ts files). This check is already handled by `npm run validate-pages`.
- Remove dead null check in EventBus.PublishInBackground (BackgroundEventChannel is now required) - Make BackgroundEventDispatcher dispatch events concurrently to avoid head-of-line blocking - Cache GetUserIdAsync result in AuthorizationEndpoint to avoid duplicate async call - Use ICollection pattern check in UserService.GetRoleIdsByNamesAsync to avoid unnecessary ToList - Remove unnecessary comments from BackgroundEventChannel
Aligns with the convention established by AuditWriterService. IServiceScopeFactory is the recommended injection point for BackgroundService scope creation.
New compile-time diagnostics: - SM0040 (Error): Duplicate module name — prevents route prefix conflicts, database schema collisions, and ambiguous TypeScript module grouping - SM0041 (Warning): View page prefix mismatch — catches pages whose name doesn't start with the owning module's name (e.g. "Orders/Browse" in the Products module), which breaks React page resolution - SM0042 (Error): Module with IViewEndpoint but no ViewPrefix — view endpoints without a ViewPrefix won't be routed correctly Also adds tests for: - SM0015 (duplicate view page name) — positive and negative cases - SM0040 — two and three duplicate modules, plus valid unique names - SM0041 — matching prefix passes, mismatch warns - SM0042 — missing ViewPrefix errors, present ViewPrefix passes, API-only module without ViewPrefix passes
Admin, OpenIddict, and Permissions modules were migrated to reference SimpleModule.Users.Contracts instead of SimpleModule.Users, so the SM0011 (illegal implementation reference) suppression is no longer needed.
All constant classes in Contracts assemblies are `static class` (excluded from DTO discovery). Permission classes are excluded via IModulePermissions check. Vogen value objects are excluded via IsVogenValueObject check. No DbContext types exist in any Contracts assembly. The suppression was preemptive and never needed.
Framework core: - Add Result<T> type, ModuleHealthStatus enum, and module lifecycle hooks (OnStartAsync/OnStopAsync/CheckHealthAsync on IModule) - Add ModuleLifecycleHostedService to invoke lifecycle hooks at startup/shutdown - Add IModuleDbContext marker interface for future per-module DB isolation - Add PermissionMatcher with wildcard support and use in authorization handler - Add [ViewPage] attribute for compile-time page name validation Source generator: - Add SM0040-SM0042 diagnostics (empty modules, missing contracts, missing ViewPrefix) - Fix SM0043 to not flag modules with DbContexts as empty - Fix endpoint-to-module matching to use namespace-based discovery - Scan contracts assemblies for permission classes (fixes SM0035 false positives) - Register IModule singletons and lifecycle service in generated AddModules() Module decoupling: - Decouple Orders.Contracts from Vogen types (UserId→string, ProductId→int) - Extract IUserAdminContracts/IRoleAdminContracts from Users module - Refactor Admin module to use contracts instead of direct UserManager/RoleManager - Add Dashboard.Contracts project with IDashboardContracts placeholder Route fixes: - Add ViewPrefix to Admin, Dashboard, OpenIddict, PageBuilder, Users modules - Fix route doubling by making all view endpoint routes relative to ViewPrefix - Fix SM0015 duplicate page name (PageBuilder/ViewerDraft) Tests updated across all affected modules and framework.
…and framework contribution
- Differentiate SM0031 vs SM0034 diagnostic descriptions - Add PublishInBackground shutdown/cancellation behavior note - Expand Settings Types to a proper table with descriptions - Clarify permission constants assembly placement - Improve SM0043 description accuracy
The extract-ts-types.mjs script was writing types.ts to the old module paths (e.g., modules/Admin/src/Admin/) instead of the renamed paths (modules/Admin/src/SimpleModule.Admin/). Updated the script to prefix "SimpleModule." to the module directory name and removed the 9 stale type files in the old locations. Also fixed a Biome formatting issue in PageBuilder Manage.tsx.
antosubash
force-pushed
the
claude/serene-wilson
branch
from
March 27, 2026 21:20
ef9b44f to
f078c5f
Compare
2 of 5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
docs/CONSTITUTION.md— the authoritative rules document for module development and framework contribution, covering 12 sections: founding principles, module boundaries, dependencies, data ownership, communication, endpoints, frontend, permissions, settings, testing, compiler-enforced rules (28 SM diagnostics), and framework contributor guidelinesCLAUDE.md— removed ~200 lines of architectural rules now covered by the Constitution, added a reference link, fixed incorrect "Inline dynamic imports" claim in Key ConstraintsTest plan
docs/CONSTITUTION.mdrenders correctly on GitHubdocs/CONSTITUTION.mdlink in CLAUDE.md resolves correctly🤖 Generated with Claude Code