Skip to content

Version history

Changelog

This is a public log of every notable change to weeklyescapes. We update it for each meaningful release. Format inspired by Keep a Changelog with our own commentary on why decisions were made.

Changelog

All notable changes to weeklyescapes are documented here.

2026-05-19 (evening, fifth batch)

Added: Smart "Switch to Hotel or resort" CTA when apartments return zero rates

Real cause discovered while auditing LiteAPI: many vacation rentals listed on LiteAPI (Booking.com Holiday Rentals, individual host inventory) appear in /listings but don't have API-bookable rates for short stays. Tempe Sep 1-8 with property_types=extended_stay returns 0 of 5 apartments with rates from LiteAPI; same query with property_types=hotels returns 3 of 5 with rates.

When /listings/rates returns zero rates AND user picked extended_stay, the empty state now shows a one-click switch:

No availability found for these dates. Try shifting your dates or

different properties. Switch to Hotel or resort → Vacation rentals

often don't sell instantly via API.

If user already on hotels filter and gets zero, suggests "Show all property types →". Keeps the funnel unblocked without auto-changing user intent. Documented as Decision S28 in decisions-log.

2026-05-19 (evening, fourth batch)

Added: Children + property type filter UI on /search

Audited LiteAPI documentation systematically (every endpoint in https://docs.liteapi.travel/reference). Identified three improvements based on the audit:

1. Children support in occupancies. LiteAPI accepts children as an array of ages, e.g. [3, 7] for two children aged 3 and 7. We were only passing adults. Now /listings/rates accepts a children list and threads it into the LiteAPI body. Frontend has "Children" dropdown that conditionally renders N age inputs (0-17 each).

2. Property type filter UI on /search. Hardcoded extended_stay default was hidden under URL param. Now there's a "Stay type" dropdown:

  • Apartment or villa (default, per Decision S21)
  • Hotel or resort
  • Show all

Selection threads through to /listings hotelTypeIds filter.

3. Better empty-state handling for stays >30 nights. LiteAPI returns error code 2001 'no availability found' when stay duration exceeds supplier max stay (often 28-30 nights). We detect this and surface a helpful availability_note field. UI shows: "Most properties cap stays at ~30 nights via API. Try splitting your trip."

Also added maxRatesPerHotel: 3 to keep response sizes manageable (LiteAPI default unlimited, can return 1MB+ per hotel) and refundable_only opt-in for travelers wanting cancellable rates only.

Created docs/spec/liteapi-reference.md (519 lines) as comprehensive endpoint catalog covering all primary endpoints, request/response shapes, error codes, performance characteristics, account-manager-enabled features, and how-to-test recipes. Source of truth for our LiteAPI integration.

2026-05-19 (evening, third batch)

Added: Cooler Sign-in pill button + homepage Day 3 status

  • Sign-in changed from inconspicuous link to amber pill button
  • (px-4 py-1.5 rounded-full bg-ink hover:bg-amber)

  • Homepage hero updated: "Pre-launch" → "Building in public · Day 3";
  • removed waitlist signup form, replaced with two clear CTAs: - "Search stays now →" (primary, dark) → /search - "Create a free account" (secondary, outline) → /sign-up

  • Homepage "What's actually built" list updated to reflect reality:
  • search/listings/rates/booking-sandbox/auth/dashboard all checked, production cutover in-progress, V2 items as TODO

Updated: README + Steering doc

README.md fully rewritten for Day 3 state with 17-row status table, current API endpoint list, full repo structure with all routes. Steering doc updated with current product surface, S17-S27 summary, API endpoints v0.6.0, /weeklyescapes/auth/* SSM namespace.

2026-05-19 (afternoon, third batch)

Added: User dashboard V1 — Clerk auth + bookings list

Per Decision S27, full V1 dashboard ships:

  • Clerk authentication via @clerk/clerk-js CDN script (Google OAuth, Apple
  • OAuth, passkeys, email magic link; no passwords)

  • /sign-in, /sign-up pages mount Clerk components client-side
  • /account dashboard shows: profile, trips list, loyalty placeholder
  • Header has auth-aware area: "Sign in" link → UserButton when signed in
  • Email-as-identity design: bookings keyed on holder.email so anonymous
  • bookings auto-link when user signs up with same email later

Backend:

  • lib/clerk.py verifies Clerk session via their API (no JWT lib bundled)
  • lib/bookings.py provides DynamoDB save/list/upsert helpers
  • New endpoints: GET /api/me, GET /api/bookings (both Clerk-auth required)
  • POST /book/finalize now writes BOOKING# records to DynamoDB
  • Health bumped to v0.6.0

SSM:

  • New params: /weeklyescapes/auth/clerk-publishable-key, /weeklyescapes/auth/clerk-secret-key
  • IAM policy extended to grant Lambda read access to /weeklyescapes/auth/*

Frontend:

  • Layout.astro injects Clerk script + has auth-aware header
  • New pages: /sign-in, /sign-up, /account
  • New scripts/fetch-auth.sh pulls publishable key from SSM, writes to
  • frontend/.env at deploy time, picked up by Astro's import.meta.env

  • frontend/.env gitignored

What's NOT in V1 (queued for V2)

  • Email confirmations from us: requires SES production access (24-48hr
  • Amazon review). Customers still get Nuitee's confirmation email today.

  • LiteAPI loyalty points display: shown as placeholder on /account.
  • Requires LiteAPI dashboard config (guest tiers + perks per tier) and loyaltyGuestId passthrough in prebook.

Test in browser

1. Visit https://weeklyescapes.com/sign-in/ 2. Sign in via Google/Apple/passkey/email link 3. Land on /account — should show profile + "No trips yet" 4. Optionally redo sandbox booking with your signed-in email as holder to see it appear in trips list

2026-05-19 (afternoon, second batch)

Added: Open destination search (any country + any city)

Per Decision S23, the 10-city dropdown is gone. /search now lets users pick any country (~65 popular travel countries) and type any city name. LiteAPI has inventory globally; we just weren't surfacing it.

Live results from open search:

  • ?country=US&city=Tempe returns Tempe Studios, Tempe Lofts, ROVE LIVING,
  • holiday homes near ASU

  • ?country=IN&city=Goa returns Alaya Stays apartments with pool
  • ?country=GR&city=Mykonos, ?country=US&city=Phoenix, etc. — anywhere
  • LiteAPI has inventory

Backend:

  • routes/listings.py accepts EITHER city= (existing curated shortcuts
  • for backwards compatibility) OR city_name=&country_code=<2-letter ISO> (new open search)

  • sources/liteapi.py search_listings_open() handles direct city_name +
  • country_code queries; uses extended_stay property type filter by default

Frontend (/search.astro):

  • Country dropdown with ~65 popular travel countries (alphabetical, ISO codes)
  • City as free text input
  • Form layout went from 6 columns to 7 on desktop, gracefully stacks on mobile
  • KNOWN_AIRPORTS map of ~80 city → IATA pairs powers the flight lookup
  • For cities without a known airport, flight section degrades gracefully:
  • "Pick a major airport for flight prices, or browse stays below"

  • Suggested-trip pills now include Tempe (US), Goa (India), Mykonos (Greece)
  • alongside the original curated 10

  • Old URLs (?destination=lisbon) still work — auto-resolved to country + city

Tradeoffs:

  • Two form fields (country + city) instead of one dropdown. Worth it for
  • global reach.

  • City guides (per requirements.md G3) remain on the curated 10 only. Open
  • search shows listings only, no editorial.

  • KNOWN_AIRPORTS is hand-curated; obscure cities show hotels but no flights.
  • Honest UX, no fabricated airport guesses.

2026-05-19 (afternoon)

Added: Apartment + villa filter on /listings (default for extended-stay focus)

This is a major positioning shift. Before today, /listings?city=lisbon returned 20 hotels because we never filtered LiteAPI's inventory by property type. LiteAPI actually has 52 property types: apartments, villas, holiday homes, condos, country houses, gites, chalets, cottages, even houseboats and castles.

Per Decision S21, /listings now defaults to property_types=extended_stay, which filters to apartment-style accommodations appropriate for 7+ night stays: Apartments, Residences, Villas, Aparthotels, Holiday homes, Homestays, Country houses, Chalets, Condos, Cottages, Gites, Riads, Vacation homes, Cabins, Houseboats, Castles, Palaces, Guest houses

Live results:

  • Lisbon now returns real apartments: Lisbon Art Stay, Martinhal, Lisbon
  • Colours Bairro Alto, Almaria Ex Libris (instead of just hotels)

  • Bali returns real villas: Aleesha Villas, Villa D'Carik Bali, Sorrento
  • Villa, Villa Reina, Luxury Nanda Villa Ubud

  • Each card shows a property type badge: "Apartment", "Villa", "Holiday home"

Backend (sources/liteapi.py):

  • HOTEL_TYPE_LOOKUP (52 entries from /v3.0/data/hotelTypes)
  • EXTENDED_STAY_TYPE_IDS, HOTEL_ONLY_TYPE_IDS, PROPERTY_TYPE_SETS
  • get_hotels_in_city() accepts hotel_type_ids list, passes as
  • comma-separated hotelTypeIds to LiteAPI server-side filter

  • normalize_hotel() includes hotel_type and hotel_type_id

Backend (routes/listings.py):

  • Accepts property_types query param (extended_stay | hotels | all)

Frontend (/search.astro):

  • Property type badge above each hotel name (amber pill, e.g., "Apartment")
  • singularPropertyType() helper converts plural ("Apartments") to
  • singular ("Apartment") for display

Documented: Uber + eSIM addons (S22, deferred to V2)

LiteAPI supports attaching Uber vouchers ($10-$100 increments) and eSIM data packages to bookings via addons array during prebook. Customer pays on top of the room rate; non-refundable. Documented in Decision S22 with the full implementation spec for when V2 booking flow lands. Not building tonight; the manifesto is delivered at V1 without addons.

URLs to test

  • https://weeklyescapes.com/search?origin=LAX&destination=lisbon — apartments + guest houses
  • https://weeklyescapes.com/search?origin=LAX&destination=bali — villas + guest houses
  • https://api.weeklyescapes.com/listings?city=lisbon&property_types=hotels — opt into hotels only
  • https://api.weeklyescapes.com/listings?city=bali — defaults to extended_stay (villas)

2026-05-19 (morning)

Added: Exclusive Rates + Perks + Promotions support (graceful empty states)

LiteAPI offers three additional feature surfaces beyond standard rates:

  • Exclusive Rates: privately negotiated hotel prices with strikethrough original-vs-discounted display (retailRate.initialPrice vs retailRate.total)
  • Exclusive Perks: value-added benefits (breakfast, upgrades, property credits) tied to loyalty tiers
  • Promotions: campaign metadata with discount %, date range, name (e.g., "Early Booker Deal")

Per Decision S20 in decisions-log.md, we now extract and display all of these on every rate. Currently the response fields are empty (LiteAPI account manager needs to enable Exclusive Rates + Perks for our account), but the implementation is in place so that the moment the switches flip, the badges and perks list appear automatically without a code change.

Backend (sources/liteapi.py normalize_rate):

  • Extracts initialPrice, promotions, perks from each rate
  • Computes is_exclusive (when initialPrice > total)
  • Computes exclusive_savings + exclusive_savings_pct
  • Computes perks_total_value (sum of all perks amount fields)
  • Top-level guest_level from guestLevel passed through

Frontend (/search.astro buildRateBlockHtml):

  • "★ Exclusive rate" amber badge when is_exclusive: true
  • Strikethrough original price next to discounted total
  • "Save $X (Y%) with [Promotion Name]" line when promotions populated
  • Perks checklist with total value: "Included perks ($220 value): ✓ Daily breakfast for 2 ($40 value), ✓ Room upgrade ($60 value), ..."
  • Empty states render cleanly (no orphan headers when perks/promotions absent)

Frontend (/book/test.astro step 1 output):

  • Shows all new fields in the test JSON output for visibility while debugging

Action item for the user

Email your LiteAPI account manager to enable: 1. Exclusive Rates for our account 2. Exclusive Perks / Loyalty Program with guest tiers and per-tier perks

Both are eligibility-gated. Once enabled, the savings badges and perks lists appear automatically on /search hotel cards.

2026-05-18 (late late evening)

Added: V1.5 booking flow with LiteAPI User Payment SDK (SANDBOX ONLY)

Implements the full LiteAPI booking flow on weeklyescapes.com using their User Payment SDK, where the customer enters their card on our page (in their iframe) and Nuitee/LiteAPI is the merchant of record. This is per Decision S19 in decisions-log.md.

Tonight: sandbox-only deployment. Production cutover is deliberately deferred to a fresh session tomorrow. We never want to ship a payment-taking code path written tired.

Backend (Lambda v0.5.0-sandbox):

  • New endpoint: POST /book/prebook
  • - Body: {offer_id, mode} - Calls LiteAPI /v3.0/rates/prebook with usePaymentSdk: true - Returns {prebook_id, transaction_id, secret_key, hotel, room_types, ...}

  • New endpoint: POST /book/finalize
  • - Body: {prebook_id, transaction_id, holder, guests, mode} - Calls LiteAPI /v2.0/rates/book with payment.method: TRANSACTION_ID - Returns {booking_id, confirmation_number, hotel, ...}

  • Both default to mode: sandbox for safety
  • LiteAPI client extended with prebook() and finalize_booking() plus mode-aware
  • key selection (liteapi-sandbox-key SSM param vs liteapi-key)

  • /listings/rates extended with mode parameter for sandbox testing chain

Frontend:

  • /book/test.astro — hardcoded sandbox test booking flow
  • - Prominent SANDBOX MODE banner at top - Step 1: fetch sandbox rate for Meliá Lisboa (4 nights) - Step 2: holder details form (pre-filled with test data) - Step 3: LiteAPI payment SDK loads in our page (iframe, we never touch cards)

  • /book/confirm.astro — booking finalization page
  • - Reads tid + pid from URL params (set by SDK after payment) - Reads holder/guest details from sessionStorage - Calls /book/finalize to confirm booking - Shows confirmation page with booking number, dates, total, supply chain disclosure - Honest "what happens next" block explaining Nuitee = merchant of record

Verified end-to-end (curl):

  • POST /book/prebook with sandbox offer_id returns valid prebook_id, transaction_id, secret_key
  • Sandbox key separate from prod (so /listings + /listings/rates keep using prod for real users)

Manual test still pending (requires browser):

  • Full flow with test card 4242 4242 4242 4242 from /book/test through SDK
  • payment to /book/confirm finalization. This is the next step.

Production cutover plan (tomorrow):

  • Switch DEFAULT_MODE in routes/book.py from "sandbox" to "production"
  • Update /book/test or build /book customer-facing page with prod mode
  • Wire "Book this stay" button on /search top 5 hotels
  • Test with own card on real low-cost hotel (cancellable rate)
  • SES production access for confirmation emails (request now, lands in 24-48 hrs)

2026-05-18 (late evening)

Added: V1 trip planner with live LiteAPI rates + total trip cost

The /search rebuild now ships the full manifesto promise: real total trip cost, real savings vs competitors, real commission disclosed per result.

Backend changes (Lambda v0.4.0):

  • New endpoint: POST /listings/rates
  • - Body: {hotel_ids, check_in, check_out, adults, currency} - Calls LiteAPI /v3.0/hotels/rates and normalizes the response - Returns per hotel: lowest_total, lowest_per_night, currency, supplier, room_name, board_name, competitor_price (booking.com), competitor_source, savings_vs_competitor, commission

  • LiteAPI client extended with get_hotel_rates() and normalize_rate()
  • Health endpoint reports both GET and POST endpoints

Frontend changes:

  • After /listings resolves, frontend takes top 5 hotels by rating, fires
  • POST /listings/rates for those 5 in a background fetch

  • Top 5 hotel cards show "Loading live rate from LiteAPI…" skeleton, replaced
  • with real per-night + total + competitor comparison + savings + commission

  • Trip header gains an estimated total trip cost panel: flight cost + cheapest
  • stay cost, with savings vs booking.com when applicable

  • Honest commission line: "We earn $297.18 commission if you book this stay
  • (5.7%)." Real number, not estimate

  • For the bottom 15 hotels (no rates fetched), keep V0 metadata + Google
  • Hotels "Compare rates" link with V0 disclosure

Real numbers from the live site (LAX → Lisbon, 30 nights, 2 adults):

  • Meliá Lisboa Aeroporto: $175.01 / night, $5,250.25 total
  • Booking.com price for same room: $6,260.68
  • Savings: $1,010.43 (16.1%)
  • Our commission: $297.18 (5.7%)

V1.5 (next): wire booking flow to LiteAPI whitelabel. Currently "Compare rates →" still links to Google Hotels; we earn LiteAPI commission only once we have the booking flow integrated. Disclosure makes this clear.

2026-05-18 (evening)

Added: /search rebuild as combined trip planner (V0)

Replaced the flight-only /search with a unified trip planner showing both flights and housing for the same trip. Per Decisions S17 (frontend-combined architecture) and S18 (hybrid rates strategy: V0 metadata, V1 top-5 rates) in decisions-log.md.

What's live:

  • Form: From (3-letter IATA) + To (10 city dropdown) + Check-in + Check-out + Adults
  • Parallel fetches to /flights and /listings on submit
  • Trip header: "LAX → Lisbon, Aug 1 to Sep 1, 31 nights, 2 adults"
  • Flight section: cheapest cached price (real), airline, duration, commission disclosure (~1.5% Travelpayouts), "Book on Aviasales →" with marker 729501
  • Hotel section: 20 LiteAPI cards with photo, name, stars, rating, review count, address, description preview, "Find rates →" linking to Google Hotels search
  • Honest V0 disclosure: "No commission yet on this link, partnerships pending" (because CJ Booking.com is in flight and LiteAPI whitelabel isn't wired yet)
  • Mobile responsive, manifesto block at bottom

What's V1 (next session):

  • New POST /listings/rates endpoint for top-5 hotels (single LiteAPI rates call, ~3s)
  • Inline per-night and total stay prices for top 5
  • Calculated total trip cost = flight + cheapest stay
  • Real commission amounts for hotels once we have rates

Spec changes documented

  • decisions-log.md: Added S17 (frontend-combined trip planner) + S18 (hybrid rates strategy)
  • requirements.md: Non-goal "Flight search / booking" replaced with finer-grained non-goals. Flight booking on weeklyescapes.com itself remains out of scope (we always redirect). Flight search as the primary product remains out of scope (housing is primary). Flight prices alongside housing for total trip cost transparency is now in scope.
  • tasks.md: Task 7 rewritten with V0 + V1 task breakdown
  • research-log.md: Documented brainstorm research (10 web searches, LiteAPI docs deep read, lastminute.com architecture article, Hipmunk failure analysis, Going.com history)

Backend change

  • LiteAPI city lookup (infra/lambda/api/sources/liteapi.py) extended with airport field per city. Frontend uses this to map destination city slug to flight destination IATA automatically.

2026-05-18 (afternoon)

Added: /api/listings endpoint with real hotel data

Built /listings Lambda endpoint backed by LiteAPI. Returns real hotel inventory for our 10 launch cities (Lisbon, Porto, Mexico City, Bangkok, Chiang Mai, Bali/Denpasar, Medellín, Tbilisi, Buenos Aires, Cape Town).

Each result includes: hotel name, address, star rating, guest rating, review count, coordinates, main photo URL, description preview. Source: LiteAPI (sandbox key, but returns real production hotel data for content; sandbox applies only to bookings).

Live examples: curl https://api.weeklyescapes.com/listings?city=lisbon&limit=3 curl https://api.weeklyescapes.com/listings?city=bangkok&limit=5

Refactored Lambda from single-file to proper package

Lambda code now structured as:

infra/lambda/api/
├── index.py              # entry point, dispatches to routes
├── routes/
│   ├── health.py
│   ├── flights.py
│   └── listings.py
├── sources/
│   ├── travelpayouts.py
│   └── liteapi.py
└── lib/
    ├── http.py           # response helpers (json_response, error_response)
    └── ssm.py            # cached parameter retrieval

This is the production pattern, not research-grade single-file. Each endpoint stays under 100 lines, sources are testable in isolation, shared concerns (HTTP, SSM) live in lib/.

Updated IAM policy

Lambda now has SSM read access to BOTH:

  • /weeklyescapes/affiliates/* (existing)
  • /weeklyescapes/hotel-apis/* (new, for LiteAPI key)

Bumped API version

  • /health now reports v0.3.0
  • Lists all three endpoints: /health, /flights, /listings

2026-05-18 (Day 1 continued, late night)

Added

  • /flights endpoint at api.weeklyescapes.com, returns cheapest flight prices
  • via Travelpayouts API. Token kept server-side, only formatted results returned to client.

  • API Lambda code moved from inline to infra/lambda/api/index.py.
  • IAM policy: Lambda can now read /weeklyescapes/affiliates/* from SSM.
  • API version bumped to 0.2.0.

Verified working

  • GET /flights?origin=LAX&destination=LIS returns real flight data (~$794)
  • GET /flights?origin=JFK&destination=CDG returns real flight data (~$431)
  • Token authentication via X-Access-Token header (server-side only)
  • Validation errors return helpful messages
  • 5-minute Cache-Control on responses

Affiliate signups

  • CJ Affiliate publisher account approved (PID: 7961481)
  • Applied to 6 CJ advertisers: Booking.com, Hotels.com, Priceline, Travelex,
  • TripAdvisor Commerce, CheapOair (pending advertiser approval, 1-7 days)

  • Travelpayouts signup complete, API token verified working
  • Coliving slug confirmed: nick-f-4
  • Outsite application submitted via Refersion (pending review)
  • Email sent to support@travelpayouts.com requesting Hotel Search API access

Infrastructure (NFLO Marketing LLC business setup)

  • Mercury bank account application started
  • LLC business info documented for affiliate signups

Secrets in SSM (us-east-2)

  • /weeklyescapes/affiliates/cj-pid (7961481)
  • /weeklyescapes/affiliates/travelpayouts-token (verified)
  • /weeklyescapes/affiliates/travelpayouts-marker (729501)
  • /weeklyescapes/affiliates/coliving-slug (nick-f-4)

Documentation (gitignored, local-only)

  • docs/spec/travelpayouts-api-reference.md, full API endpoint catalog by
  • access tier, auth patterns, rate limits, /search architecture

  • .secrets/cj-affiliate-agreement.md, CJ publisher agreement TL;DR

API endpoint discovery

Working without application:

  • /v1/prices/cheap (used by /flights)
  • /aviasales/v3/grouped_prices (calendar of cheap flights by date)
  • /finance/v2/get_user_balance (for /stats real revenue display)
  • /data/cities.json (full airport database)

Gated, application sent:

  • Hotel Search API (real-time hotel prices), 9% conversion threshold,
  • approval typically 2-4 weeks

Out of reach for now:

  • Aviasales Real-time Search API requires 50k MAU minimum

Format: Keep a Changelog inspired but adapted for indie SaaS pre-launch tracking.

Updates flow into the public /changelog page eventually (per transparency-framework.md).

---

[Unreleased] — 2026-05-17

Added — afternoon updates

  • Google Workspace email setup
  • - Added weeklyescapes.com as a User Alias Domain for virtualhomezone.com (free, no extra license) - Added Google verification TXT record to Route 53 - Swapped MX records: removed ImprovMX (10/20 priority), added 1 smtp.google.com. - Updated SPF: v=spf1 include:_spf.google.com ~all - Added DKIM record at google._domainkey.weeklyescapes.com (2048-bit RSA, properly chunked into 250+158 char strings) - Configured Gmail "Send mail as" for nick@weeklyescapes.com (verified) - Effect: can send + receive from @weeklyescapes.com addresses through main Gmail inbox - ImprovMX decommissioned — Google Workspace handles all email now

  • Coliving.com partnership outreach
  • - Email sent to partners@coliving.com from nick@weeklyescapes.com - Subject: "Coliving.com partnership inquiry" - Asks: production API access, confirmation of 50% rev-share, co-marketing once traction - Offers: SEO pages, qualified high-intent traffic, public case study, designed integration - Lead time: typical 1-3 weeks for partnership replies - Follow-up reminder: 7 business days if no response

Built today (Day 1 of building)

Strategy & spec (~7,500 lines, 17 docs)

  • manifesto.md — soul of the project: "give money back to people, make corporations pay"
  • research-process.md — research-driven decision methodology with N≥3 working/failing examples
  • research-log.md — every research session tracked
  • decisions-log.md — 16 documented decisions (S1–S16) with citations
  • business-model-analysis.md — pricing model with full pros/cons + DMAI framework
  • brand-style-guide.md — visual identity locked (colors, typography, voice, anti-palette)
  • brand-assets.md — single source of truth for domain, social handles, email
  • Updated: README, requirements, design, tasks, integration-strategy, monetization-setup, transparency-framework, validation-evidence

Domain & DNS

  • Registered weeklyescapes.com via Route 53 ($13/year, auto-renew on, privacy enabled)
  • Hosted zone: Z07606942A3I74LM0DCGL
  • Email forwarding via ImprovMX (free): catch-all *@weeklyescapes.comnsflournoy@gmail.com

Social handles claimed (4/5)

  • ✅ X (Twitter): @weeklyescapes
  • ✅ Instagram: @weeklyescapes
  • ✅ Bluesky: weeklyescapes.bsky.social
  • ✅ Reddit: u/weeklyescapes
  • ⏳ TikTok: pending verification code issue

AWS infrastructure deployed (5 stacks)

  • weeklyescapes-data — DynamoDB single-table with PITR + GSI1
  • weeklyescapes-api — Lambda + API Gateway HTTP API + custom domain
  • weeklyescapes-frontend — S3 + CloudFront (us-east-1) + Route 53 alias
  • weeklyescapes-messaging — SES domain identity with DKIM
  • weeklyescapes-monitoring — CloudWatch budget alarms ($25 / $50)

Live URLs

  • https://weeklyescapes.com — placeholder with manifesto quote
  • https://api.weeklyescapes.com/health — returns {"status":"ok","version":"0.1.0"}

X API integration

  • X developer account approved
  • 7 tokens stored in AWS SSM Parameter Store as SecureString (encrypted, free tier)
  • Path: /weeklyescapes/x/*
  • OAuth 1.0a verified working (authenticated as @weeklyescapes)
  • Bearer token valid (free tier endpoint limits expected)

Brand identity

  • Color palette locked: Ink #0f172a, Cream #fafaf7, Amber #d97706
  • Typography locked: Inter (body + headlines), Fraunces (editorial), JetBrains Mono (data)
  • Logo SVGs created (4 variants): wordmark, wordmark-horizon, monogram, favicon
  • PNG exports for social profile pictures (400×400, 1024×1024, 180×180 Apple touch, 32×32 favicon)

Code repository

  • Git initialized; SSH deploy key configured for weeklyescapes/weeklyescapes
  • All work pushed to https://github.com/weeklyescapes/weeklyescapes
  • Comprehensive .gitignore protects .secrets/, .venv/, cdk.out/, node_modules/, env files
  • Audited: no leaked AWS keys, no leaked credentials in tracked files

Tooling installed

  • AWS CDK 2.1122.0 (local, ~/.local/npm/bin)
  • Python deps: cairosvg, requests-oauthlib, boto3 (in workspace .venv)

Decisions committed today (S1–S16)

See docs/spec/decisions-log.md for full reasoning + research citations.

| ID | Decision | Status | |---|---|---| | S1 | Sequenced launch (weeklyescapes → mistfare → pointssearch) | Active | | S2 | Family Slowmad as secondary persona | Active | | S3 | TikTok as Channel 1 (1-2 high-quality videos/week) | Active | | S4 | No cold-email host outreach (legal/brand risk) | Active | | S5 | Cross-platform comparison engine (Phase 2) | Active | | S6 | Watchlist as v1 of mistfare | Active | | S7 | "Anywhere" search as v1 of weeklyescapes | Active | | S8 | Multi-passenger optimization in pointssearch v1 | Active | | S9 | Real-time public stats counters | Active | | S10 | Auth: Clerk + social OAuth + passkeys | Active | | S11 | B2B Corporate Travel Partnership (Year 2+, OBA-gated) | Roadmap | | S12 | Frontend: Astro 6 hosted on AWS S3+CloudFront | Active | | S13 | Payments: Paddle as Merchant of Record | Active | | S14 | Pricing: Hybrid (free + $49/yr Pro + B2B) | Active | | S15 | Subscriber Stipend (sponsor-funded) | Year 1.5+ | | S16 | Two-track inventory (consumer = all sources, B2B = policy-compliant only) | Active |

---

How to update this file

When you make a meaningful change: 1. If it's substantive (decision, deploy, new asset), add a bullet under [Unreleased] 2. When we ship a real version (v0.1.0+), move the unreleased items into a versioned release section 3. The public /changelog page on weeklyescapes.com pulls from this file

Keep the entries factual and dated. Per the manifesto: show our work.


Want to know what's coming? See /decisions for major upcoming choices, or /building for daily progress.