Skip to content

Conversation

@samtrion
Copy link
Contributor

No description provided.

@samtrion samtrion self-assigned this Jan 25, 2026
@samtrion samtrion added the type:feature Indicates a new feature or enhancement to be added. label Jan 25, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 25, 2026

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one) (1)
  • state:ready for merge

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Jan 25, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.36%. Comparing base (613e6ee) to head (df725b5).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #140   +/-   ##
=======================================
  Coverage   76.36%   76.36%           
=======================================
  Files          16       16           
  Lines         165      165           
  Branches       24       24           
=======================================
  Hits          126      126           
  Misses         33       33           
  Partials        6        6           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@samtrion samtrion force-pushed the feature/dynamic-content-routing branch 5 times, most recently from 32c38c1 to d7124d1 Compare January 26, 2026 06:27
Implements TASK-001 to TASK-017 of Phase 1 (Core Interfaces and Abstractions).

Added:
- ContentDescriptor base class with required Title, Slug, PublishedDate
- ResolvedContent<TDescriptor> with init-only properties
- Routing interfaces: IRoutingBuilder, IRootConfiguration, ICultureConfiguration, ISegmentConfiguration, IPageConfiguration
- Pagination: IPaginationConfiguration with PageSize and UrlFormat
- Metadata: IMetadataConfiguration for custom fields
- Storage: IContentStorageProvider, IAssetStorageProvider, IContentStorageBuilder, IAssetStorageBuilder, IFileSystemStorageOptions, IPublishingService
- Enums: CultureCanonical (WithoutPrefix, WithPrefix), PaginationUrlFormat (Numeric, Prefixed)
- Phase 1 unit tests (21 tests) validating all contracts

Quality gates:
- Build: successful
- Tests: 121 tests passed
- XML docs: present on all public APIs
- CancellationToken parameter standardized: ct -> cancellationToken
- Constraints: DateTimeOffset, English, no regions, .NET 10/C#13
Implements TASK-018, TASK-019, TASK-020, TASK-021, TASK-022, TASK-023, TASK-024, TASK-025, TASK-026, TASK-027
Implemented comprehensive Markdown and YAML frontmatter parsing pipeline:

**Package Management:**
- Added Markdig 0.41.0 for Markdown rendering with advanced extensions
- Added YamlDotNet 16.3.0 for YAML frontmatter parsing (camelCase convention)
- Updated Directory.Packages.props and ForgingBlazor.csproj references

**Parsing Components:**
- FrontmatterParser: Static class extracting YAML between --- delimiters
- MarkdownRenderer: Static class with Markdig pipeline (advanced extensions, tables, task lists, auto links, emoji)
- ContentParser: Static orchestrator coordinating all parsing steps

**Validation & Mapping:**
- ContentValidationException: Public exception with parameterless constructor for CA1032 compliance
- FrontmatterValidation: Static validation for required fields (title, slug, publishedDate), slug format, DateTimeOffset parsing with InvariantCulture
- ContentDescriptorFactory: Static reflection-based factory mapping frontmatter properties with case-insensitive matching, type conversion for DateTimeOffset/bool/enum, nullable handling

**Quality Assurance:**
- All classes use CultureInfo.InvariantCulture for date/bool parsing (CA1305 compliance)
- Static classes for utility methods (CA1822, S1118, S2325 compliance)
- Null validation via ArgumentNullException.ThrowIfNull
- Build: Successful without warnings or errors
- Tests: All 147 tests passing

Refs: REQ-CNT-001 through REQ-CNT-005, TASK-028 through TASK-037
Implements TASK-047 to TASK-051:
- Add CultureResolver for parsing cultures from two-letter codes, LCIDs, and full formats
- Add CultureFallbackChain implementing de-DE → de → en-US → en fallback hierarchy
- Add CultureContentLocator for locating content files using culture fallback
- Add ContentLookupPath record for content file paths with culture suffixes
- Add CultureValidation for startup validation of culture configuration
- Refactor all test assertions from ThrowsExactly to Assert.Throws pattern
- Use parameterName overload for ArgumentException assertions

Refs: TASK-047, TASK-048, TASK-049, TASK-050, TASK-051
Implements TASK-052 to TASK-057:
- Add RouteDefinition record for route metadata
- Add RouteRegistry for thread-safe route storage
- Add RouteResolver for path-to-route matching
- Add CanonicalUrlGenerator for culture-aware canonical URLs
- Add CanonicalLinkComponent.razor for canonical link tags
- Add PaginationSettings record as Phase 7 prerequisite
- Add comprehensive unit tests for all components

