Events integration with Luma
How the OwnersClub.ai events page renders the Owners Club Luma calendar as a static-first build-time snapshot, including how it was built and how to update it.
eventslumaintegrationstatic-site
Events integration with Luma
The public Events page lists Owners Club events. It renders the OwnersClub.ai Luma calendar from a build-time snapshot so the site stays static-first — no server, worker, or client-side fetch is required.
What was built
- Luma-style event card on the Events page: cover image, date badge (e.g. 14 OCT), event title, full date/time range with timezone (e.g. Wednesday, October 14 at 6:00 PM – 7:30 PM PDT), host (Hosted by Jim White), attendee count (9 going), and a Register button.
- A Build-time fetch script that pulls the live Luma calendar into a static JSON file.
- The page renders the events statically in the HTML — no runtime dependency.
Why it is static-first (the decision)
Luma's feeds return no CORS headers (access-control-allow-origin is absent), so a browser cannot call Luma directly, and the calendar page sends X-Frame-Options: SAMEORIGIN (blocking iframe embeds too).
The first attempt used a Cloudflare Worker proxy (/api/luma/events) to fetch Luma server-side. That worked, but it introduced a server-side dependency, which conflicts with the project's static-first, low-infrastructure goal. Per the owner's direction, the fetching was moved into a build step instead, and the Worker proxy was removed. The result is fully static.
How it works
scripts/fetch-events.tsfetches the public Luma calendar page (https://luma.com/OwnersClub, calendar idcal-z8KtuzZE6ak7suU) and its iCal feed at build time, parses the event data, and writesapps/site/src/data/luma-events.json.pnpm buildrunspnpm fetch:eventsfirst, so the snapshot is regenerated on every build.- The Events page imports that JSON statically at build time and renders each event as a card.
- The snapshot file is gitignored (generated output) — it is not committed.
Key files
| File | Role |
|---|---|
scripts/fetch-events.ts |
Build-time fetcher + parser (calendar JSON + iCal fallback) |
apps/site/src/data/luma-events.json |
Generated static snapshot (gitignored) |
apps/site/src/pages/events/index.astro |
Renders the static card; imports the JSON |
apps/site/src/styles/global.css |
.event-card, .event-cover, .event-date-badge, .event-action styles |
package.json |
build runs fetch:events; fetch:events = tsx scripts/fetch-events.ts |
knowledge/events/README.md |
Documents the locally-authored event model |
Directions for future updates
Refresh the events (re-run the snapshot)
- Run
pnpm fetch:eventsto regenerate the JSON from Luma, or just runpnpm build(which does it automatically). - The site is static, so the events only change when the build runs. Luma is the source of truth; this repo does not author the live events.
Preview before committing (owner workflow)
- Because this is static-first,
pnpm dev(Astro dev server, port 4321) is the correct preview — no Worker needed. The oldpnpm --filter @ownersclub/worker dev(port 8787) was for the removed proxy and is no longer required. - The owner does not run CLI commands. For review, start the dev server and open the page in the browser for them; they confirm visually before any commit/publish.
Change the card style or fields
- Edit
apps/site/src/pages/events/index.astro(the card markup and date/host/going formatting). - Edit
apps/site/src/styles/global.cssfor styling. - Rearrange or add fields by extending the event object in
scripts/fetch-events.tsand the frontmatter in the page.
If Luma is unreachable at build time
- The fetch script logs a warning and writes an empty event list rather than failing the build, so the site still builds.
Constraints
- Do not invent events — only real, confirmed events from the live Luma calendar.
- Do not commit the generated
luma-events.json(it is gitignored). - Do not reintroduce a server/worker dependency for event fetching — keep it static-first.
- The site lists events and links out to register on Luma; it does not host registration.