Skip to content

Latest commit

 

History

2,398 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

redmuffin.Blazor.StaticWeb (preview - alpha)

Build Status CodeQL Last Commit (master)

License: Unlicense Dependabot enabled GitHub language count GitHub code size in bytes

.NET 10 .NET 9 Blazor WebAssembly Azure Functions C# 13 TUnit Code Coverage Foundation

Maintenance GitHub commit activity

Project Status

Alpha/Preview Release - This project is in early development. While functional, expect:

  • Breaking changes between versions
  • Incomplete documentation
  • Active development with frequent updates
  • Limited production readiness

Suitable for experimentation, learning, and development environments.

Overview

redmuffin.Blazor.StaticWeb is a modern full-stack web application built with Blazor WebAssembly (.NET 9) and Azure Functions (.NET 9). The solution provides a performant, maintainable static web application with serverless backend capabilities, featuring OAuth integration and comprehensive testing infrastructure.

Table of Contents


Features

Core Functionality

  • Blazor WebAssembly (.NET 9) - Client-side execution with modern C# features
  • Azure Functions (.NET 9) - Serverless backend with HTTP triggers
  • Raindrop.io OAuth Integration - External API integration with secure authentication
  • Markdown Content Rendering - Advanced Markdown processing with Markdig

Development & Quality

  • Modern C# (C# 12/13) features - Primary constructors, collection expressions, ref readonly parameters
  • Comprehensive Testing - TUnit framework with hand-rolled fakes (see rm-guide-testing)
  • Code Coverage - Automated coverage reports with Coverlet and ReportGenerator
  • PowerShell Automation - Scripts for coverage report generation and viewing
  • SCSS Styling Only - All styling should be done using SCSS files in the wwwroot/scss/ directory.
  • CSS Files are Auto-Generated - Direct modifications to CSS files are not allowed; they are automatically generated from SCSS.
  • SCSS Partials - All SCSS partial files must start with an underscore (_) and be included in app.scss for automatic compilation.
  • Feature Folder Structure - Organized by feature for better maintainability
  • Code Quality & Security - CodeQL analysis, automated builds, Dependabot integration
  • Accessibility Compliance - WCAG 2.1 AA standards with semantic HTML and ARIA support

Infrastructure & Tools

  • EditorConfig - Consistent code style and formatting
  • Directory.Build.props - Centralized project configuration
  • Azure Static Web Apps - Deployment and hosting platform

Prerequisites

For Local Development

  • Visual Studio 2026 (Community)
  • .NET 10 SDK — Builds net9.0 projects for Azure SWA compatibility
  • Node.js (Latest LTS)
  • Python 3.10+ - Required for code-review-graph MCP server
  • PowerShell - Required for running project scripts (install on Linux: yay -S powershell)
  • RTK (Rust Token Killer) - Required for OpenCode (reduces token consumption by 60-90%)

Global Tools

Python Tools (pip)

  • code-review-graph (Optional - for token-efficient code reviews) Local knowledge graph for AI-assisted code understanding. Provides blast radius analysis, community detection, and semantic search:

    pip install code-review-graph
    code-review-graph install     # Configure for OpenCode
    code-review-graph build      # Build the knowledge graph

    What it provides:

    • 28 MCP tools for code analysis
    • Blast radius analysis (what changes break)
    • Community detection (architectural boundaries)
    • 6.8x-49x token reduction on code reviews

    Note: On Windows, OpenCode's MCP stdio layer has known issues (#16449). The tool works via shell execution but may not appear in OpenCode's MCP list. This is a known OpenCode bug, not a config issue.

Node.js Tools (npm)

  • Azure Static Web Apps CLI Required for local development and testing of Azure Static Web Apps:

    npm install -g @azure/static-web-apps-cli
  • Prettier (Required for OpenCode formatter) Required for auto-formatting non-.NET files (SCSS, CSS, JSON, Markdown, YAML):

    npm install -g prettier
  • commitlint (Required for commit message validation) Validates commit messages against Conventional Commits format:

    npm install -g @commitlint/cli @commitlint/config-conventional
  • chrome-devtools-mcp (Required for Chrome DevTools MCP integration) Enables AI-powered browser automation, performance analysis, and debugging. Required for the Chrome DevTools MCP server in opencode.json:

    npm install -g chrome-devtools-mcp

    Note: This MCP server provides browser control capabilities including navigation, script execution, screenshots, performance tracing, and network inspection. It uses the --isolated flag to run Chrome in an incognito-like mode with automatic cleanup.

  • cc-safety-net (Required for OpenCode plugin) AI agent safety net that blocks destructive git and filesystem commands before execution. Prevents accidental data loss from AI agent mistakes. MIT licensed, open source:

    npm install -g cc-safety-net

    Push Protection: The project uses two complementary layers to prevent unauthorized remote pushes and protected history rewrites:

    Layer Mechanism Blocks
    1. cc-safety-net Semantic command analysis via tool.execute.before hook git push --force / -f (destroys history)
    2. block-push.js Custom OpenCode plugin (.opencode/plugins/block-push.js) ALL git push and git revert

    Blocked Commands (cc-safety-net Built-in Rules):

    Command Pattern Reason
    git push --force / -f Destroys remote history
    git reset --hard Destroys all uncommitted changes permanently
    git checkout -- * Discards uncommitted changes permanently
    git clean -f* Removes untracked files permanently
    git branch -D * Force-deletes without merge check
    rm -rf / or rm -rf ~ Targeting root or home directory
    rm -rf . or rm -rf ../path Outside current working directory

    Note: This plugin is registered in opencode.json and intercepts all bash commands via the tool.execute.before hook. It provides semantic command analysis (not simple pattern matching), shell wrapper detection, and interpreter one-liner detection. Default mode blocks only truly destructive operations while allowing safe git workflows. See Supply Chain Attack Protection for npm security settings.

