PWA: installable app (web/win/android/ios) + download/help page + push notifications
- manifest.webmanifest + service worker (offline shell + push + notificationclick) + PNG icons (192/512/apple) + iOS meta + SW registration → installable everywhere - /Download page: per-OS install help (web/windows/android/ios), install button (beforeinstallprompt), 'enable notifications' flow, usage guide, Bazaar/TWA note; nav + footer links - Web Push foundation: WebPushSubscription entity + /push/subscribe (stores), VAPID + push settings in /Admin/Settings, on-device local notification; server broadcast documented (WebPush via Nexus) - docs/PWA-TWA.md: VAPID keygen, server-push wiring, Bubblewrap→Cafe Bazaar + assetlinks steps - Verified: manifest/sw/icons served, download page, subscribe stores (200), layout wired Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -66,6 +66,12 @@ public class AppSetting
|
||||
/// (Google Maps is blocked in Iran). Empty → only the "my location" button is shown.</summary>
|
||||
[MaxLength(200)] public string? NeshanMapKey { get; set; }
|
||||
|
||||
// --- Web Push (PWA notifications). VAPID keypair; generate once with the web-push tooling. ---
|
||||
public bool PushEnabled { get; set; } = false;
|
||||
[MaxLength(200)] public string? VapidPublicKey { get; set; }
|
||||
[MaxLength(200)] public string? VapidPrivateKey { get; set; }
|
||||
[MaxLength(120)] public string? VapidSubject { get; set; } = "mailto:admin@hamkadr.ir";
|
||||
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>Split a textarea (newline/comma separated) into trimmed non-empty items.</summary>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace JobsMedical.Web.Models;
|
||||
|
||||
/// <summary>A browser's Web Push subscription (PWA notifications). One row per device/browser.</summary>
|
||||
public class WebPushSubscription
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required, MaxLength(600)]
|
||||
public string Endpoint { get; set; } = ""; // push service URL (unique key)
|
||||
|
||||
[Required, MaxLength(200)]
|
||||
public string P256dh { get; set; } = ""; // client public key
|
||||
|
||||
[Required, MaxLength(100)]
|
||||
public string Auth { get; set; } = ""; // client auth secret
|
||||
|
||||
[MaxLength(36)]
|
||||
public string? VisitorId { get; set; } // who subscribed (anonymous visitor)
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
/// <summary>Shape posted by the browser's PushManager.subscribe().toJSON().</summary>
|
||||
public record PushSubscriptionDto(string? Endpoint, PushKeysDto? Keys);
|
||||
public record PushKeysDto(string? P256dh, string? Auth);
|
||||
Reference in New Issue
Block a user