ABOUTME: Contribution workflow covering prerequisites, validation, code standards, and PR process. ABOUTME: Includes architecture test requirements, CSS rules, DTO sync flow, and release checklist.
Audience: Contributors | AI agents Status: Implemented Owner: Contributor Experience Last Verified: 2026-07-03 Source Anchors:
docs/FIRST_CONTRIBUTION.md,docs/TESTING.md,.github/PULL_REQUEST_TEMPLATE.md,.github/ISSUE_TEMPLATE/,.agents/CONTEXT_ENGINEERING.md
| Tool | Version | Purpose |
|---|---|---|
| .NET SDK | 10.0+ (pinned by global.json) |
Build and test |
| Docker Desktop | Latest | Infrastructure services |
| .NET Aspire CLI/workload | Latest | Service orchestration |
See GETTING_STARTED.md for complete setup instructions.
Install Aspire CLI before using aspire run:
curl -sSL https://aspire.dev/install.sh | bashFor high-level expectations, project scope, discussion requirements, and the AI contribution policy, see the repository root CONTRIBUTING.md.
If this is your first contribution, start with FIRST_CONTRIBUTION.md. It gives the shortest safe path for docs-only and small-bug PRs without duplicating this full workflow.
For code changes, first prove the local stack can start from a clean checkout:
cp .env.example .env
aspire run --apphost src/Explore.AppHost/Explore.AppHost.csprojThis starts the full local Aspire topology by default. Contributors should use this path unless they intentionally need the Docker-only stack or a maintainer-specific external-infrastructure profile.
Use the GitHub templates to keep requests and reviews actionable:
| Template | Use For |
|---|---|
| Bug report | Reproducible defects, validation gaps, and regressions. |
| Feature request | New behavior with explicit problem, proposal, and non-goals (via GitHub Discussions). |
| Documentation issue | Stale, missing, confusing, or incorrect docs with source anchors. |
| AI agent contract | Work packages that need context, scoped files, validation, and handoff expectations. |
| Pull request template | PR summary, changes, AI disclosure, validation evidence, release notes, and contributor agreement. |
- Fork the repository
- Create your feature branch (
git checkout -b feature/foobar) - Commit your changes (
git commit -m "Add feature") - Push to the branch (
git push origin feature/foobar) - Create a new Pull Request
Before opening a PR:
- build the solution in Release mode
- run the affected test projects individually
- update docs when behavior, configuration, or operations change
Every non-bot contributor must sign the ISLAMU Event Contributor License Agreement by posting the exact CLA signature comment on the pull request. The CLA gives the ISLAMU project steward broad inbound rights to maintain, provide, and relicense ISLAMU Event under alternative terms when sustainability, enterprise internal-use on-premises compliance, nonprofit, humanitarian, public-sector, or procurement-restricted needs require it.
Anti-SaaS Governance Invariant: The Project Steward is bound never to license ISLAMU Event under terms that allow a third-party closed-source SaaS. Any entity operating a public SaaS must do so under AGPL-3.0-or-later, preserving universal community parity. See I-VSD Strategy Review.
The Contributor License Agreement workflow records v1.0 signatures in signatures/v1.0/cla.json on the dedicated cla-signatures branch. A pre-flight script short-circuits the full action when all commit authors are already signed or allowlisted. It uses pull_request_target and issue_comment metadata only; it must not checkout, build, test, cache, restore packages, or execute pull-request head code.
| Prefix | Usage |
|---|---|
feat/ |
New features |
fix/ |
Bug fixes |
refactor/ |
Code restructuring without behavior change |
docs/ |
Documentation only |
test/ |
Test additions or fixes |
chore/ |
Build, CI, dependency updates |
Use conventional commit format. The release engine treats commit text as
untrusted input and validates it against eng/release/policy/release-policy.yaml
and eng/release/policy/scope-registry.yaml:
type(scope): description
feat(registration): let attendees correct registration details
fix(events): keep draft events private until organizers publish them
ci(release): verify promoted release tooling
docs(documentation): clarify operator release checks
Use public product scopes such as events, registration, ticketing,
discovery, notifications, privacy, access, storage, onboarding,
federation, webhooks, localization, accessibility, and self-hosting
for release-visible outcomes. Use engineering scopes such as ci,
dependencies, architecture, database, observability, documentation,
release, testing, and build for valid internal commits that are omitted
from public notes by default.
Breaking commits must include both the ! marker and a non-empty
BREAKING CHANGE: footer. Nonbreaking commits may be omitted explicitly only
with both Changelog: skip and a non-empty Changelog-Reason:; breaking
changes cannot be skipped.
High-impact, breaking, migration, security, and deterministically grouped work also
needs a governed change fragment under docs/internal/releases/changes/<change-id>.yaml and a
matching Change-Id: footer. A backport records the original commit in that fragment's
Backport-Of field as a full object ID.
Governed release notes deliberately carry no author or committer identity, email, raw commit body, or provider handle. Release artifacts are signed, mirrored, and permanent, so contributor recognition is kept out of them on purpose; see i-vsd-release-governance.md for why that trade was made.
The release preparation commit is:
chore(release): prepare v1.1.0
Changelog: skip
Changelog-Reason: release metadata commit
Every PR must pass this checklist. Run from solution root:
dotnet build --configuration Release --verbosity quietRun each standard project individually — never use solution-level dotnet test:
dotnet test --project tests/Event.Domain.UnitTests/Event.Domain.UnitTests.csproj --configuration Release --verbosity quiet
dotnet test --project tests/Event.Application.UnitTests/Event.Application.UnitTests.csproj --configuration Release --verbosity quiet
dotnet test --project tests/Event.Architecture.Tests/Event.Architecture.Tests.csproj --configuration Release --verbosity quiet
dotnet test --project tests/Explore.Secrets.UnitTests/Explore.Secrets.UnitTests.csproj --configuration Release --verbosity quiet
dotnet test --project tests/Explore.Infrastructure.Tests/Explore.Infrastructure.Tests.csproj --configuration Release --verbosity quiet -- --treenode-filter "/*/*/*/*[Category!=Runtime]" --minimum-expected-tests 1
dotnet test --project tests/Event.Persistence.IntegrationTests/Event.Persistence.IntegrationTests.csproj --configuration Release --verbosity quiet
dotnet test --project tests/Event.API.IntegrationTests/Event.API.IntegrationTests.csproj --configuration Release --verbosity quiet
dotnet test --project tests/Explore.Blazor.IntegrationTests/Explore.Blazor.IntegrationTests.csproj --configuration Release --verbosity quiet
dotnet test --project tests/Explore.Blazor.Client.Tests/Explore.Blazor.Client.Tests.csproj --configuration Release --verbosity quietWhen a change touches SMTP, EmailDispatch, or optional RabbitMQ transport, also run the focused runtime category that matches the change:
dotnet test --project tests/Explore.Infrastructure.Tests/Explore.Infrastructure.Tests.csproj --configuration Release --verbosity quiet -- --treenode-filter "/*/*/*/*[Category=Email]" --minimum-expected-tests 1
dotnet test --project tests/Explore.Infrastructure.Tests/Explore.Infrastructure.Tests.csproj --configuration Release --verbosity quiet -- --treenode-filter "/*/*/*/*[Category=RabbitMQ]" --minimum-expected-tests 1Architecture tests are CI gates — not optional. They enforce:
- Layer dependencies — Domain has no upstream references
- Naming conventions — handlers, validators, specifications follow suffixes
- Accessibility — routable pages have
<h1>, MainLayout has landmarks - Authorization parity — every
ResourceKindsconstant has a Cerbos policy, aFallbackAuthorizationServicecase, and a JSON schema - Descriptor coverage — every
ResourceDescriptorskind is a validResourceKindsconstant - Schema coverage — every Cerbos policy YAML references both principal and resource schemas
- Documentation & XML comments — public symbols and classes have clear XML doc comments where non-inferable (legacy synthetic
ABOUTME:headers in source code are retired)
See TESTING.md for the full list of architecture convention tests.
Every non-trivial PR must record one documentation impact outcome:
| Outcome | Use When |
|---|---|
| Updated | Behavior, commands, configuration, API contracts, operator flows, or release notes changed and docs were updated in the same PR. |
| Not needed | The change is internal and does not alter documented behavior. |
| Deferred | Docs impact exists but is intentionally split; include owner, follow-up path, and reason. |
- Source code is self-documenting through Clean Architecture naming, folder structure, and standard XML doc comments (
/// <summary>) where non-inferable (syntheticABOUTME:headers in.cssource code are retired; documentation files indocs/internal/and.agents/use natural Markdown metadata blocks or standard frontmatter) - File-scoped namespaces for all new C# files
- No
as any,@ts-ignore, or type error suppression equivalents - No empty catch blocks
- Comments explain what/why, not change history
- Repositories return entities, not DTOs — mapping happens in handlers
- Validators are manually instantiated in handlers (not injected via DI)
- Navigation properties are readonly; writes go through repositories
- Use
Guidfor core aggregates,intfor lookups - Commands return
BaseCommandResponse<TId> GETendpoints:[AllowAnonymous]; write endpoints:[Authorize]
See QUICK_REFERENCE.md for the complete constraint list.
When modifying or adding CSS:
- Never add bare
.mud-*selectors — MudBlazor overrides go only inmudblazor-overrides.css - Use design tokens —
var(--isl-*)instead of hardcoded values - Respect layer order: reset → base → tokens → mudblazor-overrides → components → utilities
- Scoped CSS — use
component.razor.csswith BEM naming and::deepfor child components - No physical direction properties in scoped CSS — use logical properties (
margin-inline-startnotmargin-left)
See DESIGN_SYSTEM.md for full CSS architecture details.
Changes must respect layer boundaries:
| Layer | May Reference |
|---|---|
| Domain | Nothing (self-contained) |
| Application | Domain only |
| Persistence | Domain, Application |
| Infrastructure | Domain, Application |
| API | All layers (composition root) |
| Blazor | Own services + generated API client |
Architecture tests enforce these boundaries automatically.
When DTO contracts change, sequence matters to avoid false compile failures.
- Update DTOs, validators, mappings, and handlers in API/Application layers
- Build API:
dotnet build --project Explore.API/Explore.API.csproj --configuration Release --verbosity quiet - Confirm the API build refreshed
schemas/openapi_islamu-event.jsonthrough build-time OpenAPI generation - Build Blazor client:
dotnet build --project Explore.Blazor.Client/Explore.Blazor.Client.csproj --configuration Release --verbosity quiet - Update Blazor services/components that use the generated client types
- Rebuild and rerun all tests
The Blazor client auto-generates API types from schemas/openapi_islamu-event.json via NSwag. If UI code is changed before client regeneration, you get false compile failures because generated types still reflect the old API contract.
TDD is the default unless explicitly allowed to skip.
- Write a failing test
- Run to confirm failure
- Write minimal code to pass
- Run tests — all must pass
- Refactor with tests green
Before submitting:
- Scope is focused and independently testable (target ≤ 4 hours of work)
- Pull request template is completed with summary, linked context, docs impact, validation, and risk notes
- Build succeeds:
dotnet build --configuration Release --verbosity quiet - All 9 standard PR test projects pass individually
- Architecture tests pass (layer deps, naming, accessibility, auth parity)
- Documentation impact is recorded:
Updated,Not needed, orDeferredwith reason - New C# files use self-documenting naming and XML doc comments (
/// <summary>) where non-inferable - New CSS follows layer architecture and uses design tokens
- API contract changes include docs updates (
docs/API.md,docs/API_CHANGELOG.md) - Configuration portability changes regenerate both v1alpha2 JSON Schemas, OpenAPI, API inventory, and the NSwag client; the second generation is byte-stable and no generated file was hand-edited
- Operator/release changes update
docs/SELF_HOSTING.md,docs/BACKUP_RESTORE_UPGRADE.md, ordocs/RELEASE_CHECKLIST.mdwhen applicable - Multi-session work records bounded resume and handoff state in its task-owned
*-context.mdfollowing Context Engineering - Breaking changes are explicitly documented
- No type error suppression (
as any,@ts-ignore) - No empty catch blocks or deleted failing tests
- PR author ensures all checklist items pass
- Reviewer verifies architecture compliance and test coverage
- CI runs full build + all test projects
- Merge requires passing CI and reviewer approval
- GETTING_STARTED.md — setup and first run
- FIRST_CONTRIBUTION.md — shortest safe path for first-time contributors
- TESTING.md — test framework and project roles
- DOCUMENTATION_ARCHITECTURE.md — docs metadata, source anchors, and docs impact contract
- ARCHITECTURE.md — layer boundaries
- DESIGN_SYSTEM.md — CSS architecture and component wrappers
- QUICK_REFERENCE.md — hard constraints