.NET Tools

  • Project-Local Tools (automatically managed) The project includes pre-configured .NET tools in .config/dotnet-tools.json:

    # Restore all project-local tools
    dotnet tool restore

    Included Tools:

    • Microsoft.Web.LibraryManager.Cli (LibMan) - Client-side library management
  • Additional Global Tools (installed automatically by scripts) These tools are installed on-demand by the project scripts:

    • dotnet-reportgenerator-globaltool - Code coverage report generation

    Manual Installation (if needed):

    # Install ReportGenerator globally
    dotnet tool install --global dotnet-reportgenerator-globaltool

AI Assistant Tools

  • RTK (Rust Token Killer) - CLI proxy that reduces LLM token consumption by 60-90% on common dev commands Required for optimal OpenCode performance by compressing verbose command outputs (git, tests, package managers, etc.).

    Installation (Windows):

    # Download the latest Windows binary
    curl -L -o rtk.zip https://github.com/rtk-ai/rtk/releases/latest/download/rtk-x86_64-pc-windows-msvc.zip
    
    # Extract to a directory in PATH (e.g., C:\Users\<username>\bin)
    Expand-Archive -Path rtk.zip -DestinationPath .
    Move-Item rtk.exe C:\Users\$env:USERNAME\bin\rtk.exe
    
    # Verify installation
    rtk --version

    Installation (Linux/Omarchy):

    # Quick install script
    curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/master/install.sh | sh
    
    # Or manual installation
    curl -L -o rtk.tar.gz https://github.com/rtk-ai/rtk/releases/latest/download/rtk-x86_64-unknown-linux-musl.tar.gz
    tar -xzf rtk.tar.gz
    chmod +x rtk
    sudo mv rtk /usr/local/bin/rtk
    
    # Verify installation
    rtk --version

    OpenCode Integration:

    # Initialize RTK for OpenCode (installs plugin automatically)
    rtk init -g --opencode
    
    # Restart OpenCode for plugin to load

    What RTK Does:

    • Automatically compresses git status, cargo test, pnpm list, etc.
    • Reduces token usage by 60-90% for development commands
    • Works transparently - no changes needed to your workflow
    • Plugin integrates directly with OpenCode's tool execution

    Token Savings Examples:

    • git status: ~2,000 tokens → ~400 tokens
    • cargo test: ~25,000 tokens → ~2,500 tokens
    • pnpm list: ~8,000 tokens → ~2,400 tokens

    Note: RTK requires restarting OpenCode after installation. The plugin handles all command rewriting automatically.

Optional Tools

  • Azure CLI - For Azure resource management and deployment
  • Docker Desktop

.NET SDK Guide

This project uses .NET 10 SDK (10.0.104+) to build and test .NET 9 projects. All .csproj files target net9.0 for compatibility with Azure Static Web Apps (which does not yet support .NET 10 managed Functions). The SDK version and target framework are separate concerns — the SDK is just the build tool.

Why SDK 10?

Benefit Detail
Faster builds SDK 10 includes MSBuild and Roslyn performance improvements
Latest C# 13 features Available in the QualityGates tools project (targets net10.0)
Single SDK One global.json for the entire repository — no per-directory version switching
Future-proof Ready when Azure SWA adds .NET 10 support

Installation

# Install .NET 10 SDK (Arch Linux)
sudo pacman -S dotnet-sdk-10.0

# Install Blazor WebAssembly build tools
sudo dotnet workload install wasm-tools

Quick Verification

dotnet --version    # Should show 10.0.xxx
dotnet build        # 11 projects, 0 errors
dotnet run --project tests/redmuffin.Blazor.StaticWeb.Tests  # 293 tests pass

Key Commands

# Build everything (from repo root)
dotnet build

# Run main solution tests
dotnet run --project tests/redmuffin.Blazor.StaticWeb.Tests -c Release

# Run quality gates on tools solution
cd tools && dotnet run -- all

# Run quality gates on main solution
cd tools && dotnet run -- all --solution ../redmuffin.Blazor.StaticWeb.slnx

# Publish Blazor WASM for production
dotnet publish src/redmuffin.Blazor.StaticWeb -c Release \
  -p:PublishTrimmed=true -o publish/blazor

# Publish API for production
dotnet publish src/redmuffin.Blazor.StaticWeb.Api -c Release \
  -o publish/api

Why target net9.0?

Azure Static Web Apps managed Functions currently support up to .NET 9 (apiRuntime: dotnet-isolated:9.0 in staticwebapp.config.json). The .NET 10 Functions runtime is not yet available on SWA. When it becomes available, updating is a single-line change in each .csproj.

The Blazor WebAssembly app also targets net9.0 for consistency, even though it runs entirely in the browser and has no server-side runtime constraint.


Development Environment

Quick Start:

# Clone and setup
git clone https://github.com/michaelvolz/redmuffin.Blazor.StaticWeb.git
cd redmuffin.Blazor.StaticWeb
npm install -g @azure/static-web-apps-cli prettier @commitlint/cli @commitlint/config-conventional chrome-devtools-mcp

# Setup git hooks (run once)
.\scripts\Setup-GitHooks.ps1

# Build and run
dotnet restore
dotnet build
dotnet test

# Open in Visual Studio or run:
dotnet run --project src/redmuffin.Blazor.StaticWeb/redmuffin.Blazor.StaticWeb.csproj

PowerShell Helper Scripts

