5 min read

SmartCal

Next.jsPrismaPostgreSQLGeminiNextAuthPlaywright

Database models

  • User — central user entity with handle-based public booking pages
  • ConnectedCalendar — OAuth integration for Google Calendar with token management
  • ExternalEventMapping — maps internal booking IDs to external calendar event IDs
  • CalendarBusyBlock — cached busy time blocks from external calendars
  • EventType — configurable booking types with duration, buffer times, and AI settings
  • Booking — actual meetings with host/invitee details, status tracking, and AI agenda generation
  • AvailabilityRule — configurable working hours, buffer times, booking limits
  • RescheduleRequest — tracks rescheduling requests with AI-suggested alternatives

Authentication & Google Calendar OAuth

  • NextAuth.js integration with Google OAuth provider, automatic user handle generation from email, JWT-based session management with 30-day expiration
  • OAuth2 client management with automatic token refresh (5-minute buffer before expiry), calendar connection API, primary calendar selection, and a sync API for fetching and caching busy time blocks
POST   /api/auth/google-calendar/connect
GET    /api/auth/google-calendar/connect
PATCH  /api/auth/google-calendar/connect/primary
POST   /api/auth/google-calendar/sync
DELETE /api/auth/google-calendar/sync

Core utilities live in /src/lib/calendar/google-calendar.ts (createOAuth2Client, refreshAccessToken, getValidOAuth2Client, createCalendarEvent, updateCalendarEvent, deleteCalendarEvent, getFreeBusy, listCalendarEvents, getPrimaryCalendarId) and /src/lib/utils/timezone.ts (timezone detection, validation, and conversion between IANA identifiers and UTC).

Availability calculation engine

The core scheduling logic lives in /src/lib/availability/calculate-availability.ts:

  • calculateAvailability() — main function that computes available slots
  • createTimeIntervals() — creates time intervals based on availability rules
  • isWithinAvailabilityRule() — checks if time falls within defined rules
  • checkIntervalAvailability() — validates intervals against bookings and busy blocks
  • formatAvailableSlotsForDisplay() / getAvailableSlotsByDay() — formats and groups slots for the frontend

Booking management sits in /src/lib/booking/create-booking.ts (createBooking, cancelBooking, getBookingByUid, getUpcomingBookings, getBookingCountForDate) and /src/lib/booking/booking-utils.ts (slot generation, date formatting, gap-finding between busy blocks, and slot validation against event-type constraints).

POST   /api/availability - Calculate availability for booking
GET    /api/availability - Get availability with default parameters
POST   /api/bookings - Create a new booking
GET    /api/bookings - Get bookings (by UID or upcoming for user)
DELETE /api/bookings - Cancel a booking

Key algorithms:

  1. Availability calculation merges database availability rules with external calendar busy blocks, handles buffer times before and after existing bookings, validates against daily/weekly booking limits, and respects minimum/maximum lead time constraints.
  2. Time slot generation creates 30-minute intervals, applies availability rule filters (days of week, time ranges, exclusions), and generates gaps between busy blocks.
  3. Booking validation checks slot availability, event type constraints, and overlap with existing bookings and calendar events.

AI natural language parser (Gemini)

/src/lib/ai/ai-client.ts is an OpenAI-compatible interface wrapping Gemini models (chatCompletion, streamChatCompletion, healthCheck), and /src/lib/ai/nlp-parser.ts handles the actual parsing: parseBookingRequest, suggestAlternativeTimes, generateMeetingAgenda, detectTimezoneFromMessage, validateTimeSuggestion.

POST   /api/ai/parse-booking - Parse natural language booking request
POST   /api/ai/reschedule-suggestions - Generate AI-powered reschedule alternatives
PATCH  /api/ai/reschedule-suggestions - Accept/decline reschedule request
POST   /api/ai/generate-agenda - Generate meeting agenda from notes
GET    /api/ai/generate-agenda - Get existing agenda

Natural language booking: intent recognition (book, inquire, reschedule, cancel), relative and absolute date/time extraction (“next Tuesday”, “tomorrow 2pm”), duration parsing, time-of-day preferences, and confidence scoring on parsed information.

AI-powered rescheduling: evaluates both parties’ calendars, suggests 3 optimal alternatives, validates suggestions against user constraints, and stays aware of existing bookings and busy blocks.

Automated meeting prep: generates a 3-7 bullet agenda from booking notes, using the event title and attendee count for context, and skips regeneration if an agenda already exists.

The AI client is provider-agnostic by design:

// Easy provider switching
const ai = getAIClient('gemini-1.5-flash');
// Can switch to OpenAI, Claude, or other OpenAI-compatible providers
const ai = getAIClient('gpt-4'); // Just change model name!

Supported models: gemini-1.5-flash (fast, cost-effective) and gemini-1.5-pro (best quality for complex reasoning), with other OpenAI-compatible models swappable without code changes.

Environment setup

npm install
cp .env.example .env
# Edit .env with your credentials

npm run db:generate   # Generate Prisma client
npm run db:push       # Push database schema (dev)
npm run dev           # Run development server

Required environment variables:

DATABASE_URL="postgresql://..."
NEXTAUTH_URL="http://localhost:3000"
NEXTAUTH_SECRET="your-secret-key"
GOOGLE_CLIENT_ID="your-google-client-id"
GOOGLE_CLIENT_SECRET="your-google-client-secret"
GOOGLE_CALENDAR_CLIENT_ID="your-google-calendar-client-id"
GOOGLE_CALENDAR_CLIENT_SECRET="your-google-calendar-client-secret"
RESEND_API_KEY="your-resend-api-key"
OPENAI_API_KEY="your-openai-api-key"

Google Calendar OAuth setup: create a project in Google Cloud Console, enable the Google Calendar API, create OAuth 2.0 credentials (web application, redirect URI http://localhost:3000/api/auth/callback/google), and copy the client ID/secret into .env.

Tech stack

  • Frontend: Next.js 16 with App Router, React 19, TypeScript
  • Styling: Tailwind CSS
  • Database: PostgreSQL with Prisma ORM
  • Authentication: NextAuth.js with Google OAuth
  • Calendar integration: Google Calendar API with googleapis
  • Utilities: jose (JWT), nanoid (ID generation)

Development

npm run dev              # Development
npm run build            # Build
npm start                # Start production
npm run db:generate      # Generate Prisma client
npm run db:push          # Push schema to database (dev)
npm run db:migrate       # Run migrations
npm run db:studio        # Open Prisma Studio

License

ISC

Back to top