What inspired me

My friends kept complaining about it, and honestly I had the same issue. After the first few months of dating, every outing starts feeling the same — the same few spots, the same rotation. You open Google, you get the same crowded places everyone else gets. You scroll TikTok for 20 minutes and end up somewhere that looked better on camera than it actually was. I felt it too with my girlfriend. Nothing ever feels like you as a couple. I wanted to fix that.

What I built

Lovetism is an AI date planner that builds personalized itineraries from your journals. You pick the vibe and budget, it does the rest. It factors in weather, your partner's preferences, and your shared history to craft a full evening that actually matches who you are as a couple. Save dates, sync with your partner, leave feedback afterward so it keeps getting better.

How I built it

  • Frontend: React 19, TypeScript, Vite, TanStack Router, Tailwind CSS, Radix UI, TipTap for rich-text journals
  • Backend: Node.js, Express 5, TypeScript
  • Database: Supabase (PostgreSQL, Auth, Storage, Row Level Security) + PostGIS for geospatial radius queries. I pre-seeded ~3,500 curated Toronto places into the database using a one-time population script across 28 grid points covering 3km of Toronto's core date neighbourhoods. Every query hits my own database first and returns results in under 100ms without touching external APIs at runtime.
  • AI: Gemini 2.5 Flash handles both itinerary generation and place enrichment. It reads both partners' synchronized journal entries, weather, and curated place data to design each date, and separately analyzed real Google reviews during the seeding phase to extract date-specific vibe labels like "cozy lighting" and "hidden gem". When two partners are linked, it reads from both journals simultaneously so the result reflects both people, not just one.
  • APIs: Google Places (autocomplete, details, photos, one-time database seeding), Google Directions API (walking and transit routes with real arrival time predictions), Google Maps JavaScript API (interactive map with custom dark styling and route display), Open-Meteo (weather-aware indoor/outdoor recommendations)

The AI picks 3 stops following a natural energy arc: opener, main event, closer. It considers tonight's weather and both partners' shared journals, and returns a fully routed itinerary with arrival times and spend estimates per stop. The app queries the local PostGIS database first for speed and cost efficiency, falling back to Google Places only when needed. A shareable Google Maps link is generated for the full route.

Challenges I faced

Personalization without leaking private data: Journals are personal. I built a three-tier visibility system (private, partner-visible, and public) so the AI only reads what each person has explicitly chosen to share. Your private notes stay private.

Place curation: The hard part wasn't finding places, it was filtering out the noise. Google returns everything including chains and tourist traps. I ran a one-time population script across 28 grid points covering 3km of Toronto's core date neighbourhoods, seeded ~3,500 quality spots (3.3+ stars, non-chain) into Supabase permanently, and used Gemini 2.5 Flash to enrich each place with vibe labels pulled from real reviews. I also built a Bayesian scoring system so a 4.6-star place with 800 reviews ranks above a 4.9-star place with 12. That suspiciously high rating with almost no reviews is almost always fake.

Partner sync: Two people needed to share a date history, rate places together, and have the AI learn from both of them. I built a sync request system and linked couple records so the shared journal grows over time and feeds back into future recommendations.

Keeping Google API costs near zero: Instead of calling Google live every time, I pre-seeded the database once and query my own Supabase first. Google only gets called as a fallback. At scale this matters a lot.

Accomplishments I'm proud of

Honestly, just shipping something that solves a problem my friends and I actually have. People I showed it to gave me great feedback, and the data layer is polished enough that I feel confident launching this as a real product. The main things left are optimizing AI costs and testing with beta users.

What I learned

Geospatial data is a completely different world. PostGIS ST_DWithin queries, geography coordinate types, and spatial indexing add real complexity but they make things possible that a regular database simply cannot do. Finding 3 cozy bars within 800m of someone's exact location, filtered by budget and vibe, in under 100ms is only possible because of PostGIS.

I also learned that how you structure the AI prompt matters as much as which model you pick. Feeding Gemini a structured context object (journals, weather, budget, vibe tags, pre-filtered verified places) produces dramatically better results than a vague open-ended prompt. The model isn't imagining places. It's making smart choices from data I trust.

What's next for Lovetism

Toronto is fully covered. Next up is Vancouver and Montreal. I'm adding post-date ratings and saved favourites that feed back into the AI, building a semantic memory layer with vector search so the system remembers your entire couple history and gets smarter with every date, and integrating live local events so every itinerary can end with something actually happening in the city tonight.

Built With

  • express.js
  • gemini2.5flash
  • google-places
  • googledirectionsapi
  • googlemapsjavascriptapi
  • groqapi(llama3.370b)
  • node.js
  • open-meteo
  • postgis
  • radix
  • react19
  • shadcn
  • supabaseauth
  • supabasepostgresql
  • supabasestorage
  • tailwind
  • tanstackrouter
  • tiptap
  • typescript
  • vite
Share this project:

Updates