Located in scripts/:

Script Purpose
Update-PackageVersions.ps1 Updates CPM-managed NuGet package versions
Generate-CoverageReport.ps1 Generates code coverage
View-CoverageReport.ps1 Views coverage report
Setup-GitHooks.ps1 Configures git hooks for commit validation

For package updates, run scripts/Update-PackageVersions.ps1 and finish with dotnet clean && dotnet build --verbosity quiet && dotnet test.

Creating an alias (optional): Add to your PowerShell profile ($PROFILE):

Set-Alias -Name opencode -Value "C:\path\to\scripts\opencode-secure.ps1"

Getting Started

Local Development Workflow

  1. Clone the repository:

    git clone https://github.com/michaelvolz/redmuffin.Blazor.StaticWeb.git
    cd redmuffin.Blazor.StaticWeb
  2. Verify prerequisites:

    • Check .NET versions: dotnet --list-sdks
    • Ensure you have .NET 9 SDK installed
    • Verify Node.js: node --version
  3. Install global tools:

    npm install -g @azure/static-web-apps-cli prettier @commitlint/cli @commitlint/config-conventional chrome-devtools-mcp
  4. Setup git hooks:

    .\scripts\Setup-GitHooks.ps1
  5. Build and run:

    dotnet restore
    dotnet build
    dotnet test
  6. Start development:

    # Using Visual Studio
    # Open redmuffin.Blazor.StaticWeb.sln
    # Use "Start both" profile
    
    # Or using CLI
    dotnet run --project src/redmuffin.Blazor.StaticWeb/redmuffin.Blazor.StaticWeb.csproj --launch-profile https

    This is the normal day-to-day dev server command. scripts/Start.ps1 is reserved for final integration-style testing and broader environment validation.

  7. Navigate to:

Validation Steps

After setup, verify everything is working:

  1. Build succeeds without errors
  2. All tests pass
  3. Application loads at http://localhost:4280
  4. API endpoints are accessible (check browser dev tools Network tab)
  5. Hot reload works (modify a .razor file and see changes)

Known Build Warnings

IL2111 Warnings (Expected and Safe to Ignore):

During development and building, you may encounter IL2111 warnings like:

warning IL2111: Method 'Microsoft.AspNetCore.Components.LayoutView.Layout.set' with parameters or return type with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method.

These warnings are expected and safe to ignore because:

  • They occur in generated Razor files (App_razor.g.cs) during Blazor WebAssembly compilation
  • They are related to Blazor's internal layout handling mechanism
  • They do not affect application functionality or performance
  • They are part of the normal Blazor compilation process and ASP.NET Core Components trimming optimization
  • They are in generated code that is not under developer control

Action required: None - these warnings can be safely ignored during development and deployment.

Next Steps


Development Workflow

Trunk-Based Development

This project follows Trunk-Based Development - a source-control branching model where developers collaborate on code in a single branch called 'trunk' (or 'main'/'master'), avoiding long-lived feature branches.

Key Principles

  • Single Main Branch: All development happens on the master branch
  • Frequent Integration: Developers commit/push to trunk at least once every 24 hours
  • Short-Lived Feature Branches: When used, feature branches are small, short-lived (hours to 1-2 days), and created from a single developer workstation
  • Continuous Integration: Every commit triggers automated builds and tests
  • No Merge Hell: Avoid the complexity of long-lived branches and large merges

Benefits for This Project

  • Continuous Integration Ready: Enables true CI/CD with frequent integration
  • Faster Feedback: Issues are discovered and resolved quickly
  • Simplified Workflow: No complex branching strategies to manage
  • Better Collaboration: All developers work with the latest code
  • Reduced Risk: Smaller, more frequent changes are easier to review and safer to deploy

Workflow Guidelines

  1. Daily Commits: Commit to master at least once per day
  2. Small Changes: Break work into small, incremental commits
  3. Pre-Integration Checks: Run full build and tests before pushing
  4. Feature Flags: Use feature flags for incomplete features rather than branches
  5. Pull Requests: Use short-lived PRs for code review (merge within 24 hours)

Best Practices

  • Keep the Build Green: Never break the build on master
  • Test Locally First: Run dotnet build and dotnet test before pushing
  • Use Feature Flags: Hide incomplete features behind flags instead of long-lived branches
  • Quick Code Reviews: Review and merge PRs promptly to avoid drift
  • Rollback Ready: Maintain ability to rollback any commit if needed

Tools and Automation

  • GitHub Actions: Automated CI/CD pipeline on every push
  • Automated Testing: TUnit tests run on every commit
  • Code Quality Checks: CodeQL security scanning and analysis
  • Deployment Pipeline: Automatic deployment to Azure Static Web Apps

Anti-Patterns to Avoid

  • ❌ Long-lived feature branches (more than 1-2 days)
  • ❌ Delaying integration until "feature complete"
  • ❌ Large batch commits
  • ❌ Breaking the build on master
  • ❌ Avoiding commits due to "incomplete" work

Resources

Test-Driven Development (TDD)

This project embraces Test-Driven Development - a software development methodology that guides software development by writing tests before the actual implementation. TDD was developed by Kent Beck in the late 1990s as part of Extreme Programming.

Core Principles

  • Red-Green-Refactor Cycle: Write a failing test (Red), make it pass with minimal code (Green), then refactor while keeping tests green
  • Test-First Approach: Write tests before writing the production code they're meant to verify
  • Incremental Development: Build software in small, testable increments
  • Continuous Testing: Maintain a comprehensive suite of automated tests that run frequently
  • Design Through Testing: Use tests to drive and validate software design decisions