Refs: TASK-052, TASK-053, TASK-054, TASK-056, TASK-057
…unnecessary async/await

feat(dependencies): upgrade bunit package to version 1.34.0
refactor(routing): simplify method implementations and improve readability
- Use full culture name (de-DE) instead of two-letter code (de) in CanonicalUrlGenerator
- Fix CultureFallbackChain to always include requested culture first
- Handle trailing slash correctly for root paths with culture prefix

All 306 tests now passing
Implements TASK-044 to TASK-046:
- FileSystemWatcherService with 300ms debounced file change detection
- ContentCacheService with culture-aware caching (30min sliding, 4h absolute expiration)
- ContentCacheInvalidationHandler connecting file system events to cache invalidation

All 315 tests passing (+9 new tests for caching and file watching).

Refs: TASK-044, TASK-045, TASK-046
Implements TASK-059 to TASK-062:
- Add PaginatedResult<T> wrapper class for paginated collections
- Add PaginationService for page calculations and URL generation
- Add PaginationUrlParser for Numeric and Prefixed format parsing
- Add PaginationRouteConstraint for route validation
- Comprehensive test coverage for pagination logic (57 new tests)

Features:
- CreatePaginatedResult handles empty collections, first/middle/last pages
- IsValidPageNumber validates page ranges with 404 for out-of-range
- GeneratePageUrl supports Numeric (/posts/2) and Prefixed (/posts/page-2) formats
- Page 1 canonical at segment root (/posts not /posts/1)
- Negative number rejection in URL parsing
- Edge case handling: zero pages, exact boundaries, single pages

All 372 tests passing.

Refs: TASK-059, TASK-060, TASK-061, TASK-062
Implements TASK-076 to TASK-078:
- Add ContentComponent<TDescriptor> base class for content components
- Add ComponentValidation for @page/@layout directive enforcement
- Add ForgingRouteView with ResolvedContent<T> parameter handling
- Add ForgingRouter with navigation and routing infrastructure
- Comprehensive XML documentation on all public APIs

Features:
- ContentComponent<TDescriptor> provides typed content component base (REQ-CMP-011)
- ComponentValidation ensures no @page/@layout directives (REQ-CMP-009, REQ-CMP-010)
- ForgingRouteView handles RouteData binding and ResolvedContent injection
- ForgingRouter provides Router-compatible API for future content routing
- Implements IComponent, IHandleAfterRender, IDisposable per Blazor patterns
- NavigationManager integration with location change subscriptions
- RenderFragment handling for Found/NotFound/Navigating states

All 372 tests passing.

Refs: TASK-076, TASK-077, TASK-078
…, startup validation, and service registration

Implements TASK-063 to TASK-075:

Phase 8 - Publishing Workflow:
- Add PublishingService implementing IPublishingService (TASK-063)
- Add PublishingConfirmationService for user confirmation management (TASK-064)
- Add ContentExpirationService using TimeProvider for expiration checks (TASK-065)
- Add DraftContentFilter for environment-based draft filtering (TASK-066)

Phase 9 - Startup Validation:
- Add RoutingConfigurationValidation with IValidateOptions (TASK-067)
- Add ContentStructureValidation for file existence checks (TASK-068)
- Add StorageConfigurationValidation for base path validation (TASK-069)
- Add StartupValidationHostedService for aggregated validation (TASK-070)

Phase 10 - Service Registration:
- Add AddRoutingServices for route registry and resolver (TASK-071)
- Add AddContentServices for content infrastructure (TASK-072)
- Add AddStorageServices for publishing confirmation (TASK-073)
- Add AddValidationServices for validation infrastructure (TASK-074)
- Add AddCultureServices for culture fallback and validation (TASK-075)

Features:
- PublishingService with TODO for segment/culture enumeration
- PublishingConfirmationService with concurrent confirmation management
- ContentExpirationService using TimeProvider per CON-DEC-002
- DraftContentFilter respecting development/production environments
- Comprehensive startup validation with fail-fast error aggregation
- Service registration methods excluding static utility classes

All 372 tests passing.

Refs: TASK-063, TASK-064, TASK-065, TASK-066, TASK-067, TASK-068, TASK-069, TASK-070, TASK-071, TASK-072, TASK-073, TASK-074, TASK-075
All 372 tests passing. Plan document reflects complete status of Phases 1-11.
…ode-only components

