Skip to content

feat: PWA manifest + service worker + SEO improvements - #50

Open
jerry-shimizutech wants to merge 2 commits into
mainfrom
feat/mo-seo-pwa
Open

feat: PWA manifest + service worker + SEO improvements#50
jerry-shimizutech wants to merge 2 commits into
mainfrom
feat/mo-seo-pwa

Conversation

@jerry-shimizutech

@jerry-shimizutech jerry-shimizutech commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Makes marianasopen.com installable as a Progressive Web App (PWA) on mobile and desktop. Also improves structured data for Google rich results.

Inbox Item

Leon requested: "Marianas Open — optimize it for SEO and PWA"

Changes

PWA

  • Install vite-plugin-pwa + configure VitePWA with Workbox service worker
  • Full web app manifest: name, icons, screenshots, shortcuts (Calendar + Rankings)
  • Generated PWA icons: 192×192, 512×512 standard + 512×512 maskable (dark navy background)
  • Generated app screenshots for install prompt (desktop + mobile)
  • Workbox runtime caching:
    • API calls (NetworkFirst, 4-hour cache, 10s timeout fallback)
    • Google Translate (CacheFirst, 7-day cache)
    • Cloudinary images (CacheFirst, 30-day cache)

index.html meta improvements

  • Apple PWA meta tags (apple-mobile-web-app-capable, apple-mobile-web-app-status-bar-style, etc.)
  • Default OG + Twitter Card tags (overridden per-page via react-helmet-async)
  • <link rel="preconnect"> to API and Clerk domains for faster page loads

SEO — Structured Data

  • seo.ts new helpers: getBreadcrumbSchema, getFaqSchema, getSportsEventSchema
  • CalendarPage — BreadcrumbList structured data (Google shows breadcrumbs in search)
  • RankingsPage — BreadcrumbList structured data
  • AboutPage — BreadcrumbList + FAQPage schema (5 BJJ questions, enables FAQ rich results)

Testing

  • npm run build ✅ (133 entries precached, sw.js + workbox bundle generated)
  • TypeScript compiles clean ✅

PWA Install

After deploy, visiting marianasopen.com on mobile Chrome/Safari will show an "Add to Home Screen" prompt. Users get the dark navy icon with MO logo, shortcuts to Calendar and Rankings.

Screenshots (icons)

icon-192.png and icon-512.png use the MO white logo centered on #07111f (dark navy) background, consistent with the site's color scheme.

Greptile Summary

This PR adds full PWA support (installable app, Workbox service worker, web app manifest) and SEO improvements (BreadcrumbList + FAQPage + SportsEvent structured data, OG/Twitter defaults, preconnect hints) to marianasopen.com. The implementation is well-structured and all previously flagged P1 issues (crossorigin on preconnects, black-translucent status bar, missing cacheableResponse on Translate/Cloudinary caches) have been resolved.\n\nSummary of changes:\n- vite.config.tsVitePWA plugin with full manifest (icons, screenshots, shortcuts) and three Workbox runtime caching strategies\n- index.html — Apple PWA meta tags, OG/Twitter Card defaults, <link rel=\"preconnect\"> hints\n- src/lib/seo.ts — New getBreadcrumbSchema, getFaqSchema, and getSportsEventSchema helpers\n- AboutPage, CalendarPage, RankingsPage — Breadcrumb structured data; AboutPage also gets FAQ rich-result schema\n- package.json — Adds vite-plugin-pwa; workbox-window is listed but not directly used (see comment)\n\nRemaining findings (all P2):\n- item: item.url ?? undefined in getBreadcrumbSchema is a no-op — ?? undefined can be dropped\n- workbox-window devDependency is redundant; vite-plugin-pwa bundles its own copy\n- getSportsEventSchema is exported but not yet wired to any page component\n- Breadcrumb URLs in the three page files are hardcoded strings instead of using the existing buildCanonicalUrl helper from seo.ts

Confidence Score: 5/5

Safe to merge — all previous P1 issues are resolved and only minor style suggestions remain.

All three previously-flagged P1 issues (crossorigin on preconnects, black-translucent status bar, missing cacheableResponse) are addressed in this revision. The only remaining findings are P2 style/cleanup items that don't affect runtime correctness or user experience.

No files require special attention. web/src/lib/seo.ts and web/package.json have minor style nits worth cleaning up but do not block merge.

Important Files Changed

Filename Overview
web/vite.config.ts Adds VitePWA plugin with Workbox manifest, icons, screenshots, and runtime caching. API/Translate/Cloudinary rules all now have cacheableResponse guards. Clean configuration.
web/src/lib/seo.ts Adds getBreadcrumbSchema, getFaqSchema, and getSportsEventSchema helpers. Minor issue: item.url ?? undefined is redundant; getSportsEventSchema is an unused dead export.
web/index.html Adds PWA meta tags, OG/Twitter defaults, and preconnect hints. Both preconnects include crossorigin, and status bar is set to black. All previous concerns addressed.
web/src/pages/AboutPage.tsx Integrates getBreadcrumbSchema and getFaqSchema with 5 well-written BJJ FAQs. Breadcrumb URL is hardcoded rather than using buildCanonicalUrl.
web/src/pages/CalendarPage.tsx Adds BreadcrumbList schema. Breadcrumb URL hardcoded (minor style issue).
web/src/pages/RankingsPage.tsx Adds BreadcrumbList schema. Breadcrumb URL hardcoded (minor style issue).
web/package.json Adds vite-plugin-pwa and workbox-window as devDependencies. workbox-window is not imported in any source file and is bundled internally by vite-plugin-pwa, making the explicit listing redundant.

