Skip to content

fix(sync): allow public ICS feed through auth middleware - #11

Merged
NewWorldVenture merged 1 commit into
mainfrom
fix/public-ics-feed-auth
Jun 20, 2026
Merged

NewWorldVenture merged 1 commit into
mainfrom
fix/public-ics-feed-auth

Conversation

@NewWorldVenture

Copy link
Copy Markdown
Owner

Follow-up hotfix to #10.

The auth middleware redirected /api/sync/feeds/<token> to /login, making the public iCalendar feed unusable — Apple Calendar / Outlook / Alexa subscribe to it without a login (the unguessable feed token is the authorization). Verified live on production: a bad token returned a 307 → /login instead of a 404.

Fix: add /api/sync/feeds to the middleware PUBLIC allowlist.

🤖 Generated with Claude Code

The middleware treated everything outside the PUBLIC allowlist as protected,
so /api/sync/feeds/<token> redirected to /login — breaking the entire point
of the public feed (Apple Calendar / Outlook / Alexa subscribe with no auth;
the unguessable feed token is the authorization). Add it to PUBLIC.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 20, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
familyos Ready Ready Preview, Comment Jun 20, 2026 4:35pm

@NewWorldVenture
NewWorldVenture merged commit 868a1eb into main Jun 20, 2026
2 checks passed
@NewWorldVenture
NewWorldVenture deleted the fix/public-ics-feed-auth branch June 20, 2026 16:36
NewWorldVenture pushed a commit that referenced this pull request Jul 3, 2026
Moment reminders all fired at a blanket ~20h/2h, so a packing nudge and a
shopping nudge landed at the same unhelpful time. Now each fires when it's
actually actionable.

- Pure lib lib/moments/reminders.ts (tested, 6 cases): reminderLeadMinutes +
  reminderTimeFor pick a per-domain lead (packing → night before, shopping →
  ~2 days out, budget → 2 days, health → morning-of, photo → at the event,
  leave-by → the leave time) and clamp to now+1m so no past reminders.
- Wired into both remind paths: the Moments page and the Home "Remind me"
  button, replacing the ad-hoc 20h/2h math.

Verified: tsc clean, eslint clean on changed files, 1542 tests, next build
exit 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qnr3AA4xBTeaJ4Lrm41o7J
NewWorldVenture pushed a commit that referenced this pull request Jul 12, 2026
The rail card that prompt-routed every question to the generic assistant is now
a real marketplace specialist that answers IN the rail, grounded in the
family's live board.

- lib/marketplace/assistant.ts (pure, 9 tests): intent router (price/find/
  mine/demand/sell/fees/safety/general) + answerMarketQuestion(q, snapshot) —
  price answers run the quick-post comparables engine over the family's own
  listings; find filters by terms + budget and deep-links matching items
  (zero-hit offers a saved-search alert); "how are my listings doing" counts
  live listings + open offers; demand ranks open wanted requests by category;
  fees answers mirror the honest no-commission fee policy. marketSystemPrompt()
  builds a grounded digest (category medians, open requests, "never invent")
  for the LLM tier.
- app/(app)/marketplace/assistant-actions.ts: loads the live snapshot, then
  answers via the configured admin AI engine (resolveProvider, history-aware)
  when a key exists — any model failure falls back to the deterministic
  engine, so the panel works fully with no key and upgrades automatically.
- components/marketplace/market-assistant.tsx: in-rail chat with suggestion
  chips, reply bubbles and per-reply deep-link chips; replaces the stub card on
  the marketplace home (dead ASSISTANT_PROMPTS removed).

No new migration; grounded in existing marketplace tables (already seeded at
volume). tsc/eslint green, 2486 tests passing, next build green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018G7EyLjpFGBb9xJiGovim5
NewWorldVenture pushed a commit that referenced this pull request Oct 11, 2026
…tion receipts and delivery, one civil-time rule

Coordinator 6103529789 items 1-4 and the verified follow-up findings on #1004.

T1 (audit #18) app/api/vacations/ai/route.ts build: after generation the route
claims the trip with a compare-and-set on vacations.updated_at as read before
the model call (409 code trip_changed for the loser), re-reads the plan
(an overtaken first build answers 409 has_plan), and fences every rebuild
delete at write time on booked=false, the builder stamp and the updated_at the
row had when the family asked. A row booked, un-stamped or edited during
generation or the write phase survives; rollback restores exactly what the
delete returned. Residual (needs SQL): a request that read the trip after
another's claim while that one was still writing is not fenced; pinned in
tests/a-trip-rebuild-keeps-what-changed-meanwhile.test.ts.

T2 (audit #12) a repeated disruption returns no moves and the recorded summary;
the action passes alreadyApplied/previouslyNotified and the receipt says
"already on the itinerary" instead of an 18:00->20:00 move that never happened.

T3 (audit #12/#1) notification delivery is tracked apart from the re-flow: a
"[family notified]" stamp on the disruption note, written after notify()
accepts; notify() is keyed per disruption (trip:disruption:note) with once, so
a failed or interrupted notice is sent by the retry exactly once and the
itinerary does not move again.

T4 (audit #7/#8/#10/#13/#16) lib/time/civil.ts: one grammar and one rule
(RFC 5545 3.3.5, the calendar's) for datetime-local inputs, reminders and
school/sports windows: fractions read on the family clock, impossible dates
refused, seconds kept, folds -> first instant everywhere, gaps -> offset before
the gap, a midnight-gap day starts at the jump (America/Santiago,
Asia/Beirut). fetchForecast treats a missing end_date as start_date.

L-trips-1 (#18) buildPlan stamps the concierge marker; the 409 says whether a
rebuild replaces anything and the client asks "add alongside?" otherwise.
L-trips-2 (#17) disruption rollback deletes only created days that hold no
item (day_id is ON DELETE CASCADE).
L-trips-3 (#11) trip zones stored by canonical IANA name (create form, editor,
findOrCreateVacation); abbreviations and offsets refused.
L-trips-4 (#13) overview weather card reads only in-trip days for both its
empty state and its advice.
L-trips-5 (#22) a first concierge message creates its conversation only after
the model answered.
L-trust-1 (#2/#6) dryRunGate and execute.ts gate() share readSkipsTrustGate;
the dry run passes sensitiveRead.
L-trust-2 (#6) insights kinds school/sports/trips and household search's trip
sources follow the same view rule; the "private to the adults" comments now
say what is true.
L-trust-3 (#2) the gate comment names which household rules can lift a
private-read denial for the AI actor (role/everyone/AI policies, not
per-member grants or delegations).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K

This branch was successfully deployed

1 active deployment
Preview — 10e714e8 Deployed Jun 20, 2026 by vercel[bot]
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