- Remove ForgingRouter.razor and ForgingRouteView.razor files
- Implement BuildRenderTree method for both components
- Remove partial class declarations
- Add ArgumentNullException.ThrowIfNull for builder parameter
- All 372 tests passing
Implements TASK-084 through TASK-092
- Create ForgingBlazor.Storage.AzureBlob project
- Add Azure.Storage.Blobs 12.24.0 package
- Implement IAzureBlobStorageOptions and AzureBlobStorageOptions
- Implement AzureBlobContentStorageProvider with async blob operations
- Implement AzureBlobAssetStorageProvider with content-type detection
- Create ContentStorageBuilderExtensions and AssetStorageBuilderExtensions
- Add comprehensive README.md with usage examples

Refs: TASK-084, TASK-085, TASK-086, TASK-087, TASK-088, TASK-089, TASK-090, TASK-091, TASK-092
Implements TASK-095
- Create CheckSlugTests with 24 test cases
- Test valid slugs including minimum (3 chars) and maximum (70 chars) boundaries
- Test invalid starts/ends (hyphens, digits)
- Test consecutive hyphens rejection
- Test invalid characters (Unicode, special chars, whitespace)
- Test ValidateSlug exception messages and parameter names
- All 431 tests passing

Refs: TASK-095
Update last_updated timestamp after completing Phase 12 (Azure Blob Storage)
and Phase 13 (Core Interface Tests)
- Fixed IContentStorageProvider implementation in AzureBlobContentStorageProvider
  - Changed methods to use generic TDescriptor instead of string return types
  - Changed culture parameter from string to CultureInfo
  - Updated GetContentsAsync to return IReadOnlyList<TDescriptor>
  - Fixed ExistsAsync signature to accept single path parameter
  - Integrated ContentParser.Parse for descriptor creation

- Fixed IAssetStorageProvider implementation in AzureBlobAssetStorageProvider
  - Changed GetAssetAsync return type from Task<byte[]?> to Task<Stream>
  - Changed SaveAssetAsync parameter from byte[] to Stream
  - Changed GetAssetsAsync parameter from optional prefix to required folder
  - Updated to use DownloadStreamingAsync for stream-based retrieval

- Added project reference to ForgingBlazor in ForgingBlazor.Storage.AzureBlob.csproj
  to access ContentParser for content parsing

- Added InternalsVisibleTo for NetEvolve.ForgingBlazor.Storage.AzureBlob in
  ForgingBlazor.csproj to allow access to internal ContentParser API

- Fixed CA1308 code analysis warning by changing ToLowerInvariant to
  ToUpperInvariant in GetContentType method

All build errors resolved, build succeeds, and all 431 tests pass.
- Removed unnecessary global:: prefix from using directives in multiple files.
- Changed List<string> instantiation to use the simpler syntax in ContentStructureValidation.cs and StartupValidationHostedService.cs.
- Added unit tests for CanonicalLinkComponent and RouteDefinition to enhance test coverage.
- Improved thread safety tests in RouteRegistryTests and RouteResolverTests.
- Added new tests for route registration and resolution scenarios.
- Add FrontmatterParserTests.cs with 11 tests covering YAML extraction, edge cases
- Add MarkdownRendererTests.cs with 13 tests for HTML rendering validation
- Add ContentParserTests.cs with 11 tests for full parsing pipeline
- Fix case-insensitive frontmatter validation using ToUpperInvariant (CA1308)
- Add array/list conversion support in ContentDescriptorFactory
- Fix malformed YAML test to expect InvalidOperationException
- Replace obsolete HasCount() with Count() in TUnit assertions

Implements TASK-100, TASK-101, TASK-102, TASK-103
Refs: Phase 15 - Unit Tests Content Parsing

All tests passing: 538/538 ✅
Implements TASK-096, TASK-097, TASK-098, TASK-099 delivering complete routing unit test coverage:
- SlugRouteConstraintTests (40 tests): validates slug pattern matching with comprehensive edge cases including min/max length boundaries, valid/invalid characters, consecutive hyphens, special cases
- RoutingBuilderTests (14 tests): verified existing tests for FluentAPI configuration and nested segments
- RouteResolverTests (13 tests): verified existing tests for path matching and normalization
- CanonicalUrlGeneratorTests (21 tests): verified existing tests for culture-aware URL generation

Test results: 573 tests passing (+40 new)
Build status: successful with existing warnings

Refs: TASK-096, TASK-097, TASK-098, TASK-099
Phase 16 - Unit Tests Culture (GOAL-016):
- TASK-096: CultureResolverTests.cs verified (18 tests)
  * Two-Letter code parsing (en, de, fr)
  * LCID parsing (1033 for en-US, 1031 for de-DE)
  * Full culture name parsing (de-DE, fr-FR)
  * Invalid inputs, null/empty/whitespace handling
  * Case insensitivity testing

