Ai ready
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- What does this PR do and why? -->
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
<!-- Key changes made -->
|
||||||
|
|
||||||
|
-
|
||||||
|
-
|
||||||
|
|
||||||
|
## How to Test
|
||||||
|
|
||||||
|
1. Run the Blazor Web App: `dotnet run --project Fixiy.Web/Fixiy.Web.csproj`
|
||||||
|
2. <!-- Additional steps specific to this PR -->
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
- [ ] New interfaces defined in `Fixiy.Shared/Interfaces/` (not in platform projects)
|
||||||
|
- [ ] Platform-specific services implemented in both `Fixiy.Maui/Services/` and `Fixiy.Web/Services/`
|
||||||
|
- [ ] Both DI roots updated (`MauiProgram.cs` and `Fixiy.Web/Program.cs`)
|
||||||
|
- [ ] Render modes use `InteractiveRenderSettings.*` properties, not `RenderMode.*` constants
|
||||||
|
- [ ] No MAUI-specific APIs (`DeviceInfo`, `FileSystem`, etc.) introduced in `Fixiy.Shared`
|
||||||
|
- [ ] `_Imports.razor` updated if new shared namespaces are needed
|
||||||
|
- [ ] `InteractiveRenderSettings.ConfigureBlazorHybridRenderModes()` updated if new render mode properties added
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
# GitHub Copilot Instructions — Fixiy
|
||||||
|
|
||||||
|
## Language and Style
|
||||||
|
|
||||||
|
- **C# 12+** with `<Nullable>enable</Nullable>` and `<ImplicitUsings>enable</ImplicitUsings>` throughout. Never disable these per-file without strong justification.
|
||||||
|
- Use **file-scoped namespaces** (`namespace Fixiy.Shared.Services;`) not block-scoped.
|
||||||
|
- Prefer `record` types for immutable DTOs.
|
||||||
|
- Use `async`/`await` consistently — never `.Result` or `.Wait()` on Tasks.
|
||||||
|
- Remove unused `using` directives.
|
||||||
|
|
||||||
|
## Blazor Component Conventions
|
||||||
|
|
||||||
|
- All shared components live in `Fixiy.Shared/Components/`. Do not create components in `Fixiy.Maui` or `Fixiy.Web`.
|
||||||
|
- Pages go in `Fixiy.Shared/Components/Pages/`, layout in `Layout/`, reusable elements in `SingleElements/`.
|
||||||
|
- Scoped CSS goes in a matching `.razor.css` file alongside the component.
|
||||||
|
- Inject services via `@inject` in `.razor` files — Blazor components do not support constructor injection.
|
||||||
|
- Prefer `[Parameter]` for component inputs; avoid cascading parameters unless genuinely needed across deep trees.
|
||||||
|
|
||||||
|
## Render Mode Rules
|
||||||
|
|
||||||
|
- **Always use `InteractiveRenderSettings.*` properties** (`@InteractiveServer`, `@InteractiveAuto`, `@InteractiveWebAssembly`) in shared components — never hard-coded `RenderMode.*` constants.
|
||||||
|
- `Fixiy.Maui/MauiProgram.cs` calls `ConfigureBlazorHybridRenderModes()` which sets all three properties to `null`. This is intentional — MAUI Blazor Hybrid runs components statically.
|
||||||
|
- Do not work around the null render modes in shared code. Components that need interactivity must tolerate `null` render mode in MAUI context.
|
||||||
|
|
||||||
|
## IFormFactor Platform Abstraction
|
||||||
|
|
||||||
|
- Platform-specific device info must be accessed via `IFormFactor` injection (`Fixiy.Shared/Interfaces/IFormFactor.cs`).
|
||||||
|
- **Never call `DeviceInfo`, `Connectivity`, `FileSystem`, or any `Microsoft.Maui.*` API from `Fixiy.Shared`.**
|
||||||
|
- When adding new platform capabilities: define interface in `Fixiy.Shared/Interfaces/` → implement in both `Fixiy.Maui/Services/` and `Fixiy.Web/Services/` → register in both DI roots.
|
||||||
|
|
||||||
|
## IntegryApiClient Registration
|
||||||
|
|
||||||
|
- Register with the same `appToken` and `useLoginAzienda: true` in both hosts.
|
||||||
|
- MAUI: `.UseIntegry(appToken, useLoginAzienda: true)` on the `MauiAppBuilder` chain.
|
||||||
|
- Web: `builder.Services.UseIntegry(appToken, useLoginAzienda: true)` in `Program.cs`.
|
||||||
|
- One registration per DI root — do not call it twice.
|
||||||
|
|
||||||
|
## Service Registration Lifetimes
|
||||||
|
|
||||||
|
- `Fixiy.Maui` registers platform services as **`Singleton`** — the MAUI app has a single long-lived process.
|
||||||
|
- `Fixiy.Web` registers platform services as **`Scoped`** — ASP.NET Core server-side per-request scope.
|
||||||
|
- Interfaces must not assume a specific lifetime; implementations may.
|
||||||
|
|
||||||
|
## Maintenance Matrix
|
||||||
|
|
||||||
|
| Change | Cascades to |
|
||||||
|
|--------|-------------|
|
||||||
|
| Add/modify `Fixiy.Shared/Interfaces/*.cs` | Both `Fixiy.Maui/Services/` and `Fixiy.Web/Services/` implementations + DI registration in both hosts |
|
||||||
|
| Modify `InteractiveRenderSettings.cs` | `MauiProgram.ConfigureBlazorHybridRenderModes()` — must null every new property |
|
||||||
|
| Add a new shared page | `Fixiy.Shared/Components/Pages/` → nav link in `NavMenu.razor` if user-accessible |
|
||||||
|
| Add a NuGet package | Target `.csproj` file; check private NuGet feed has it |
|
||||||
|
| Change IntegryApiClient version | All three `.csproj` files (`Fixiy.Maui`, `Fixiy.Shared`, `Fixiy.Web`) |
|
||||||
|
| Modify `_Imports.razor` | Verify no MAUI-only or web-only namespaces are introduced |
|
||||||
|
| Update app token | `Fixiy.Maui/MauiProgram.cs` `AppToken` const + `Fixiy.Web/Program.cs` `appToken` const |
|
||||||
|
|
||||||
|
## Test Conventions
|
||||||
|
|
||||||
|
- No test projects are currently configured. When adding tests, use **xUnit** with **bUnit** for Razor component testing.
|
||||||
|
- Test projects should reference `Fixiy.Shared` and provide mock implementations of `IFormFactor`.
|
||||||
|
- Use `Moq` or `NSubstitute` for mocking; do not create manual stubs unless the interface is trivial.
|
||||||
|
|
||||||
|
## Code Style Notes
|
||||||
|
|
||||||
|
- Omit the `private` modifier on fields — it is the default in C#.
|
||||||
|
- Constants: `PascalCase` for class-level `const`, no Hungarian notation.
|
||||||
|
- One type per file; file name matches type name.
|
||||||
|
- Keep `@code` blocks in `.razor` files focused — extract complex logic to a `*.razor.cs` code-behind or a separate service class.
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
name: Copilot Setup Steps
|
||||||
|
|
||||||
|
on: workflow_dispatch
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
copilot-setup-steps:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup .NET
|
||||||
|
uses: actions/setup-dotnet@v4
|
||||||
|
with:
|
||||||
|
dotnet-version: '10.0.x'
|
||||||
|
|
||||||
|
- name: Configure private NuGet source credentials
|
||||||
|
# NuGet.Config points to the private Integry feed; CI secrets provide auth.
|
||||||
|
# Set NUGET_USERNAME and NUGET_PASSWORD in repository secrets.
|
||||||
|
run: |
|
||||||
|
dotnet nuget update source integry \
|
||||||
|
--username "${{ secrets.NUGET_USERNAME }}" \
|
||||||
|
--password "${{ secrets.NUGET_PASSWORD }}" \
|
||||||
|
--store-password-in-clear-text
|
||||||
|
|
||||||
|
- name: Restore dependencies
|
||||||
|
run: dotnet restore Fixiy.sln
|
||||||
|
|
||||||
|
- name: Build Fixiy.Web
|
||||||
|
# MAUI builds require platform-specific workloads not available on ubuntu-latest.
|
||||||
|
# Fixiy.Web covers the shared Blazor component tree and validates the full build.
|
||||||
|
run: dotnet build Fixiy.Web/Fixiy.Web.csproj --no-restore -c Debug
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
# Fixiy — Agent Guide
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
Fixiy is a **.NET MAUI Blazor Hybrid** app that shares its entire UI with a **Blazor Server Web App** via a Razor Class Library (RCL). All pages and components live in `Fixiy.Shared` and are consumed by both host projects without modification.
|
||||||
|
|
||||||
|
- **App ID:** `it.integry.fixiy`
|
||||||
|
- **Solution:** `Fixiy.sln`
|
||||||
|
- **SDK:** .NET 10 (`global.json` — `rollForward: latestMajor`)
|
||||||
|
- **NuGet source:** Private feed — see `NuGet.Config` (`https://nuget.studioml.it/repository/nuget-group/index.json`)
|
||||||
|
- **Platforms:** Android 26+, iOS 15+, Web (Blazor Server)
|
||||||
|
|
||||||
|
## Repository Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
Fixiy.sln
|
||||||
|
├── Fixiy.Maui/ # .NET MAUI Blazor Hybrid host (Android + iOS)
|
||||||
|
│ ├── MauiProgram.cs # DI root — registers MAUI services + IntegryApiClient
|
||||||
|
│ ├── Services/FormFactor.cs # MAUI implementation of IFormFactor (uses DeviceInfo)
|
||||||
|
│ ├── Platforms/ # Platform-specific entry points (Android, iOS, …)
|
||||||
|
│ └── Resources/ # App icons, splash, fonts, images
|
||||||
|
├── Fixiy.Shared/ # Razor Class Library — all shared UI
|
||||||
|
│ ├── Components/
|
||||||
|
│ │ ├── Layout/ # MainLayout.razor, NavBar.razor, NavMenu.razor
|
||||||
|
│ │ ├── Pages/ # Routable pages (e.g., Home.razor)
|
||||||
|
│ │ └── SingleElements/ # Reusable components (e.g., NoDataAvailable.razor)
|
||||||
|
│ ├── Interfaces/IFormFactor.cs # Platform abstraction interface
|
||||||
|
│ ├── InteractiveRenderSettings.cs # Shared render mode constants (nulled in MAUI)
|
||||||
|
│ └── _Imports.razor # Global using directives for shared components
|
||||||
|
└── Fixiy.Web/ # Blazor Server Web App host
|
||||||
|
├── Program.cs # DI root — registers web services + IntegryApiClient
|
||||||
|
└── Services/FormFactor.cs # Web implementation of IFormFactor
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tech Stack
|
||||||
|
|
||||||
|
| Layer | Technology |
|
||||||
|
|-------|-----------|
|
||||||
|
| Mobile host | .NET MAUI Blazor Hybrid — `net10.0-android`, `net10.0-ios` |
|
||||||
|
| Web host | Blazor Server (ASP.NET Core, `net10.0`) |
|
||||||
|
| Shared UI | Razor Class Library (`Fixiy.Shared`, `net10.0`) |
|
||||||
|
| Client SDK | `IntegryApiClient` — MAUI / Core / Blazor variants (private NuGet) |
|
||||||
|
| Fonts | OpenSans via MAUI font registration |
|
||||||
|
|
||||||
|
## Build & Run
|
||||||
|
|
||||||
|
**Prerequisites:** .NET SDK 10, MAUI workload (`dotnet workload install maui`) for mobile builds.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Restore (requires private NuGet credentials — see NuGet.Config)
|
||||||
|
dotnet restore Fixiy.sln
|
||||||
|
|
||||||
|
# Run Blazor Web App (no platform SDK required)
|
||||||
|
dotnet run --project Fixiy.Web/Fixiy.Web.csproj
|
||||||
|
|
||||||
|
# Build MAUI for Android (requires MAUI workload)
|
||||||
|
dotnet build Fixiy.Maui/Fixiy.Maui.csproj -f net10.0-android
|
||||||
|
|
||||||
|
# Build MAUI for iOS (requires macOS + Xcode)
|
||||||
|
dotnet build Fixiy.Maui/Fixiy.Maui.csproj -f net10.0-ios
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Patterns and Conventions
|
||||||
|
|
||||||
|
### 1. InteractiveRenderSettings pattern
|
||||||
|
|
||||||
|
`Fixiy.Shared/InteractiveRenderSettings.cs` exposes `static IComponentRenderMode?` properties (`InteractiveServer`, `InteractiveAuto`, `InteractiveWebAssembly`). In `Fixiy.Web` these remain set to real render modes. In `Fixiy.Maui`, `MauiProgram.ConfigureBlazorHybridRenderModes()` sets all three to `null` — MAUI Blazor Hybrid does not support server or WASM render modes.
|
||||||
|
|
||||||
|
**Always use the property, not the constant, in shared components:**
|
||||||
|
|
||||||
|
```razor
|
||||||
|
@* Wrong — hard-coded constant, crashes in MAUI *@
|
||||||
|
@rendermode="RenderMode.InteractiveServer"
|
||||||
|
|
||||||
|
@* Correct — resolves to null in MAUI, InteractiveServer in Web *@
|
||||||
|
@rendermode="@InteractiveServer"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. IFormFactor platform abstraction
|
||||||
|
|
||||||
|
`IFormFactor` (in `Fixiy.Shared/Interfaces/`) provides `GetFormFactor()` and `GetPlatform()`. Each host project provides its own implementation registered in DI. Inject `IFormFactor` in shared components; **never call `DeviceInfo` or other MAUI APIs from `Fixiy.Shared`**.
|
||||||
|
|
||||||
|
### 3. IntegryApiClient registration
|
||||||
|
|
||||||
|
Both DI roots register IntegryApiClient with the same `appToken` and `useLoginAzienda: true`.
|
||||||
|
|
||||||
|
- MAUI: `.UseIntegry(appToken, useLoginAzienda: true)` on `MauiAppBuilder`
|
||||||
|
- Web: `builder.Services.UseIntegry(appToken, useLoginAzienda: true)`
|
||||||
|
|
||||||
|
The app token must match across both registrations. It is currently declared as a `const` in `MauiProgram.cs` and a `const string` in `Fixiy.Web/Program.cs`.
|
||||||
|
|
||||||
|
### 4. Adding a new page
|
||||||
|
|
||||||
|
1. Create `Fixiy.Shared/Components/Pages/YourPage.razor` with `@page "/your-route"`
|
||||||
|
2. No extra registration required — `Routes.razor` discovers pages via assembly scanning
|
||||||
|
3. Add a navigation entry to `Fixiy.Shared/Components/Layout/NavMenu.razor` if user-accessible
|
||||||
|
|
||||||
|
### 5. Adding a platform-specific service
|
||||||
|
|
||||||
|
1. Define the interface in `Fixiy.Shared/Interfaces/IYourService.cs`
|
||||||
|
2. Implement in `Fixiy.Maui/Services/YourService.cs` (may use MAUI APIs)
|
||||||
|
3. Implement in `Fixiy.Web/Services/YourService.cs` (BCL only)
|
||||||
|
4. Register in `Fixiy.Maui/MauiProgram.cs` as `AddSingleton<IYourService, YourService>()`
|
||||||
|
5. Register in `Fixiy.Web/Program.cs` as `AddScoped<IYourService, YourService>()`
|
||||||
|
|
||||||
|
## Maintenance Matrix
|
||||||
|
|
||||||
|
| When you change… | Also update… |
|
||||||
|
|------------------|-------------|
|
||||||
|
| `Fixiy.Shared/Interfaces/IFormFactor.cs` | `Fixiy.Maui/Services/FormFactor.cs` and `Fixiy.Web/Services/FormFactor.cs` |
|
||||||
|
| Any interface in `Fixiy.Shared/Interfaces/` | Both platform `Services/` implementations + both DI roots |
|
||||||
|
| `InteractiveRenderSettings.cs` (add/remove property) | `MauiProgram.ConfigureBlazorHybridRenderModes()` — must null all new properties |
|
||||||
|
| `Fixiy.Shared/_Imports.razor` | Verify imports are valid in both MAUI and Web (no platform-only namespaces) |
|
||||||
|
| IntegryApiClient package version | Update in all three `.csproj` files consistently |
|
||||||
|
| App token | Update in both `Fixiy.Maui/MauiProgram.cs` and `Fixiy.Web/Program.cs` |
|
||||||
|
| `Fixiy.Shared/Components/Layout/NavMenu.razor` | Review navigation works on both platforms |
|
||||||
|
|
||||||
|
## CI/CD
|
||||||
|
|
||||||
|
No CI pipeline is currently configured. The project uses a private NuGet feed (`NuGet.Config`). For CI builds:
|
||||||
|
|
||||||
|
- Set `NUGET_USERNAME` and `NUGET_PASSWORD` (or PAT) as CI secrets
|
||||||
|
- Build only `Fixiy.Web` in standard CI; MAUI builds require platform-specific agents with MAUI workloads
|
||||||
|
- See `.github/workflows/copilot-setup-steps.yml` for environment setup reference
|
||||||
|
|
||||||
|
## Common Pitfalls
|
||||||
|
|
||||||
|
- **Render mode constants in shared code:** Use `@InteractiveServer` (property from `InteractiveRenderSettings`) never `RenderMode.InteractiveServer`. The MAUI host nulls these via `ConfigureBlazorHybridRenderModes()`.
|
||||||
|
- **MAUI APIs in Fixiy.Shared:** `DeviceInfo`, `FileSystem`, `Connectivity`, and other `Microsoft.Maui.*` APIs are not available in the RCL. Define a new `IFormFactor`-style interface instead.
|
||||||
|
- **Private NuGet feed:** All `dotnet restore` calls require credentials. In CI, add the source credentials via environment secrets — the `NuGet.Config` `<clear/>` directive removes all default sources.
|
||||||
|
- **MAUI workload for builds:** `dotnet workload install maui` is required before building `Fixiy.Maui`. Standard CI runners (Ubuntu) don't have it by default.
|
||||||
|
- **Service lifetimes:** MAUI registers platform services as `Singleton` (long-lived app); Web registers them as `Scoped` (per request). Interfaces must not assume a specific lifetime.
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [1.0.0]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- .NET MAUI Blazor Hybrid host targeting Android 26+ and iOS 15+
|
||||||
|
- Blazor Server Web App host sharing UI via `Fixiy.Shared` Razor Class Library
|
||||||
|
- `IFormFactor` platform abstraction for device/platform detection
|
||||||
|
- `InteractiveRenderSettings` pattern for sharing render modes between MAUI and Web
|
||||||
|
- IntegryApiClient integration for both MAUI and Web entry points
|
||||||
|
- `NoDataAvailable` reusable component
|
||||||
|
- `NavBar` and `NavMenu` layout components
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
[](https://github.com/johnpapa/ai-ready)
|
||||||
|
|
||||||
# .NET MAUI Blazor Hybrid app with a Blazor Web App sample app
|
# .NET MAUI Blazor Hybrid app with a Blazor Web App sample app
|
||||||
|
|
||||||
This sample app demonstrates a .NET MAUI Blazor Hybrid app with a Blazor Web App that uses a shared user interface via a Razor class library (RCL).
|
This sample app demonstrates a .NET MAUI Blazor Hybrid app with a Blazor Web App that uses a shared user interface via a Razor class library (RCL).
|
||||||
@@ -8,4 +10,12 @@ For more information, see [Build a .NET MAUI Blazor Hybrid app with a Blazor Web
|
|||||||
|
|
||||||
1. Clone this repository or download a ZIP archive of the repository. For more information, see [How to download a sample](https://learn.microsoft.com/aspnet/core/introduction-to-aspnet-core#how-to-download-a-sample).
|
1. Clone this repository or download a ZIP archive of the repository. For more information, see [How to download a sample](https://learn.microsoft.com/aspnet/core/introduction-to-aspnet-core#how-to-download-a-sample).
|
||||||
|
|
||||||
1. Run the `MauiBlazorWeb.Maui` project to run the .NET MAUI Blazor Hybrid app, or run the `MauiBlazorWeb.Web` project to run the Blazor Web App.
|
1. Run the `Fixiy.Maui` project to run the .NET MAUI Blazor Hybrid app, or run the `Fixiy.Web` project to run the Blazor Web App.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
1. Fork the repository and create a branch from `master`.
|
||||||
|
2. Restore dependencies: `dotnet restore Fixiy.sln` (requires credentials for the private NuGet feed — see `NuGet.Config`).
|
||||||
|
3. Run the web app to verify changes: `dotnet run --project Fixiy.Web/Fixiy.Web.csproj`.
|
||||||
|
4. Open a pull request — see [`.github/PULL_REQUEST_TEMPLATE.md`](.github/PULL_REQUEST_TEMPLATE.md) for the checklist.
|
||||||
|
5. See [`AGENTS.md`](AGENTS.md) for architecture details and the maintenance matrix.
|
||||||
|
|||||||
Reference in New Issue
Block a user