Sequence Diagram

sequenceDiagram
    participant Browser
    participant SW as Service Worker (Workbox)
    participant Cache
    participant API as marianas-open-api
    participant CDN as Cloudinary/Translate

    Note over Browser,SW: First visit — PWA install prompt shown
    Browser->>SW: Install & activate (precache JS/CSS/HTML/images)
    SW->>Cache: Store precached assets

    Note over Browser,SW: Subsequent navigation
    Browser->>SW: Fetch request
    alt API request (/api/*)
        SW->>API: NetworkFirst (10s timeout)
        API-->>SW: 200 OK
        SW->>Cache: Store (mo-api-cache, 4h TTL)
        SW-->>Browser: Response
    else Cloudinary image
        SW->>Cache: CacheFirst lookup
        Cache-->>SW: Hit → serve immediately
        SW-->>Browser: Cached image (30d TTL)
    else Google Translate
        SW->>Cache: CacheFirst lookup
        Cache-->>SW: Miss → fetch CDN
        CDN-->>SW: Response
        SW->>Cache: Store (google-translate-cache, 7d TTL)
        SW-->>Browser: Response
    else Precached asset
        SW->>Cache: Cache hit
        SW-->>Browser: Instant response
    end
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: web/src/lib/seo.ts
Line: 81

Comment:
**Redundant nullish coalescing expression**

`item.url` is typed as `string | undefined`, so `item.url ?? undefined` is identical to `item.url`. The `?? undefined` guard adds no value here.

```suggestion
      item: item.url,
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: web/package.json
Line: 44

Comment:
**`workbox-window` not used directly in source**

`workbox-window` is added as a devDependency but is never imported in any source file. `vite-plugin-pwa` ships with its own bundled copy of `workbox-window` to power the `autoUpdate` registration virtual module — you don't need to list it separately. Leaving it here risks version skew between the copy bundled by `vite-plugin-pwa` and the one resolved from `node_modules`.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: web/src/lib/seo.ts
Line: 108-144

Comment:
**`getSportsEventSchema` is exported but not yet used**

This helper is defined and ready to go (the JSDoc comment even names the target: `EventDetailPage`), but it is not consumed by any component in this PR. No action needed right now, just flagging it as a dead-export so reviewers know to wire it up on the event detail page in a follow-up.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: web/src/pages/AboutPage.tsx
Line: 44

Comment:
**Breadcrumb URLs are hardcoded strings instead of using `SITE_URL`**

The rest of `seo.ts` uses the `SITE_URL` constant and the `buildCanonicalUrl` helper to construct absolute URLs. The breadcrumb calls in `AboutPage.tsx`, `CalendarPage.tsx`, and `RankingsPage.tsx` bypass those helpers and hardcode `https://marianasopen.com/…` directly. If the domain ever changes, or if the constants in `seo.ts` are updated, these will silently fall out of sync.

Consider:
```tsx
import { getBreadcrumbSchema, buildCanonicalUrl } from '../lib/seo';

getBreadcrumbSchema([{ name: 'About', url: buildCanonicalUrl('/about') }])
```

Same pattern applies to `CalendarPage.tsx` (`/calendar`) and `RankingsPage.tsx` (`/rankings`).

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "fix: address Greptile P2 feedback on PR ..." | Re-trigger Greptile

- Install vite-plugin-pwa and configure VitePWA with workbox service worker
- Add web app manifest: name, icons, screenshots, shortcuts (Calendar + Rankings)
- Generate PWA icons: 192x192, 512x512 standard + 512x512 maskable
- Generate app screenshots for install prompt
- Update index.html: PWA meta tags (apple-mobile-web-app-*, theme-color,
  application-name), default OG/Twitter tags, preconnect hints
- Add seo.ts helpers: getBreadcrumbSchema, getFaqSchema, getSportsEventSchema
- Add BreadcrumbList structured data to CalendarPage and RankingsPage
- Add BreadcrumbList + FAQ structured data to AboutPage (5 common BJJ questions)
- Workbox runtime caching: API (NetworkFirst 4h), Google Translate (CacheFirst 7d),
  Cloudinary images (CacheFirst 30d)

The site is now installable as a PWA on mobile and desktop with offline support
for previously-visited pages. Google will also show FAQ rich results on About.
@netlify

netlify Bot commented Mar 27, 2026

Copy link
Copy Markdown

Deploy Preview for marianas-open ready!

Name Link
🔨 Latest commit 10d04b1
🔍 Latest deploy log https://app.netlify.com/projects/marianas-open/deploys/69c68df21b42a100082b692f
😎 Deploy Preview https://deploy-preview-50--marianas-open.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Mar 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b2d689fb-371a-4210-8eda-ca794da73525

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/mo-seo-pwa

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jerry-shimizutech

Copy link
Copy Markdown
Contributor Author

@greptile

Comment thread web/index.html Outdated
Comment thread web/index.html Outdated
Comment thread web/vite.config.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant