# 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.