Benefits for This Project

  • Higher Code Quality: TDD leads to cleaner, more maintainable code with fewer bugs
  • Better Design: Writing tests first forces consideration of API design and component interfaces
  • Faster Feedback: Immediate feedback on code changes through automated test execution
  • Regression Prevention: Comprehensive test suite catches issues when refactoring or adding features
  • Documentation: Tests serve as living documentation of how the code should behave
  • Confidence: Developers can refactor and change code with confidence knowing tests will catch issues

TDD Workflow Guidelines

  1. Write a Failing Test: Start by writing a test that describes the desired behavior
  2. Run the Test: Verify the test fails (Red state) - this confirms the test is valid
  3. Write Minimal Code: Implement just enough code to make the test pass (Green state)
  4. Refactor: Improve the code quality while keeping all tests green
  5. Repeat: Continue the cycle for each new piece of functionality

Best Practices

  • One Test at a Time: Focus on one failing test before moving to the next
  • Small Steps: Make the smallest possible change to pass each test
  • Test Names: Use descriptive test names with underscores (e.g., Should_Return_User_When_Valid_Id_Provided)
  • Fast Tests: Keep tests fast-running to enable frequent execution
  • Independent Tests: Each test should be able to run independently of others
  • Mock External Dependencies: Use hand-rolled fakes for test doubles (see rm-guide-testing for patterns)

TDD with Our Technology Stack

  • TUnit Framework: Modern, fast testing framework optimized for .NET
  • Constructor Injection: Design services with dependency injection for easy testing
  • Component Testing: Use TestContext for testing Blazor components
  • API Testing: Test Azure Functions with HTTP triggers and dependency injection
  • Test Doubles: Hand-rolled fakes as primary pattern. LightMock.Generator available as a compile-time source-gen fallback for large interfaces (see .opencode/skills/redmuffin-standards/rm-guide-testing/SKILL.md)

Testing Principles

  • Pure Functions First: Extract complex logic into public static methods. Test them directly with zero mocking.
  • Fakes Over Mocks: Hand-rolled [Interface]_Fake classes document the contract explicitly and work under WASM/AOT.
  • One Test, One Concept: Each test asserts one logical behavior. Multiple assertions for the same concept are fine.

Tools and Automation

  • Visual Studio Integration: Run tests directly from IDE with full debugging support
  • Continuous Testing: Tests run automatically on every commit via GitHub Actions
  • Code Coverage: Comprehensive coverage reports to ensure test effectiveness
  • Fast Feedback: TUnit's performance optimizations enable rapid test execution

Anti-Patterns to Avoid

  • ❌ Writing tests after the implementation (Test-Last Development)
  • ❌ Testing implementation details instead of behavior
  • ❌ Large, complex tests that are hard to understand and maintain
  • ❌ Skipping the refactor step in the Red-Green-Refactor cycle
  • ❌ Writing tests that are tightly coupled to specific implementations

Resources

Testing Behavior, Not Implementation Details

This project follows authoritative testing best practices that emphasize testing behavior through public interfaces rather than internal implementation details. This approach produces more maintainable, refactor-safe tests that provide long-term value.

Core Principles

  • Test Public Contracts: Focus on testing public methods, parameters, and return values
  • Avoid Internal Dependencies: Do not test private methods, internal data structures, or implementation details
  • Stable Test Foundation: Test what remains stable over time (the interface) rather than what changes frequently (internal logic)
  • Refactor-Safe Design: Write tests that survive refactoring when public behavior remains unchanged
  • Design for Testability: Encourage refactoring internal code to make it more testable through public interfaces

Benefits

  • Maintainable Tests: Tests remain valid as long as public behavior is preserved
  • Flexible Implementation: Internal code can be refactored without breaking tests
  • True Regression Protection: Tests verify actual user-facing behavior, not implementation artifacts
  • Reduced Test Brittleness: Fewer tests break during legitimate refactoring activities
  • Better API Design: Writing tests first against public interfaces leads to cleaner, more intuitive APIs

Guidelines for This Project

  1. Focus on Public APIs: Test methods, properties, and behaviors that are accessible to consumers
  2. Avoid Private Method Testing: If a private method needs testing, consider making it public or refactoring
  3. Test Outcomes, Not Steps: Verify what the code produces, not how it produces it
  4. Use Mocking Judiciously: Mock external dependencies, not internal components
  5. Design Components for Testing: Structure code so that behavior can be validated through public interfaces

Anti-Patterns to Avoid

  • ❌ Testing private methods directly
  • ❌ Asserting on internal data structures or state
  • ❌ Testing implementation details that could change during refactoring
  • ❌ White-box testing that tightly couples tests to current implementation
  • ❌ Testing trivial code (simple getters/setters) that provides no real value

Authoritative References


Usage

Common Development Tasks

Running the Application

# Start the full development environment
# Open redmuffin.Blazor.StaticWeb.sln in Visual Studio
# Press F5 or use "Start both" profile
# Application will be available at http://localhost:4280

Building and Testing

# Build the entire solution
dotnet build

# Run all tests
dotnet test

# Generate code coverage report
.\scripts\Generate-CoverageReport.ps1

# View coverage report
.\scripts\View-CoverageReport.ps1

Working with Features

# Create a new feature (example structure)
# Add files under src/redmuffin.Blazor.StaticWeb/Features/YourFeature/
# - YourFeature.razor           # Main component
# - YourFeature.razor.cs        # Code-behind
# - Components/                 # Child components
# Add component styles as SCSS partial:
# - wwwroot/scss/_YourFeature.scss  # Component styles (imported in app.scss)

API Development