- TASK-097: CultureFallbackChainTests.cs verified (11 tests)
  * Complete fallback hierarchy: de-DE → de → en-US → en → invariant
  * Custom default culture support
  * Duplicate elimination in chain
  * Culture suffix generation (.de-DE, .de, .en-US, .en, empty)

- TASK-098: CultureContentLocatorTests.cs verified (6 tests)
  * Lookup path generation with culture suffixes
  * Constructor validation
  * Different culture handling

Phase 17 - Unit Tests Pagination (GOAL-017):
- TASK-107: PaginationServiceTests.cs verified (30 tests)
  * Page calculation (first/middle/last pages)
  * Empty collection handling
  * Page size boundaries (minimum 1)
  * Exact page boundaries
  * Out-of-range page validation
  * URL generation (Numeric & Prefixed formats)

- TASK-108: PaginationUrlParserTests.cs verified (23 tests)
  * Numeric format parsing (e.g., "2")
  * Prefixed format parsing (e.g., "page-2")
  * Invalid inputs (negative, zero, non-numeric)
  * Case-insensitive prefix matching
  * Edge cases (empty/whitespace, missing numbers)

Total: 88 tests verified passing (35 culture + 53 pagination)
All tests: 573/573 ✅

Refs: Phase 16 - Unit Tests Culture, Phase 17 - Unit Tests Pagination
- Add RoutingConfigurationValidationTests with 10 tests for configuration validation
- Add ContentStructureValidationTests with 13 tests for content structure validation
- Add StorageConfigurationValidationTests with 11 tests for storage configuration validation

Validation coverage includes:
- Routing: null checks, empty collections, culture validation, component/layout types
- Content: constructor validation, missing files, segment/page detection, pagination
- Storage: path validation, directory existence, null/empty/whitespace handling

Implements TASK-112, TASK-113, TASK-114
Refs: Phase 19 - Unit Tests Validation

All tests passing: 609/609 ✅
…d storage

- Add AzureBlobContentStorageProviderTests with Azurite emulation (10 tests)
- Add ContentRoutingIntegrationTests with route resolution tests (7 tests)
- Add PublishingWorkflowIntegrationTests with draft/expiration workflow tests (11 tests)
- Add TestContentFixture for sample content generation with multi-culture support
- All integration tests pass successfully (627/637 total tests passing)
- Azurite tests properly skip when emulator is not running (10 tests)

Implements TASK-115, TASK-116, TASK-117, TASK-118, TASK-119
Refs: Phase 20 - Integration Tests

All tests passing: 627/637 \u2705 (10 Azurite tests skipped as expected)
- Extract StorageConfiguration into separate file
- Extract RoutingConfiguration into separate file
- Add Testcontainers.Azurite 4.2.0 for automated integration testing
- Configure AzuriteFixture with --skipApiVersionCheck flag

Follows one-class-per-file principle for better maintainability.

Refs: Phase 20 - Integration Tests
- Move AzuriteFixture from AzureBlobContentStorageProviderTests.cs to AzuriteFixture.cs
- Ensures one-class-per-file principle in tests directory

Follows architectural decision for better test organization.
- Use [ClassDataSource<AzuriteFixture>] attribute for dependency injection
- Implement IAsyncInitializer and IAsyncDisposable in AzuriteFixture
- Convert static methods to instance methods using fixture parameter
- Change AzuriteFixture visibility from internal to public
- Fix invalid slugs in test data (post-1 → post-one, post-2 → post-two)

This follows TUnit best practices for shared test fixtures and enables
proper lifecycle management through the framework.

All 10 tests passing.
@samtrion samtrion force-pushed the feature/dynamic-content-routing branch from dc64572 to 7957500 Compare January 28, 2026 10:40
- Add ForgingRouteView unit tests (7 tests)
- Add ForgingRouter unit tests (8 tests)
- Add ForgingRouterSmokeTests integration tests (7 tests)
- Verify all 652 tests passing

Implements TASK-081, TASK-082, TASK-083
Completes Phase 11 and Phase 18 testing requirements
Refs: TASK-081, TASK-082, TASK-083, TASK-109, TASK-110, TASK-111
- Mark TASK-081 through TASK-083 as completed (2026-01-28)
- Mark TASK-109 through TASK-111 as completed (2026-01-28)
- Add Phase 18 completion report with test summary
- Update Phase 11 report with new test details

All 652 tests passing
… improve exception handling in ForgingRouter tests
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type:feature Indicates a new feature or enhancement to be added.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants