FullStackHero .NET Starter Kit

repository·main·Indexed 27 days ago

https://github.com/fullstackhero/dotnet-starter-kit

A production-ready starter kit for multi-tenant SaaS applications featuring a .NET 10 modular monolith backend with vertical slices and two React 19 front-ends (Admin and Dashboard). Includes pre-configured identity, billing, and observability, with support for .NET Aspire and Docker Compose deployment using Postgres, Redis, and MinIO.

Tokens
28.9K
Snippets
67
Records
190
Agent score
87%

What's inside fullstackhero-dotnet-starter-kit

  1. Automated Tenant Expiry Notifications

    main

    A recurring Hangfire job (TenantExpiryScanJob) monitors tenant validity and triggers notifications via the Notifications module.

    Triggered Events:

    • TenantNearingExpiryIntegrationEvent: Triggered within a configurable number of days before ValidUpto.
    • TenantEnteredGraceIntegrationEvent: Triggered once ValidUpto is passed but within the grace window.
    • TenantExpiredIntegrationEvent: Triggered once the grace window has closed.

    These events drive automated emails to tenants to encourage renewal.

  2. Design Unification: Admin to Dashboard Reskin

    main

    The clients/admin application is undergoing a visual unification to match the clients/dashboard design system. This process involves replacing the 'Console' aesthetic (editorial-terminal, chartreuse accents, grid textures) with the 'Dashboard' aesthetic (warm brand/saffron accents, editorial card system, and space-efficient grid layouts).

    Key Changes:

    • Tokens: Adoption of the dashboard's color palette, surfaces, radii, and typography.
    • Components: Migration to the dashboard's ui/* component set (including avatar, dropdown-menu, and switch).
    • Layout: Replacement of the 18rem FormShell/FormSection rail with the dashboard's SettingsSection and Field grid-based layout.
    • File Uploads: Transitioning to the dashboard's presigned ImageInput for avatar and image field uploads to resolve data-URL limitations.
  3. Implement tenant subscription management in the Dashboard

    main

    The Dashboard client (clients/dashboard) manages tenant subscriptions through the following features:

    • Subscription Page: Displays the current plan, validity, expiry badges, usage limits/overages, and recent invoices.
    • Expiry/Grace Banners: A global banner in the AppShell driven by getMyStatus() (with a staleTime of ~5m) that appears when a tenant is InGrace or within the lead days before expiry.
    • Invoice Management: Provides an invoice detail page showing line items and a link to download the invoice PDF via invoicePdfUrl(id).

    API updates required in api/billing.ts:

    • Update SubscriptionStatus to Active|Suspended|Cancelled.
    • Type invoice line items.
    • Add getMyStatus().
    • Add getMyInvoice(id).
    • Add invoicePdfUrl(id).
  4. Configure External Proxy and CORS

    main

    The Docker Compose setup does not include a reverse proxy or TLS terminator. You must route TLS subdomains to the host ports.

    Crucial: The URLs you serve via your proxy must match the FSH_API_URL, FSH_ADMIN_URL, and FSH_DASHBOARD_URL defined in your .env file. If they do not match, the frontends will fail to load the configuration and CORS errors will occur.

    | Public URL (your domain) | Host port |
    |---|---|
    | `api.example.com` | `8080` |
    | `admin.example.com` | `8081` |
    | `app.example.com` | `8082` |
  5. Deploy via Docker Compose

    main

    For single-host production deployment, use the provided Docker Compose configuration.

    1. Navigate to the deployment directory: cd deploy/docker
    2. Copy the environment template (Note: fsh new pre-generates this with strong secrets): cp .env.example .env
    3. Start the containers: docker compose up -d --build
    cd deploy/docker
    cp .env.example .env
    docker compose up -d --build
  6. Implement WhatsApp Wallet and Top-up Request (Phase 1)

    main

    This implementation plan outlines the creation of a prepaid money wallet system within the Billing module. The goal is to allow tenants (clinics) to request wallet top-ups via the dashboard, which operators can then approve/reject via the admin app. Once an invoice for the top-up is marked as paid, the wallet is automatically credited.

    Key Components

    • Entities: Wallet, WalletTransaction (ledger), and TopupRequest.
    • Workflow: Dashboard request $\rightarrow$ Admin review $\rightarrow$ Invoice generation $\rightarrow$ Payment collection $\rightarrow$ Automatic wallet credit.
    • Scope: This phase covers the funding (crediting) side only. The metering (debiting per message) is out of scope for Phase 1.
  7. Admin Wallet Management API and UI Implementation

    main

    Administrators can review, approve, or reject top-up requests via the Admin dashboard.

    API Endpoints

    • GET /api/v1/billing/wallet/topup-requests: Lists all top-up requests. Supports filtering by tenantId, status, pageNumber, and pageSize.
    • POST /api/v1/billing/wallet/topup-requests/{id}/approve: Approves a request. Returns a string (typically the new invoiceId).
    • POST /api/v1/billing/wallet/topup-requests/{id}/reject: Rejects a request. Accepts an optional reason string.

    UI Implementation Details

    • Top-ups List: A table showing tenant ID, amount, currency, status, and creation date.
    • Actions:
      • Approve: Triggers approveTopupRequest. On success, invalidates ["billing","topup-requests"] and provides a link to the generated invoice.
      • Reject: Triggers rejectTopupRequest with a reason via an AlertDialog.
    • Permissions: Actions are gated by BillingPermissions.Manage.

    Data Types

    • TopupRequestStatus: "Pending" | "Invoiced" | "Completed" | "Rejected" | "Cancelled" | (string & {})
  8. Quick start with .NET Aspire (Recommended)

    main

    To launch the entire stack—including Postgres, Redis, MinIO, the API, and both React applications—use the .NET Aspire orchestrator. This automatically handles database migrations and starts all services.

    Available Surfaces:

    • Aspire dashboard: https://localhost:15888
    • API + Scalar docs: https://localhost:7030/scalar
    • Admin console: http://localhost:5173
    • Tenant dashboard: http://localhost:5174
    dotnet run --project src/Host/FSH.Starter.AppHost
  9. Run FullStackHero — Admin via .NET Aspire (Recommended)

    main

    Use this option to launch the entire stack (Postgres, Redis, MinIO, API, and the Admin Vite app) simultaneously. Aspire handles service discovery and automatically wires the VITE_API_BASE_URL environment variable.

    1. Install dependencies for the admin client: npm install --prefix clients/admin
    2. Run the AppHost project: dotnet run --project src/Host/FSH.Starter.AppHost

    The admin app will be available at http://localhost:5173 via the Aspire dashboard.

    npm install --prefix clients/admin
    dotnet run --project src/Host/FSH.Starter.AppHost
  10. Renew a tenant subscription

    main

    Use the RenewTenant functionality to extend a tenant's validity or change their billing plan. This replaces the legacy UpgradeTenant workflow.

    Endpoint: POST api/v1/tenants/{id}/renew Permission Required: MultitenancyPermissions.Tenants.UpgradeSubscription

    Command Structure:

    • TenantId: The ID of the tenant to renew.
    • PlanKey: (Optional) The new plan slug. If null, the current plan is renewed.

    Renewal Logic:

    • The new validity period is calculated by stacking the remaining time onto the existing period (if ValidUpto > now) and adding the new term months.
    • If the PlanKey differs from the current plan, the subscription is swapped (old becomes Cancelled, new becomes Active).
    • A TenantRenewedIntegrationEvent is published.
  11. Admin Design Unification: Implementation Phases

    main

    The design unification is executed in a bottom-up, multi-phase approach to ensure stability. Each phase must pass npm run build (tsc + vite) and eslint before proceeding.

    1. Phase 1: Tokens & Global Styles - Port globals.css from dashboard to admin. Remove // CONSOLE chrome and grid textures.
    2. Phase 2: UI Primitives & Form Layout - Port ui/* components. Replace FormShell/FormSection/FormActions with SettingsSection and Field. Port list/ primitives and EntityPageHeader.
    3. Phase 3: App Shell - Rebuild components/layout/* (sidebar, topbar, mobile-nav) using the dashboard pattern. Retire the // CONSOLE masthead.
    4. Phase 4: Page Migration - Apply the new vocabulary to pages in increasing order of complexity: settings/ $\rightarrow$ roles/ & users/ $\rightarrow$ tenants/ $\rightarrow$ billing/, webhooks/, audits/, etc. $\rightarrow$ auth/ & login.