# Add new Azure Function
# Add files under src/redmuffin.Blazor.StaticWeb.Api/Functions/
# Functions are automatically discovered by the runtime

# Test API endpoints
# Use browser dev tools or tools like Postman
# Base URL: http://localhost:4280/api/

Debugging

  • Frontend: Set breakpoints in .razor.cs files
  • Backend: Set breakpoints in Azure Functions
  • Network: Use browser dev tools to inspect API calls

Example Workflows

Adding a New Page

  1. Create src/redmuffin.Blazor.StaticWeb/Features/Pages/NewPage.razor
  2. Add @page "/newpage" directive
  3. Implement component logic in NewPage.razor.cs
  4. Add styles as SCSS partial in wwwroot/scss/_NewPage.scss and import in app.scss
  5. Test locally and add unit tests

Creating an API Endpoint

  1. Create src/redmuffin.Blazor.StaticWeb.Api/Functions/NewFunction.cs
  2. Add [Function("FunctionName")] attribute
  3. Implement HTTP trigger logic
  4. Add corresponding tests in test project
  5. Test with frontend integration

Project Structure

The project follows a feature folder structure to organize code by feature rather than by technical layer. This approach improves maintainability and scalability by grouping related components, services, and assets together.

redmuffin.Blazor.StaticWeb/
├── .github/
│   ├── instructions/                        # AI coding guidelines
│   ├── workflows/                           # GitHub Actions
│   └── prompts/                             # AI prompts
├── src/
│   ├── redmuffin.Blazor.StaticWeb/          # Blazor WebAssembly (.NET 9)
│   │   ├── Features/
│   │   │   ├── Pages/
│   │   │   └── Shared/
│   │   ├── Core/
│   │   ├── wwwroot/
│   │   └── Properties/
│   ├── redmuffin.Blazor.StaticWeb.Api/      # Azure Functions (.NET 9)
│   │   ├── Functions/
│   │   └── Core/
│   ├── redmuffin.Blazor.StaticWeb.Common/   # Shared utilities
│   └── SwaLauncher/                         # SWA CLI launcher (.NET 9)
├── tests/
│   ├── redmuffin.Blazor.StaticWeb.Tests/
│   └── redmuffin.Blazor.StaticWeb.Api.Tests/
├── scripts/                                 # Build & deployment scripts
├── TestResults/                             # Test output

Technology Stack

Frontend Technologies

  • Blazor WebAssembly Framework for building interactive web UIs using C# instead of JavaScript. Enables client-side execution of .NET code in the browser.

  • C# 12/13 Modern, object-oriented programming language with latest features including primary constructors, collection expressions, and ref readonly parameters.

  • .NET 9 Cross-platform, high-performance framework for building modern applications with the latest features and performance improvements.

Backend Technologies

  • Azure Functions Serverless compute platform running on .NET 9 with HTTP triggers for RESTful API endpoints.

  • Raindrop.io API External API integration with OAuth 2.0 authentication for bookmark management functionality.

UI Framework & Styling

  • Zurb Foundation Responsive front-end framework providing robust grid system, UI components, and accessibility features.

  • SCSS (Sass) CSS preprocessor with variables, nesting, and modularization for modern styling capabilities.

    Important: All styling must be done through SCSS files located in wwwroot/scss/. CSS files in wwwroot/css/ are automatically generated and should never be edited directly. Component-specific styles should be created as SCSS partials (starting with underscore) and imported into app.scss for automatic compilation.

    SCSS Partials: All SCSS partial files must start with an underscore (_) and be imported into app.scss for automatic compilation. This ensures proper dependency management and build optimization.

  • Blazored.LocalStorage Blazor library for browser local storage access via JavaScript interop.

Content & Utilities

  • Markdig Fast, extensible Markdown processor for .NET with advanced extensions support.

  • Microsoft.AspNetCore.WebUtilities Utilities for web applications including query string parsing and URL manipulation.

Testing Framework

  • TUnit Modern, fast, and flexible .NET testing framework with parallel execution and comprehensive assertion library.

    Why TUnit Over xUnit?

    TUnit offers several advantages over xUnit, making it a compelling choice for modern .NET testing:

    1. Performance:

      • Source Generation: Utilizes source-generated tests to eliminate runtime reflection, significantly improving performance.
      • Faster Execution: Tests execute up to 10x faster in TUnit compared to xUnit due to better optimization.
    2. Parallel Execution:

      • Flexible Parallelism: Provides granular control over test parallelism with custom attributes like [NotInParallel] and ParallelLimiter.
      • Intelligent Scheduling: Offers enhanced control over test order and parallel execution.
    3. Modern Architecture:

      • Native AOT Support: Full support for Ahead-Of-Time (AOT) compilation and trimming, making it ideal for modern .NET applications.
    4. Advanced Test Control:

      • Test Dependencies: Supports dependency chains with [DependsOn], allowing structured integration testing without turning off parallelism.
      • Retry Logic: Built-in retry mechanisms for specific test scenarios.
    5. Better Setup and Teardown:

      • Enhanced Lifecycle Methods: Offers multiple setup and teardown methods with improved management and reduced issues.
    6. Compile-Time Safety:

      • Type Safe Assertions: Ensures more reliable tests with compile-time assertion checks.
    7. Extensibility:

      • Customization: Extensively customizable with support for diverse data sources, attributes, and test behavior.
      • IDE Integration: Seamless support with major IDEs, improving developer experience and test management.
    8. Rich Data Features:

      • Fluent Assertions: Utilizes fluent async assertions and provides detailed test metadata for expressive test writing.
  • LightMock.Generator Compile-time source-gen mocking library. Used as a fallback when hand-rolled fakes would be too large. For patterns and conventions, see .opencode/skills/redmuffin-standards/rm-guide-testing/SKILL.md.

