feat(web): add PWA install support#576
Conversation
# Conflicts: # Cli/ForgeTrust.AppSurface.Cli/README.md
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughAdds PWA configuration types, validation, runtime endpoints, Razor head metadata, a CLI verifier, an example app, and supporting tests and documentation across the web and CLI projects. ChangesPWA install contract
Sequence Diagram(s)See the hidden artifact above. Estimated code review effort🎯 5 (Critical) | ⏱️ ~90 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Pull request overview
Adds first-class Progressive Web App (PWA) install support to ForgeTrust.AppSurface.Web (options + endpoint mapping + Razor head emission) and introduces a corresponding appsurface pwa verify CLI command plus an executable example and documentation to prove/diagnose install posture.
Changes:
- Added
WebOptions.Pwaconfiguration surface with startup validation and opt-in offline service worker mapping. - Mapped PWA endpoints (manifest, diagnostics HTML/JSON, optional service worker) and added
<appsurface:pwa-head />TagHelper for MVC/Razor layouts. - Added CLI verification (
appsurface pwa verify --url <origin>) with stable diagnostics plus an example app and docs/release notes.
Reviewed changes
Copilot reviewed 36 out of 38 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| Web/ForgeTrust.AppSurface.Web/WebStartup.cs | Validates/enables PWA support during startup and maps PWA endpoints. |
| Web/ForgeTrust.AppSurface.Web/WebOptions.cs | Adds WebOptions.Pwa configuration entry point. |
| Web/ForgeTrust.AppSurface.Web/TagHelpers/AppSurfacePwaHeadTagHelper.cs | Implements <appsurface:pwa-head /> to emit manifest/theme/icon/service-worker metadata. |
| Web/ForgeTrust.AppSurface.Web/README.md | Documents the “3-minute” PWA install setup path and key behaviors. |
| Web/ForgeTrust.AppSurface.Web/PwaOptionsValidator.cs | Validates PWA options and provides diagnostic codes + safe-path helpers. |
| Web/ForgeTrust.AppSurface.Web/PwaOptions.cs | Defines the main PWA options model. |
| Web/ForgeTrust.AppSurface.Web/PwaOfflineOptions.cs | Defines opt-in offline fallback/service-worker configuration. |
| Web/ForgeTrust.AppSurface.Web/PwaIcon.cs | Defines manifest/head icon entries. |
| Web/ForgeTrust.AppSurface.Web/PwaEndpointMapper.cs | Maps manifest/diagnostics/service-worker endpoints and renders payloads. |
| Web/ForgeTrust.AppSurface.Web/PwaDisplayMode.cs | Introduces manifest display-mode enum. |
| Web/ForgeTrust.AppSurface.Web/PwaDiagnosticEndpointExposure.cs | Introduces diagnostics exposure enum. |
| Web/ForgeTrust.AppSurface.Web/Docs/pwa-install.md | Adds full PWA install/offline/diagnostics/CLI documentation. |
| Web/ForgeTrust.AppSurface.Web.Tests/PwaOptionsTests.cs | Adds unit coverage for PWA option defaults + validation diagnostics. |
| Web/ForgeTrust.AppSurface.Web.Tests/PwaEndpointTests.cs | Adds integration coverage for mapped endpoints and PathBase behavior. |
| Web/ForgeTrust.AppSurface.Web.Tests/PublicEnumContractTests.cs | Adds enum numeric-value stability tests for new public enums. |
| Web/ForgeTrust.AppSurface.Web.Tests/AppSurfacePwaHeadTagHelperTests.cs | Adds TagHelper output/disabled-path tests, including PathBase behavior. |
| releases/unreleased.md | Updates unreleased notes to include PWA feature summary. |
| packages/README.md | Updates package chooser text to mention opt-in PWA support in Web package. |
| packages/package-index.yml | Updates package index metadata to include PWA install support in Web. |
| ForgeTrust.AppSurface.slnx | Adds the new examples/web-pwa-install project to the solution. |
| examples/web-pwa-install/wwwroot/icons/app-512.svg | Adds example PWA icon asset (512). |
| examples/web-pwa-install/wwwroot/icons/app-192.svg | Adds example PWA icon asset (192). |
| examples/web-pwa-install/WebPwaInstallExample.csproj | Adds runnable example project referencing ForgeTrust.AppSurface.Web. |
| examples/web-pwa-install/Views/Shared/_Layout.cshtml | Uses <appsurface:pwa-head /> in the example layout. |
| examples/web-pwa-install/Views/Home/Index.cshtml | Adds example landing page text and verifier command hint. |
| examples/web-pwa-install/Views/_ViewStart.cshtml | Sets example layout. |
| examples/web-pwa-install/Views/_ViewImports.cshtml | Imports TagHelpers including ForgeTrust.AppSurface.Web. |
| examples/web-pwa-install/verify.sh | Adds a script to run the example and execute the CLI verifier. |
| examples/web-pwa-install/README.md | Documents what the example proves and how to run it. |
| examples/web-pwa-install/Program.cs | Configures PWA options + offline fallback endpoint in the example app. |
| examples/web-pwa-install/packages.lock.json | Adds locked restore entries for the new example project. |
| examples/web-pwa-install/Controllers/HomeController.cs | Adds MVC controller to serve the example page. |
| examples/README.md | Adds the new PWA install proof example to the examples list. |
| Cli/ForgeTrust.AppSurface.Cli/README.md | Documents the new appsurface pwa verify command. |
| Cli/ForgeTrust.AppSurface.Cli/PwaCommand.cs | Implements pwa verify command and verifier logic/diagnostics. |
| Cli/ForgeTrust.AppSurface.Cli/AppSurfaceCliApp.cs | Registers HttpClient/verifier DI services and adjusts HttpClient logging. |
| Cli/ForgeTrust.AppSurface.Cli.Tests/PwaVerifierTests.cs | Adds extensive verifier pass/fail coverage and adapter tests. |
| CHANGELOG.md | Adds a changelog entry describing the new PWA install support. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/README.md (1)
59-60: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winAdd the required icon MIME type.
PwaOptionsValidatorrequiresPwaOptions.Icons[i].Type, so this sample will fail startup when copied as-is. Add a concrete type, for exampleimage/png, to both icon entries. Based on the upstream validator contract inWeb/ForgeTrust.AppSurface.Web/PwaOptionsValidator.cs.🛠️ Suggested fix
- options.Pwa.Icons.Add(new PwaIcon { Source = "/icons/app-192.png", Sizes = "192x192" }); - options.Pwa.Icons.Add(new PwaIcon { Source = "/icons/app-512.png", Sizes = "512x512" }); + options.Pwa.Icons.Add(new PwaIcon { Source = "/icons/app-192.png", Sizes = "192x192", Type = "image/png" }); + options.Pwa.Icons.Add(new PwaIcon { Source = "/icons/app-512.png", Sizes = "512x512", Type = "image/png" });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/README.md` around lines 59 - 60, The README sample for the PWA package is missing the required icon MIME type, which will cause validation to fail when copied. Update the `ForgeTrust.AppSurface.Web` package example so both icon entries include a concrete `Type` value, matching the expectations enforced by `PwaOptionsValidator` and `PwaOptions.Icons`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Cli/ForgeTrust.AppSurface.Cli/AppSurfaceCliApp.cs`:
- Around line 77-79: The PWA verification HttpClient setup in AppSurfaceCliApp
currently allows redirects, which can let PwaVerifier treat a redirected
cross-origin response as valid. Update the AddHttpClient configuration for
PwaVerificationHttpClient to disable automatic redirects, or add a final-URI
validation step in PwaVerifier so responses that leave the app origin/base path
are rejected. Use the existing PwaVerificationHttpClient and PwaVerifier
registration points to apply the fix.
In `@examples/web-pwa-install/Controllers/HomeController.cs`:
- Around line 5-12: Document the public API surface added by HomeController and
its Index action by adding XML documentation to the HomeController class and
Index() method, describing the root route, the fact that it renders the default
view, and the intended sample/expected usage; make sure the docs cover API
shape, behavior, defaults, constraints, and usage so the new controller is fully
documented per the codebase guidelines.
In `@examples/web-pwa-install/Program.cs`:
- Around line 34-53: The new internal module surface in WebPwaInstallModule is
missing XML documentation, so add docs to the class and each member
(IncludeAsApplicationPart, ConfigureServices, RegisterDependentModules,
ConfigureHostBeforeServices, ConfigureHostAfterServices) describing its role and
lifecycle ordering; also document why IncludeAsApplicationPart must remain
enabled for this sample so the analyzer/doc warning is cleared.
In `@examples/web-pwa-install/Views/Home/Index.cshtml`:
- Around line 3-14: The rendered diagnostics links and verify command are
ignoring Request.PathBase, so the page can generate incorrect URLs when the app
is hosted under a sub-path. Update the Home/Index.cshtml logic around
verifierOrigin and the /_appsurface/pwa link to build both values with
Context.Request.PathBase preserved, using the existing verifierOrigin variable
so the displayed appsurface pwa verify --url target matches the deployment root.
In `@Web/ForgeTrust.AppSurface.Web/Docs/pwa-install.md`:
- Around line 20-21: The PWA install sample is missing the required icon MIME
type, so copying it will fail validation in PwaOptionsValidator. Update both
PwaIcon entries in the PwaOptions setup to include a concrete Type value, such
as image/png, and keep the change consistent with the validator contract in
PwaOptionsValidator and the sample shown in Pwa-install.md.
In `@Web/ForgeTrust.AppSurface.Web/PwaOptionsValidator.cs`:
- Line 23: The StartUrl validation in PwaOptionsValidator is too strict because
it reuses RequireLocalPath, which rejects valid query strings used by PWA
start_url values. Update the StartUrl-specific validation path to allow a query
component while still rejecting unsafe forms like double slashes, scheme-like
strings, backslashes, fragments, traversal, and control characters; keep the
existing stricter checks for Scope, ManifestPath, and DiagnosticsPath unchanged.
In `@Web/ForgeTrust.AppSurface.Web/README.md`:
- Around line 59-60: The PWA sample is missing the required icon MIME type, so
copying it will fail validation in PwaOptionsValidator. Update the two
PwaOptions.Icons.Add entries in the README example to set PwaIcon.Type for each
icon, using a concrete value like image/png, and keep the existing Source and
Sizes fields unchanged.
---
Outside diff comments:
In `@packages/README.md`:
- Around line 59-60: The README sample for the PWA package is missing the
required icon MIME type, which will cause validation to fail when copied. Update
the `ForgeTrust.AppSurface.Web` package example so both icon entries include a
concrete `Type` value, matching the expectations enforced by
`PwaOptionsValidator` and `PwaOptions.Icons`.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: e52ced2a-4c8c-4e7d-800a-50473e108d3c
⛔ Files ignored due to path filters (2)
examples/web-pwa-install/wwwroot/icons/app-192.svgis excluded by!**/*.svgexamples/web-pwa-install/wwwroot/icons/app-512.svgis excluded by!**/*.svg
📒 Files selected for processing (36)
CHANGELOG.mdCli/ForgeTrust.AppSurface.Cli.Tests/PwaVerifierTests.csCli/ForgeTrust.AppSurface.Cli/AppSurfaceCliApp.csCli/ForgeTrust.AppSurface.Cli/PwaCommand.csCli/ForgeTrust.AppSurface.Cli/README.mdForgeTrust.AppSurface.slnxWeb/ForgeTrust.AppSurface.Web.Tests/AppSurfacePwaHeadTagHelperTests.csWeb/ForgeTrust.AppSurface.Web.Tests/PublicEnumContractTests.csWeb/ForgeTrust.AppSurface.Web.Tests/PwaEndpointTests.csWeb/ForgeTrust.AppSurface.Web.Tests/PwaOptionsTests.csWeb/ForgeTrust.AppSurface.Web/Docs/pwa-install.mdWeb/ForgeTrust.AppSurface.Web/PwaDiagnosticEndpointExposure.csWeb/ForgeTrust.AppSurface.Web/PwaDisplayMode.csWeb/ForgeTrust.AppSurface.Web/PwaEndpointMapper.csWeb/ForgeTrust.AppSurface.Web/PwaIcon.csWeb/ForgeTrust.AppSurface.Web/PwaOfflineOptions.csWeb/ForgeTrust.AppSurface.Web/PwaOptions.csWeb/ForgeTrust.AppSurface.Web/PwaOptionsValidator.csWeb/ForgeTrust.AppSurface.Web/README.mdWeb/ForgeTrust.AppSurface.Web/TagHelpers/AppSurfacePwaHeadTagHelper.csWeb/ForgeTrust.AppSurface.Web/WebOptions.csWeb/ForgeTrust.AppSurface.Web/WebStartup.csexamples/README.mdexamples/web-pwa-install/Controllers/HomeController.csexamples/web-pwa-install/Program.csexamples/web-pwa-install/README.mdexamples/web-pwa-install/Views/Home/Index.cshtmlexamples/web-pwa-install/Views/Shared/_Layout.cshtmlexamples/web-pwa-install/Views/_ViewImports.cshtmlexamples/web-pwa-install/Views/_ViewStart.cshtmlexamples/web-pwa-install/WebPwaInstallExample.csprojexamples/web-pwa-install/packages.lock.jsonexamples/web-pwa-install/verify.shpackages/README.mdpackages/package-index.ymlreleases/unreleased.md
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
Web/ForgeTrust.AppSurface.Web.Tests/PwaEndpointTests.cs (1)
245-254: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReuse one valid-options builder across the PWA test suites.
ConfigureValidPwahand-copies part ofPwaOptionsTests.CreateValidOptions(), so any new required field or default can make the validator and endpoint suites diverge silently. A single shared test fixture/helper would keep both suites pinned to the same baseline config.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Web/ForgeTrust.AppSurface.Web.Tests/PwaEndpointTests.cs` around lines 245 - 254, `ConfigureValidPwa` is duplicating the baseline setup from `PwaOptionsTests.CreateValidOptions`, which can drift from the validator tests. Refactor the PWA test setup to use a single shared valid-options builder/helper across both suites, and have `ConfigureValidPwa` populate from that shared source instead of hand-copying fields so `PwaEndpointTests` and `PwaOptionsTests` stay aligned.Cli/ForgeTrust.AppSurface.Cli.Tests/PwaVerifierTests.cs (1)
762-777: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winTighten the fake client’s URL matching.
StringComparer.OrdinalIgnoreCaseplusTrimEnd('/')erases path-case and trailing-slash distinctions that this verifier explicitly cares about, so a bad URI resolution can still pass in tests. Use exact URI strings here, or normalize throughUrion both insert and lookup instead of lossy string surgery.Proposed fix
- private readonly Dictionary<string, PwaHttpResponse> _responses = new(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary<string, PwaHttpResponse> _responses = new(StringComparer.Ordinal); ... - _responses[url.TrimEnd('/')] = new PwaHttpResponse(statusCode, contentType, body); + _responses[url] = new PwaHttpResponse(statusCode, contentType, body); ... - return Task.FromResult(_responses.TryGetValue(uri.ToString().TrimEnd('/'), out var response) + return Task.FromResult(_responses.TryGetValue(uri.ToString(), out var response) ? response : new PwaHttpResponse(HttpStatusCode.NotFound, "text/plain", string.Empty));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Cli/ForgeTrust.AppSurface.Cli.Tests/PwaVerifierTests.cs` around lines 762 - 777, The fake client in PwaVerifierTests currently uses case-insensitive string keys and TrimEnd('/') in Add and GetAsync, which can hide URI resolution bugs. Update the _responses lookup in the fake Pwa HTTP client to use exact URI string matching, or normalize both stored and requested URLs consistently via Uri rather than lossy string trimming; keep the behavior localized to Add and GetAsync so the verifier still catches path-case and trailing-slash mismatches.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Cli/ForgeTrust.AppSurface.Cli/README.md`:
- Line 79: Update the README summary for the verifier to match the actual
contract: in the CLI docs section, expand the accepted origins in the relevant
description near the verifier behavior to include loopback addresses like
127.0.0.1 and ::1, and document that offline checks also validate
offlineFallbackPath reachability in addition to service-worker posture. Keep the
wording aligned with the existing verifier/ASPWA2xx diagnostics description so
users can tell which URLs are valid and why offline validation fails.
In `@Web/ForgeTrust.AppSurface.Web/PwaOptionsValidator.cs`:
- Around line 207-244: The scope/start-url validation logic is duplicated
between PwaOptionsValidator.RequireStartUrlWithinScope/IsPathWithinScope and the
CLI verifier in PwaCommand, so update this to use one shared implementation
instead of two copies. Extract the common path/scope checks into a shared helper
or utility and have both the runtime validator and appsurface pwa verify call
that same code, keeping the contract consistent when the rule changes.
---
Outside diff comments:
In `@Cli/ForgeTrust.AppSurface.Cli.Tests/PwaVerifierTests.cs`:
- Around line 762-777: The fake client in PwaVerifierTests currently uses
case-insensitive string keys and TrimEnd('/') in Add and GetAsync, which can
hide URI resolution bugs. Update the _responses lookup in the fake Pwa HTTP
client to use exact URI string matching, or normalize both stored and requested
URLs consistently via Uri rather than lossy string trimming; keep the behavior
localized to Add and GetAsync so the verifier still catches path-case and
trailing-slash mismatches.
In `@Web/ForgeTrust.AppSurface.Web.Tests/PwaEndpointTests.cs`:
- Around line 245-254: `ConfigureValidPwa` is duplicating the baseline setup
from `PwaOptionsTests.CreateValidOptions`, which can drift from the validator
tests. Refactor the PWA test setup to use a single shared valid-options
builder/helper across both suites, and have `ConfigureValidPwa` populate from
that shared source instead of hand-copying fields so `PwaEndpointTests` and
`PwaOptionsTests` stay aligned.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: e499bbf5-86f9-4371-8150-3b9bcb8c51d5
📒 Files selected for processing (13)
Cli/ForgeTrust.AppSurface.Cli.Tests/PwaVerifierTests.csCli/ForgeTrust.AppSurface.Cli/PwaCommand.csCli/ForgeTrust.AppSurface.Cli/README.mdWeb/ForgeTrust.AppSurface.Web.Tests/PwaEndpointTests.csWeb/ForgeTrust.AppSurface.Web.Tests/PwaOptionsTests.csWeb/ForgeTrust.AppSurface.Web/Docs/pwa-install.mdWeb/ForgeTrust.AppSurface.Web/PwaDiagnosticEndpointExposure.csWeb/ForgeTrust.AppSurface.Web/PwaDisplayMode.csWeb/ForgeTrust.AppSurface.Web/PwaOptionsValidator.csWeb/ForgeTrust.AppSurface.Web/README.mdexamples/web-pwa-install/Controllers/HomeController.csexamples/web-pwa-install/Program.csexamples/web-pwa-install/Views/Home/Index.cshtml
Summary
Adds first-class PWA install support to
ForgeTrust.AppSurface.Webinstead of introducing a new package.WebOptions.Pwawith validation for install-critical metadata, required icon sizes, safe app-root-relative paths, display modes, and explicit offline configuration./manifest.webmanifest, development diagnostics under/_appsurface/pwa, status JSON, and a service worker only when offline fallback support is explicitly enabled.<appsurface:pwa-head />for MVC/Razor layouts, including manifest, theme color, mobile app metadata, versioned icons, and service-worker metadata when configured.appsurface pwa verify --url <origin>with stableASPWA2xxdiagnostics for manifest/head/icon/origin/offline posture.examples/web-pwa-installas an executable proof app with explicit offline fallback configuration.Test Coverage
New coverage added for:
Pre-Landing Review
No issues found. Ship review was rerun after merging
origin/main.Design Review
The feature includes a small MVC sample and diagnostic page. Full
/qabrowser testing covered the root sample, diagnostics page, and mobile offline fallback.Eval Results
No prompt-related files changed, so evals were skipped.
Scope Drift
Scope Check: CLEAN
Intent: Make PWA install metadata one-line and diagnosable in the existing AppSurface Web package, with offline support explicit and opt-in.
Delivered: Web PWA options/endpoints/TagHelper, CLI verifier proof, docs, package chooser metadata, and executable example.
Plan Completion
The implementation matches the supplied plan at the package-contract level:
WebOptions.Pwaadded inForgeTrust.AppSurface.Web.<appsurface:pwa-head />.appsurface pwa verify --url <origin>.Verification Results
dotnet test Cli/ForgeTrust.AppSurface.Cli.Tests/ForgeTrust.AppSurface.Cli.Tests.csproj --no-restore --filter FullyQualifiedName~Pwapassed: 11/11.dotnet test Web/ForgeTrust.AppSurface.Web.Tests/ForgeTrust.AppSurface.Web.Tests.csproj --no-restore --filter FullyQualifiedName~Pwapassed: 25/25.APP_SURFACE_WEB_PWA_PORT=5067 bash examples/web-pwa-install/verify.shpassed.dotnet format --verify-no-changespassed.dotnet run --project tools/ForgeTrust.AppSurface.PackageIndex/ForgeTrust.AppSurface.PackageIndex.csproj --no-restore -- verifypassed.git diff --checkpassed./qabrowser pass found 0 issues and produced.gstack/qa-reports/qa-report-127-0-0-1-5067-2026-06-26.md.TODOS
No TODO items completed in this PR.
Documentation
Web/ForgeTrust.AppSurface.Web/README.mdwith a 3-minute PWA install path.Web/ForgeTrust.AppSurface.Web/Docs/pwa-install.md.examples/web-pwa-install/README.md.Cli/ForgeTrust.AppSurface.Cli/README.md.packages/package-index.yml,packages/README.md,CHANGELOG.md, andreleases/unreleased.md.Test plan