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:
@@ -93,6 +93,9 @@ namespace JobsMedical.Web.Migrations
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("character varying(200)");
|
||||
|
||||
b.Property<bool>("PushEnabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("SmsApiKey")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("character varying(200)");
|
||||
@@ -118,6 +121,18 @@ namespace JobsMedical.Web.Migrations
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("VapidPrivateKey")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("character varying(200)");
|
||||
|
||||
b.Property<string>("VapidPublicKey")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("character varying(200)");
|
||||
|
||||
b.Property<string>("VapidSubject")
|
||||
.HasMaxLength(120)
|
||||
.HasColumnType("character varying(120)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("AppSettings");
|
||||
@@ -668,6 +683,44 @@ namespace JobsMedical.Web.Migrations
|
||||
b.ToTable("Visitors");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("JobsMedical.Web.Models.WebPushSubscription", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Auth")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("character varying(100)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Endpoint")
|
||||
.IsRequired()
|
||||
.HasMaxLength(600)
|
||||
.HasColumnType("character varying(600)");
|
||||
|
||||
b.Property<string>("P256dh")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("character varying(200)");
|
||||
|
||||
b.Property<string>("VisitorId")
|
||||
.HasMaxLength(36)
|
||||
.HasColumnType("character varying(36)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Endpoint")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("WebPushSubscriptions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("JobsMedical.Web.Models.Application", b =>
|
||||
{
|
||||
b.HasOne("JobsMedical.Web.Models.User", "Doctor")
|
||||
|
||||
Reference in New Issue
Block a user