Build and Analysis Tools

  • LibMan (Library Manager) Lightweight client-side library acquisition tool for managing third-party libraries like Foundation.

  • Roslynator Analyzers Provides refactorings, analyzers, and fixes for improving code quality and maintainability.

  • StyleCop Analyzers Enforces a set of style and consistency rules for C# code, ensuring adherence to coding standards.

  • Meziantou Analyzers Offers additional code quality checks focused on performance, security, and best practices.

  • VSThreading Analyzers Ensures threading best practices are followed, especially for asynchronous programming.

  • Coverlet Cross-platform code coverage library for .NET, enabling comprehensive test coverage analysis with multiple output formats.

  • ReportGenerator Powerful tool for generating readable reports from code coverage data, supporting HTML, XML, and various other formats with historical tracking.

Development Tools

  • GitHub Copilot AI-powered code completion tool with MCP server integration.

  • EditorConfig Consistent coding style definitions across different editors and IDEs.

  • Directory.Build.props Centralized MSBuild properties for consistent build configuration across all projects.


Development Tools

The project includes comprehensive development tools and integrations to enhance productivity and code quality.

Quality Gates Toolchain

The Quality Gates toolchain runs Uncle Bob Martin's full metric suite (CRAP, SCRAP, Architecture, Mutation) as a single dotnet tool. All four gates must pass before work is considered done. See tools/README.md for full documentation.

Guiding Principles & Authors

Our code quality standards are grounded in these authors. All code changes must improve the code per their principles. See rm-guide-cleanup and rm-gates-cleanup skills for the full rule set.

Author Key Contribution
Robert C. Martin (Uncle Bob) Clean Code, SOLID, TDD, metrics-driven development
Kent Beck TDD, Test Desiderata, Extreme Programming, YAGNI
Michael Feathers Working Effectively with Legacy Code, characterization tests
Dave Farley Modern Software Engineering, Continuous Delivery, fast feedback
Martin Fowler Refactoring, patterns, decompose conditional
Sandi Metz Practical OOD, duplication vs wrong abstraction, Rule of Three
John Ousterhout A Philosophy of Software Design, deep modules (use for structure)
Steve Freeman & Nat Pryce Growing OO Software, mock-object TDD
Kevlin Henney Simplicity before generality, use before reuse
Mary & Tom Poppendieck Lean Software Development, eliminate waste

Prerequisites System Requirements

  • Minimum RAM: 8GB (16GB recommended)
  • Disk Space: 10GB free space
  • OS: Windows 10/11, macOS 10.15+, or Linux (Ubuntu 20.04+)
  • CPU: x64 processor with SSE2 instruction set support

Container Infrastructure

Docker for MCP Servers

MCP servers run as Docker containers for isolation:

  • Brave Search — Web search with Brave API
  • Fetch — Web content fetching
  • Time — Date/time utilities
  • Sequential Thinking — AI reasoning assistance

Note: Context7 uses HTTP endpoint, not Docker.

File Search Tools

Everything Search (es.exe)

For optimal performance when searching files in large codebases, this project uses Everything Search with its command-line interface es.exe.

Why es.exe?

  • Lightning Fast: Leverages NTFS Master File Table for near-instantaneous results (milliseconds vs. seconds/minutes with grep)
  • Comprehensive: Searches file names, paths, and content across entire drives
  • Developer Optimized: Perfect for .NET projects with many files

Installation:

  1. Download from voidtools.com
  2. Install Everything (the GUI app)
  3. The CLI es.exe will be available in the installation directory (usually C:\Program Files\Everything\es.exe)

Usage Examples:

# Search for files containing "opencode"
es.exe opencode

# Search for C# files with "interface"
es.exe interface *.cs

# Find all .md files
es.exe *.md

Tips:

  • Results are returned instantly for indexed drives
  • Use for both local and external file searches
  • If es.exe fails to load, ensure Everything is running and indexing is complete

This tool significantly speeds up development workflows in this project.


Build and Deployment

Build Commands

Build the entire solution:

dotnet build

Build specific projects:

dotnet build src/redmuffin.Blazor.StaticWeb/
dotnet build src/redmuffin.Blazor.StaticWeb.Api/

Run tests:

dotnet test

Code Coverage

The project includes comprehensive code coverage analysis using Coverlet and ReportGenerator:

Generate Coverage Reports:

.\scripts\Generate-CoverageReport.ps1

View Coverage Reports:

# View unified coverage report (default)
.\scripts\View-CoverageReport.ps1

# View branded coverage report with history
.\scripts\View-CoverageReport.ps1 -ReportType Branded

# View basic HTML coverage report
.\scripts\View-CoverageReport.ps1 -ReportType Html

Coverage Features:

  • Multiple Output Formats: HTML, XML, JSON, and Cobertura formats
  • Unified Reports: Combined coverage from both Blazor and API test projects
  • Historical Tracking: Coverage trends over time with the branded report
  • Automated Exclusions: Generated files, vendor libraries, and test projects automatically excluded
  • Threshold Configuration: Configurable coverage thresholds for quality gates
  • Tool Integration: Automatic installation of required tools (ReportGenerator)

Coverage Configuration:

  • Coverage settings are configured in test project files (.csproj)
  • Global exclusions are defined in Directory.Build.props
  • Additional exclusions can be configured in .coverletrc
  • Reports are generated in the coverage/ directory

Deployment

