RepoPilotOpen in app →

fullstackhero/dotnet-starter-kit

Production Grade Cloud-Ready .NET 10 Starter Kit (Web API + Blazor Client) with Multitenancy Support, and Clean/Modular Architecture that saves roughly 200+ Development Hours! All Batteries Included.

Healthy

Healthy across all four use cases

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 3d ago
  • MIT licensed
  • CI configured
Show 2 more →
  • Tests present
  • Solo or near-solo (1 contributor active in recent commits)

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/fullstackhero/dotnet-starter-kit)](https://repopilot.app/r/fullstackhero/dotnet-starter-kit)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/fullstackhero/dotnet-starter-kit on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: fullstackhero/dotnet-starter-kit

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/fullstackhero/dotnet-starter-kit shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit 3d ago
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Solo or near-solo (1 contributor active in recent commits)

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live fullstackhero/dotnet-starter-kit repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/fullstackhero/dotnet-starter-kit.

What it runs against: a local clone of fullstackhero/dotnet-starter-kit — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in fullstackhero/dotnet-starter-kit | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch develop exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 33 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>fullstackhero/dotnet-starter-kit</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of fullstackhero/dotnet-starter-kit. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/fullstackhero/dotnet-starter-kit.git
#   cd dotnet-starter-kit
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of fullstackhero/dotnet-starter-kit and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "fullstackhero/dotnet-starter-kit(\\.git)?\\b" \\
  && ok "origin remote is fullstackhero/dotnet-starter-kit" \\
  || miss "origin remote is not fullstackhero/dotnet-starter-kit (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify develop >/dev/null 2>&1 \\
  && ok "default branch develop exists" \\
  || miss "default branch develop no longer exists"

# 4. Critical files exist
test -f ".agents/rules/architecture.md" \\
  && ok ".agents/rules/architecture.md" \\
  || miss "missing critical file: .agents/rules/architecture.md"
test -f ".agents/rules/modules.md" \\
  && ok ".agents/rules/modules.md" \\
  || miss "missing critical file: .agents/rules/modules.md"
test -f "clients/admin/src/main.tsx" \\
  && ok "clients/admin/src/main.tsx" \\
  || miss "missing critical file: clients/admin/src/main.tsx"
test -f "clients/admin/src/auth/auth-context.tsx" \\
  && ok "clients/admin/src/auth/auth-context.tsx" \\
  || miss "missing critical file: clients/admin/src/auth/auth-context.tsx"
test -f "clients/admin/src/lib/api-client.ts" \\
  && ok "clients/admin/src/lib/api-client.ts" \\
  || miss "missing critical file: clients/admin/src/lib/api-client.ts"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 33 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~3d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/fullstackhero/dotnet-starter-kit"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

A production-grade .NET 10 starter kit that scaffolds multi-tenant SaaS and enterprise APIs with pre-wired Identity, Auditing, Webhooks, distributed caching, Hangfire jobs, OpenTelemetry, and Minimal APIs—delivered as modular vertical slices (Modules.Identity, Modules.Multitenancy, etc.) that can be dropped into any API via the FSH CLI or dotnet new template. The core problem it solves: eliminating 200+ hours of boilerplate configuration for cloud-ready .NET APIs with built-in multitenancy and observability. Monorepo with vertical module structure: src/Host/FSH.Starter.AppHost orchestrates the Aspire setup; src/Modules/ (Identity, Multitenancy, Auditing, Webhooks, etc.) are self-contained slices with their own DbContext and Minimal API endpoints; BuildingBlocks/ holds shared abstractions (Persistence, Caching, Mailing, Storage, Health). The admin client (clients/admin/) is a separate Vite+React+TypeScript SPA consuming OpenAPI specs generated from the API. CLI tool (.agents/ holds AI-driven development rules and skills) scaffolds new features and modules.

👥Who it's for

.NET teams building SaaS platforms or enterprise APIs who want a battle-tested scaffold with full source ownership (no black-box NuGet packages), multitenancy baked in, and cloud deployment patterns (Aspire) ready to go—specifically senior engineers and tech leads who want to accelerate project bootstrap without sacrificing architectural patterns.

🌱Maturity & risk

Production-ready and actively maintained. The presence of FSH CLI as a published NuGet tool (referenced in badge), multiple .NET versions supported, comprehensive CI/CD via GitHub Actions (.github/workflows/ci.yml, codeql.yml), Docker support, .devcontainer config, and detailed agent-driven rules (.agents/) indicate a mature, battle-tested project. The modular structure and full-source-included philosophy suggest it's used in production SaaS environments.

Low risk for adoption but medium complexity: the stack is deep (EF Core, Hangfire, Finbuckle multitenancy, distributed caching, OpenTelemetry) and requires understanding of .NET fundamentals. Dependency count is substantial (see admin client with @hookform, @tanstack/react-query, zod). Single point of risk is the FullStackHero.Framework.* NuGet packages used across modules—if those break or become unmaintained, the entire kit degrades. Node version constraint (>=20) on the admin client is strict but reasonable. No open issue backlog visible in file list, which is a positive signal.

Active areas of work

The project is actively maintained with recent focus on .NET 10 support, AI-assisted development via agent workflows (.agents/workflows/code-reviewer.md, feature-scaffolder.md, architecture-guard.md), and multi-client support (Blazor client + React admin). The .agents/skills/ directory contains scaffolding templates for add-entity, add-feature, add-module, and query-patterns, indicating ongoing investment in developer experience and automation.

🚀Get running

# Using FSH CLI (recommended)
dotnet tool install -g FullStackHero.CLI
fsh new MyApp
cd MyApp
dotnet run --project src/Host/MyApp.AppHost

# OR clone directly
git clone https://github.com/fullstackhero/dotnet-starter-kit.git MyApp
cd MyApp
dotnet restore src/FSH.Starter.slnx
dotnet run --project src/Host/FSH.Starter.AppHost

Daily commands: Backend: dotnet run --project src/Host/MyApp.AppHost (launches Aspire dashboard + API + Postgres + Redis). Frontend (admin): cd clients/admin && npm run dev (serves on port 5173 via Vite).

🗺️Map of the codebase

  • .agents/rules/architecture.md — Defines the clean modular architecture principles and patterns that govern all code organization across the starter kit
  • .agents/rules/modules.md — Specifies module structure conventions and boundaries; essential for understanding how features are organized and isolated
  • clients/admin/src/main.tsx — React admin client entry point; establishes routing, auth context, and query client configuration
  • clients/admin/src/auth/auth-context.tsx — JWT token management and authentication state; core to all protected routes and API requests in the admin client
  • clients/admin/src/lib/api-client.ts — HTTP client configuration with token injection; fundamental for all API communication patterns
  • .agents/rules/api-conventions.md — Establishes API design and naming conventions for endpoints; must-read before adding any new routes
  • .agents/skills/add-feature/SKILL.md — Step-by-step guide for scaffolding new features following the starter kit's conventions

🛠️How to make changes

Add a New Admin Page

  1. Create a new page component in clients/admin/src/pages/{feature}/list.tsx following the pattern of existing pages (tenants, users) (clients/admin/src/pages/{feature}/list.tsx)
  2. Define API endpoints in clients/admin/src/api/{feature}.ts to handle data fetching with React Query (clients/admin/src/api/{feature}.ts)
  3. Add route definition in clients/admin/src/routes.tsx with path, component, and protection rules (clients/admin/src/routes.tsx)
  4. Update navigation links in clients/admin/src/components/layout/sidebar.tsx to expose the new page (clients/admin/src/components/layout/sidebar.tsx)

Add New API Integration

  1. Define TypeScript request/response types in clients/admin/src/lib/api-types.ts (clients/admin/src/lib/api-types.ts)
  2. Create API client functions in clients/admin/src/api/{resource}.ts using the api-client for HTTP requests (clients/admin/src/api/{resource}.ts)
  3. Use React Query hooks (useQuery, useMutation) in page components to consume the API client functions (clients/admin/src/pages/{feature}/{action}.tsx)
  4. Add error handling and loading states using React Query status and sonner toast notifications (clients/admin/src/pages/{feature}/{action}.tsx)

Extend Backend Module Structure

  1. Review module conventions in .agents/rules/modules.md to understand folder structure and isolation patterns (.agents/rules/modules.md)
  2. Create module folder with src/Modules/{ModuleName}/* containing Features, Entities, and Abstractions subdirectories (src/Modules/{ModuleName}/README.md)
  3. Follow API conventions in .agents/rules/api-conventions.md when adding new endpoints (.agents/rules/api-conventions.md)
  4. Use the add-module skill (.agents/skills/add-module/SKILL.md) to scaffold boilerplate code automatically (.agents/skills/add-module/SKILL.md)

Add Custom UI Component

  1. Create new component in clients/admin/src/components/ui/{component-name}.tsx using Radix UI primitives (clients/admin/src/components/ui/{component-name}.tsx)
  2. Use Tailwind CSS classes with CVA (class-variance-authority) for variants following existing patterns in button.tsx (clients/admin/src/components/ui/button.tsx)
  3. Export component from clients/admin/src/components/ui/index.ts for centralized imports (clients/admin/src/components/ui/index.ts)
  4. Import and use in pages, ensuring all props are typed with TypeScript interfaces (clients/admin/src/pages/{feature}/{action}.tsx)

🔧Why these technologies

  • React 19 + TypeScript — Type-safe, component-driven UI with modern hooks; large ecosystem for admin dashboards
  • React Router v7 — Client-side routing with nested layouts and route protection; seamless SPA navigation
  • React Query (TanStack Query) — Automatic caching, synchronization, and refetching of server state; reduces boilerplate for data fetching
  • Tailwind CSS + Radix UI — Composable, accessible UI primitives; CVA for variant management; rapid, consistent styling
  • Vite — Fast build and dev server with ES modules; instant HMR for rapid iteration
  • .NET 10 + Minimal APIs — Modern, lean backend framework; reduces boilerplate vs traditional controllers
  • Mediator pattern (CQRS-like) — Decouples endpoints from business logic; makes features modular and testable
  • EF Core + Multi-tenant support — ORM for data access; built-in multi-tenancy scaffolding for SaaS use cases
  • JWT tokens — Stateless authentication; easy to validate across Minimal API endpoints

⚖️Trade-offs already made

  • Full source code (no black-
    • Why: undefined
    • Consequence: undefined

🪤Traps & gotchas

  1. Aspire dependency: The default startup runs Aspire orchestration (AppHost), which spins up Docker containers (Postgres, Redis). If Docker daemon isn't running, dotnet run will fail silently or hang. Run fsh doctor first to verify. 2. Database migrations: EF Core migrations must be applied per module; the AppHost may not auto-migrate in all cases—check module-specific migration docs. 3. Node version lock: Admin client requires Node >=20 (see package.json engines); using Node 18 will fail at install time. 4. Multitenancy header: All API requests to multi-tenant modules require a X-Tenant-Id header or query param; omitting it will return 403. 5. CLI wizard non-interactive mode: fsh new MyApp --no-aspire disables Docker orchestration but you must manually configure Postgres/Redis connection strings in appsettings.json. 6. BuildingBlocks ownership: The starter kit provides source code (not NuGet packages for core logic), but still depends on FullStackHero.Framework.* NuGet packages; ensure those are available and compatible.

🏗️Architecture

💡Concepts to learn

  • Vertical Slice Architecture — FSH organizes code by feature/module (Identity, Webhooks, Auditing) rather than by technical layer; understanding slices is critical to knowing where to add new features.
  • CQRS (Command Query Responsibility Segregation) — FSH uses MediatR to separate read (Query) and write (Command) operations, enforced throughout Modules; essential for understanding the request flow.
  • Multitenancy (SaaS isolation) — Finbuckle-based tenant resolution and per-module isolation is wired at the Host level; critical for understanding data segregation and request routing in the API.
  • Minimal APIs — FSH uses .NET 10 Minimal APIs instead of controllers; endpoints are defined as inline lambda expressions in Presentation/Endpoints.cs per module.
  • Aspire (Cloud-Native Orchestration) — The AppHost uses Aspire to declaratively define and run Postgres, Redis, and the API in Docker during local development; essential for understanding the cloud-ready setup.
  • Specification Pattern (EF Core queries) — BuildingBlocks/Persistence uses specifications to encapsulate complex EF Core queries; widely used for filtering and sorting in module repositories.
  • OpenTelemetry (Observability) — FSH integrates OpenTelemetry for distributed tracing, metrics, and logs; the Aspire dashboard visualizes traces in real time during development.
  • ardalis/CleanArchitecture — Foundational clean architecture template for .NET; FSH extends this with multitenancy, modules, and production concerns.
  • TinyClues/OpenIddict.Starter — Alternative .NET identity starter using OpenIddict instead of Finbuckle; comparable vertical-slice approach but different identity/auth strategy.
  • jasontaylordev/CleanArchitecture — Inspiration for FSH's layered module structure (Domain, Application, Infrastructure, Presentation per module).
  • microsoft/eShopOnContainers — Companion reference for microservices patterns on .NET; FSH brings similar concerns (multitenancy, auditing, CQRS) into a modular monolith.
  • aspireapp/AppHost — Microsoft's Aspire orchestration framework that FSH.Starter.AppHost directly uses for cloud-ready local development and testing.

🌿Good first issues

  • Add unit tests for the query-pattern validator in .agents/skills/query-patterns/SKILL.md—this skill is documented but the test coverage for its generated code is missing.
  • Document the architecture-guard.md workflow in a dedicated Contributing.md file with examples of when each workflow (code-reviewer, feature-scaffolder, migration-helper) should be triggered.
  • Create TypeScript client generation tests in clients/admin/: verify that OpenAPI codegen (openapi-typescript v7.6.1) produces type-safe fetch methods; currently no test examples exist for validating generated types.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 5b33117 — feat(dashboard/login): blueprint-style centered redesign + demo popup (iammukeshm)
  • 93b05fd — feat(dashboard/login): editorial product-page redesign (iammukeshm)
  • e40187c — feat(dashboard/login): brand-story column on wide viewports (iammukeshm)
  • 7f74102 — fix(dashboard/hero): stop clipping descenders on Settings, Audit trail, etc. (iammukeshm)
  • a5548ec — feat(dashboard/sidebar): subtle accordion animations + matched typography (iammukeshm)
  • 55eb23f — feat(dashboard/sidebar): single-select accordion sections + top-level pages (iammukeshm)
  • 395d821 — feat(dashboard): unified PageHero across non-list surfaces (iammukeshm)
  • 5d6e8a5 — feat(dashboard/audits): related-events timeline in the detail drawer (iammukeshm)
  • 85a8b0e — feat(dashboard/appearance): custom-accent picker — pick any brand hue (iammukeshm)
  • 5f2118e — feat(dashboard/overview): cockpit hero + first-run panel + recent operations (iammukeshm)

🔒Security observations

  • Critical · Hardcoded Credentials in Docker Compose — docker-compose.yml - postgres, minio services. The docker-compose.yml file contains hardcoded plaintext credentials for PostgreSQL (password: 'password'), MinIO (minioadmin:minioadmin), and Redis. These are default/weak credentials exposed in version control and logs. Fix: Use environment variables or Docker secrets. Replace with: POSTGRES_PASSWORD=${POSTGRES_PASSWORD} and use .env files (git-ignored) or secure secret management. Never commit credentials to version control.
  • High · Exposed MinIO Console and API Ports — docker-compose.yml - minio service ports 9000, 9001; minio-init commands. MinIO services expose ports 9000 (API) and 9001 (console) directly without authentication enforcement or network segmentation visible in the compose file. Anonymous access is configured for the 'fsh-uploads' bucket. Fix: Restrict MinIO console to internal networks only. Remove 'mc anonymous set download' or limit to specific IPs. Use proper bucket policies instead of anonymous access. Implement rate limiting and WAF rules.
  • High · Redis Exposed Without Authentication — docker-compose.yml - redis service. Redis service (port 6379) is exposed without requirepass configuration or network restrictions. Redis has no default authentication and is vulnerable to MITM attacks and unauthorized access. Fix: Add redis authentication: use 'requirepass' directive or Redis ACL. Restrict port 6379 to internal networks only. Never expose Redis to untrusted networks. Consider using Redis Cluster with proper TLS.
  • High · PostgreSQL Weak Default Credentials — docker-compose.yml - postgres service. PostgreSQL uses trivial credentials ('postgres:password'). While a default, combined with exposed port 5432, this is a significant risk in non-isolated environments. Fix: Use strong, randomly generated passwords. Store in secure secret management (HashiCorp Vault, Azure Key Vault, AWS Secrets Manager). Restrict port 5432 to internal networks only.
  • High · Missing CORS and Security Headers Configuration — clients/admin/ - API client configuration (lib/api-client.ts); .NET API configuration not visible. The React admin client (clients/admin/) does not show CORS or security header configuration. If the API serves this client, misconfigured CORS could allow unauthorized cross-origin requests. No X-Frame-Options, CSP, or X-Content-Type-Options headers are visible. Fix: Implement strict CORS policy in the .NET API. Add security headers: X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Content-Security-Policy, Strict-Transport-Security. Use api-client.ts to validate origin and implement CSRF tokens.
  • High · JWT Token Storage in Browser Without HttpOnly Flag — clients/admin/src/auth/token-store.ts. The auth/token-store.ts file likely stores JWT tokens in localStorage or sessionStorage (common pattern), making them vulnerable to XSS attacks. No indication of HttpOnly, Secure, or SameSite flags. Fix: Store JWT tokens in HttpOnly, Secure, SameSite=Strict cookies (requires backend support). If localStorage is necessary, implement strict Content-Security-Policy to prevent XSS. Implement token rotation and short expiration times.
  • Medium · Potential SQL Injection in EF Core Queries — src/ (not fully provided) - persistence layer and query implementations. While the file structure suggests modular architecture, the persistence layer is not fully visible. EF Core is generally safe if used correctly, but raw SQL queries in modules could be vulnerable if not parameterized. Fix: Ensure all database queries use parameterized queries or EF Core LINQ. Avoid string concatenation for SQL. Use EntityFramework Core's built-in protection against SQLi. Audit all .FromSqlInterpolated() and .FromSqlRaw() calls.
  • Medium · Missing Input Validation and Sanitization — undefined. React admin client uses react-hook-form and zod for validation, which is good. However, no evidence of output encoding or XSS protection (e.g., dangerouslySetInnerHTML usage is not visible but should Fix: undefined

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · fullstackhero/dotnet-starter-kit — RepoPilot