The project is configured for deployment to Azure Static Web Apps:

  1. Create an Azure Static Web App resource
  2. Link the GitHub repository to the Azure resource
  3. Configure build settings:
    • App location: src/redmuffin.Blazor.StaticWeb
    • API location: src/redmuffin.Blazor.StaticWeb.Api
    • Output location: wwwroot
  4. Push changes to the master branch to trigger automatic deployment

License

This project is licensed under the Unlicense.


Acknowledgements


Azure Functions Integration

The API project leverages Azure Functions with .NET 9 Isolated Worker to provide serverless compute capabilities. This integration enables scalable and event-driven backend functionality for the Blazor WebAssembly application.

Key Features

  • Azure Functions Worker SDK (.NET 9): Isolated worker process for better performance and control
  • HTTP Triggers: RESTful API endpoints with strong typing and dependency injection
  • OAuth Integration: Secure token exchange for external API authentication
  • Dependency Injection: Full DI container support with IHttpClientFactory, ILogger, and custom services

For more details, refer to the Azure Functions Documentation.


MCP Server Integration

The development environment includes several Model Context Protocol (MCP) servers that enhance AI-powered code assistance capabilities. These servers enable AI assistants (like GitHub Copilot) to access external resources, search capabilities, and up-to-date documentation.

Available MCP Servers

Configured Servers

  • Fetch MCP Server: Retrieves web content from URLs, automatically converting HTML to markdown for easier AI consumption
  • Time MCP Server: Provides current time and date information
  • Context7 MCP Server: Fetches up-to-date documentation for libraries and frameworks via HTTP endpoint
  • Brave Search MCP Server: Provides real-time web search and local business search capabilities (requires API key)
  • Sequential Thinking MCP Server: Enables structured, multi-step reasoning and problem-solving through dynamic thought processes
  • Chrome DevTools MCP Server: Provides browser automation, performance analysis, network inspection, and debugging capabilities (requires Node.js and Chrome)
  • code-review-graph: Local knowledge graph for token-efficient code reviews. Builds structural map of codebase with Tree-sitter, provides blast radius analysis, and 28 MCP tools for code understanding (Python 3.10+ required)

Context-Mode (Token Optimization)

The project uses context-mode for context window optimization when running OpenCode. This tool executes commands in a sandboxed subprocess, keeping raw output out of the context window.

Already Configured: context-mode is pre-configured in the project's opencode.json plugin list. No additional installation required.

Usage:

# Run commands in sandbox (output stays in subprocess)
ctx_execute --command "dotnet build"

# Analyze files without loading into context
ctx_execute_file --path "src/Program.cs" --language "csharp" --code "console.log(' analyzing...')"

Benefits:

  • Command output stays in sandbox, only parsed results enter context
  • 5x+ token reduction on large outputs
  • Works with any CLI command (git, dotnet, npm, etc.)
  • File analysis without full content in context

Key Benefits

  • Real-Time Information: Access current documentation, search results, and web content
  • Enhanced Problem Solving: Structured reasoning and comprehensive resource access
  • Development Efficiency: Reduce context switching by accessing external resources directly through AI
  • Up-to-Date Content: Documentation that's more recent than AI training data cutoffs
  • Privacy-Focused: Brave Search integration respects user privacy

Configuration

MCP servers are pre-configured in the project's .mcp.json file and integrate seamlessly with GitHub Copilot when Docker Desktop is available. Some servers may require API keys (like Brave Search) for full functionality.

Note: The Chrome DevTools MCP server is configured in the project's opencode.json. The chrome-devtools-mcp package is installed globally via npm (npm install -g chrome-devtools-mcp). It requires:

The --isolated flag is used to create a temporary user data directory (incognito-like behavior) that is automatically cleaned up after each session.

Usage Examples

Once configured, you can ask your AI assistant to:

  • "Fetch the latest Blazor WebAssembly documentation"
  • "Search for recent .NET 9 performance improvements"
  • "Get current Azure Functions examples using Context7"
  • "Help me think through this architecture problem step by step"

Security Considerations

  • Fetch MCP Server can access local/internal IP addresses - ensure proper network security policies in corporate environments
  • All servers respect standard web protocols (robots.txt, user-agent settings)
  • Configuration is managed through your AI assistant's settings

Security Policy

CRITICAL: This project follows a zero-tolerance policy for secrets in files. The repository MUST NEVER contain a single secret.

Zero Secrets Policy

The repository MUST NEVER contain any secrets, including:

  • API keys or tokens
  • Passwords or credentials
  • Database connection strings with credentials
  • Private keys (SSH, GPG, etc.)
  • Session tokens or refresh tokens
  • Any sensitive configuration values

Even in private repositories, secrets must never be committed. Automated scanners will find and exploit them within hours.

Allowed Secret Management Methods

Method Use Case Syntax
Environment Variables MCP configs, scripts {env:VAR_NAME} or ${env:VAR}
GitHub Repository Secrets CI/CD pipelines ${{ secrets.SECRET_NAME }}
Azure Key Vault Production deployments az keyvault secret show
User Secrets Local .NET development dotnet user-secrets

MCP Configuration Rules

All MCP configurations must read secrets from environment variables:

// CORRECT - reads from environment
"env": { "API_KEY": "${env:API_KEY}" }

// WRONG - hardcoded value (NEVER DO THIS)
"env": { "API_KEY": "actual_secret_here" }

GitHub Actions Secrets

For CI/CD, use GitHub Repository Secrets:

# Correct - uses repository secrets
env:
  Values__RainDropClientId: ${{ secrets.RAINDROP_CLIENT_ID }}

# Wrong - hardcoded value (NEVER DO THIS)
env:
  Values__RainDropClientId: "actual_client_id"

What To Do If You Expose a Secret

  1. IMMEDIATELY rotate the exposed secret (generate new key/token)
  2. Alert the team about the exposure
  3. Remove from git history if committed:
    git filter-branch --force --index-filter \
      'git rm --cached --ignore-unmatch path/to/file' \
      --prune-empty --tag-name-filter cat -- --all
    git push origin --force --all
  4. Update all dependent systems with the new secret

Security Checklist

Before committing, verify:

  • No API keys, tokens, or secrets in changed files
  • No password, secret, token, key, credential, auth with visible values
  • Config files use ${env:VAR} or ${input:VAR} syntax only
  • .gitignore includes sensitive file patterns

Local Development: Visual Studio Multi-Project Startup

The project is configured for seamless development using Visual Studio's multi-project startup feature, which automatically launches all required components.

Quick Start

  1. Start the development environment:

    • Open redmuffin.Blazor.StaticWeb.sln in Visual Studio 2026 (Community)
    • Use the "Start both" profile (or similar multi-project startup configuration)
    • Visual Studio will automatically start:
      • Blazor WebAssembly frontend
      • Azure Functions API backend
      • SwaLauncher (which starts the Azure Static Web Apps emulator)
  2. Access the application:

    • Open http://localhost:4280 in your browser
    • All API calls will be routed through the same port as the web app
    • OAuth redirects and authentication flows will work correctly

Development Features

  • Hot Reload: Changes to Blazor components and API functions are automatically reflected
  • Unified Routing: Single port for both frontend and API eliminates CORS issues
  • Production Simulation: Mimics the exact Azure Static Web Apps runtime environment
  • Debugging Support: Full debugging capabilities for both frontend and backend code

Simplified Development Workflow

For streamlined development and testing, the project now supports a simplified workflow that focuses on frontend development and design validation without requiring the full Azure Functions backend.

Quick Development Setup

  1. Start only the main web project:

    • In Visual Studio, set redmuffin.Blazor.StaticWeb as the startup project
    • Press F5 or click "Start"
    • The application will launch on http://localhost:5233
  2. Automatic mock data integration:

    • The application automatically detects when Azure Functions are unavailable
    • Mock data services seamlessly replace API calls
    • All UI components and user interactions function normally

Benefits for Development Teams

  • Faster Startup: Eliminates the overhead of starting multiple projects and services
  • Design-Focused Development: Perfect for UI/UX work, component development, and frontend testing
  • Simplified Debugging: Focus on frontend logic without backend complexity
  • Developer Friendly: Reduces cognitive load and setup complexity for team members
  • Rapid Prototyping: Quickly test design changes and user interactions

When to Use Each Approach

Development Task Recommended Approach
UI/UX Design Simplified (localhost:5233)
Component Development Simplified (localhost:5233)
Frontend Logic Testing Simplified (localhost:5233)
API Integration Testing Full Stack ("Start both" profile)
OAuth Flow Testing Full Stack ("Start both" profile)
End-to-End Testing Full Stack ("Start both" profile)

Technical Implementation

The simplified workflow leverages:

  • Conditional service registration based on environment detection
  • Mock data providers that simulate realistic API responses
  • Seamless fallback mechanisms for external service dependencies
  • Consistent data models ensuring compatibility between mock and real data

Transitioning Between Workflows

Developers can easily switch between approaches:

  • To Simplified: Stop debugging, set main project as startup, restart
  • To Full Stack: Use "Start both" profile or multi-project startup configuration
  • No code changes required - the application automatically adapts

Notes

  • The CLI simulates the Azure Static Web Apps environment, making it ideal for development and testing
  • The "Start both" profile in Visual Studio simplifies launching both projects together
  • OAuth flows and API integration work seamlessly in this local development setup
  • The simplified workflow is particularly beneficial for design-focused tasks and rapid development

Supply Chain Attack Protection

This project implements defense-in-depth protections against package manager and dependency chain attacks. All protections were added in April 2025.

What Are Supply Chain Attacks?

Attackers compromise trusted packages to infiltrate downstream applications. Common vectors include:

  • Typosquatting (malicious packages with similar names)
  • Dependency confusion (internal packages masquerading as public)
  • Malicious maintainers publishing compromised updates
  • Compromised package maintainer accounts

Protections Implemented

Layer Protection How It Works
npm 7-day release age filter Blocks packages published within 7 days, preventing fresh supply chain attacks (e.g., Axios incident)
npm Ignore scripts Blocks postinstall scripts that could execute malicious code during install
npm Exact versions save-exact=true prevents unexpected version changes from ^ or ~ ranges
npm Strict peer deps Prevents malformed peer dependency resolution attacks
NuGet Signature validation signatureValidationMode=accept validates signed packages while allowing unsigned popular ones

Configuration Files

.npmrc                    # npm supply chain settings
nuget.config              # NuGet supply chain settings
Directory.Packages.props  # Centralized package versioning

npm Configuration (.npmrc)

min-release-age=7         # Block recent packages
ignore-scripts=true        # No postinstall code
save-exact=true           # Exact versions only
strict-peer-deps=true      # Strict peer resolution
engine-strict=true        # Enforce Node.js version

NuGet Configuration (nuget.config)

<config>
  <add key="signatureValidationMode" value="accept" />
</config>

Why These Protections Matter

  • 7-day filter: The Axios compromise used a same-day malicious release; this blocks that vector entirely
  • Signature validation: NuGet validates package signatures to detect tampering after publication

Maintenance Notes

  • The accept mode allows unsigned packages while validating signed ones
  • npm settings are repository-scoped via .npmrc — applies to all projects in the repo