Design Documentation - snuhcs-course/swpp-2026-project-team-01 GitHub Wiki
Design Documentation
Version: 1.0
Last updated on: 2026-10-09
Table of contents
1. Document revision history
| Version | Date | Key changes |
|---|---|---|
| 1.0 | 2026-10-09 | Initial Version |
2. System design
2.1. System architecture
2.1.1. Overall architecture
CalTalk uses a client–server design for one host and one external guest per request. Web and personal-agent clients collect requests and display decisions. An AI assistant guides setup and negotiation through server-authorized tools. Supabase Auth provides account sessions, and Supabase PostgreSQL stores scheduling state and durable jobs. Application services verify resource access, apply scheduling rules and control booking. This prevents client text, speech recognition or model output from becoming booking authority. The frontend web is mainly constructed with responsive React with TypeScript.

2.1.2. Frontend class diagram

The boxes represent target React components and TypeScript modules, not JavaScript class declarations. HostCalendarSetup offers Google connection or manual calendar entry. MemberPreferenceChat uses AIConversationClient to save and reuse a member's preferences; nonmembers can proceed through GuestWorkspace without an account. SchedulingClient sends reviewed scheduling commands. Both clients use authorized server routes and receive only audience-safe data. The modules map to apps/web/components/, apps/web/lib/ and apps/web/app/ in the supplied frontend architecture.
2.1.3. Backend class diagram

These are target service and adapter responsibilities within lib/server/, agent/ and the entry adapters. AuthorizationService verifies Supabase Auth sessions and then checks application-specific access; a valid login alone does not approve a request. SupabaseDBAdapter accesses PostgreSQL through scoped queries and authorized RPCs, with RLS as an additional row boundary. The AI conversation runtime uses OpenAI and saves member-confirmed preferences. Scheduling reads the host's chosen Google or internal calendar; booking writes to that same source after host approval. RequestStore persists the shared request state through Supabase.
| Component | Target module | Interface and responsibility |
|---|---|---|
| Web UI | apps/web/ |
Host /app, public /{handle}, protected /booking/[bookingId]; Google/manual calendar setup, member preference chat and typed cards for candidates and decisions. |
| Identity | lib/server/identity/, Supabase Auth |
Verify member sessions with Supabase Auth, then check operation-specific host setup state, nonmember request credentials, agent grants, resource ownership and revocation. |
| Conversation | agent/ |
Guide host setup and member preference conversations; separate host-private and requester contexts and call only authorized scheduling tools. |
| Scheduling | lib/server/scheduling/ |
Validate intake, evaluate Google or manual calendar data, version proposals and record decisions. |
| Booking jobs | lib/server/booking/, lib/server/jobs/ |
Recheck constraints and confirm one booking in the selected Google or internal calendar; reconcile uncertain Google outcomes. |
| Data | lib/server/db/, supabase/migrations/ |
Supabase PostgreSQL stores manual calendar entries, member preferences, requests, decisions, grants and jobs. Migrations define RLS, transactional RPCs and uniqueness constraints. |
2.1.4. External libraries and services
| Dependency | Use | Status |
|---|---|---|
Expo, React Native, @supabase/supabase-js |
Current prototype UI and database client | In repository |
| Next.js, React, TypeScript | Responsive first-release web application | Target in supplied architecture |
| eve with direct OpenAI access | Conversation execution and structured extraction | Proposed; runtime and model choice need verification |
| Supabase Auth and PostgreSQL | Account sessions, RLS-protected records, transactional RPCs and durable scheduling jobs | Selected; the current prototype schema exists, but the target schema is not yet implemented |
| Google Calendar API and Google Routes | Optional Google calendar availability/booking and two-sided travel estimates | Target provider integrations |
@js-temporal/polyfill |
IANA time zones and daylight-saving ambiguity checks | Target dependency |
| Cloudflare Email Service | Contact proof, recovery and booking notifications | Selected delivery direction |
| ElevenLabs Speech to Text (Scribe) | English/Korean dictation | Selected target provider |
2.1.5. Architectural decisions
| Decision | Reason |
|---|---|
| One scheduling API for web, MCP and CLI | All clients must observe the same request, proposal version and permissions. |
| Server-side approval and Calendar writes | Client or agent access cannot substitute for the host's explicit decision. Secrets remain server-side. |
| Deterministic feasibility before AI ranking | Calendar conflicts, hard rules and travel gaps cannot be waived by generated text. |
| Separate host and requester views | Requesters must not receive the host's private events, preferences, travel context or notes; members can access only their own saved preferences. |
| AI as a guided interface | The assistant helps members set preferences and helps both participants review proposals, while server-side checks and explicit decisions control booking. |
| Durable booking job with fixed event identity | Timeouts and restarts can be reconciled without creating a second event. |
2.2. Design details
2.2.1. Main flow and APIs
A host creates an account or signs in without an invitation and either connects Google Calendar or manually registers their own calendar. The host reviews suggested meeting windows, modes, locations and travel buffers, confirms the settings, and shares a link. A guest who is not a CalTalk member creates one request without an account, corrects the summary, chooses a feasible time and agrees to the current proposal. A member guest can use scheduling preferences saved through an earlier AI conversation to guide the choice of a time, then reviews and agrees to the exact proposal. The authenticated host reviews that version and confirms it separately. Only then does a worker recheck feasibility and complete the booking. A changed proposal requires new decisions.
Request states are Gathering details → Negotiating → Awaiting host approval → Booking pending → Booked. Revision returns to negotiation; Declined, Withdrawn and Expired close an open request.
HTTP routes, MCP tools and CLI commands are adapters for the same operations. The names below are logical contracts, not finalized URLs.
| Operation | Input and authority | Result |
|---|---|---|
configureHostCalendar |
Authenticated host; Google connection or manually entered calendar and current revision | Confirmed calendar source and availability settings. |
createRequest |
Active host handle, required meeting details, creation idempotency key; optional authenticated member identity | Request ID and nonmember request-scoped credential when needed. |
readMemberPreferences / saveMemberPreferences |
Authenticated member and member-reviewed AI conversation | The member's saved scheduling preferences and version; never another member's profile. |
readRequest / clarifyRequest |
Member session, current nonmember guest credential or owning host; expected revision for writes | Audience-safe request state or a focused missing-detail question. |
listCandidates |
Complete request, selected host calendar source, member preferences when authorized, and current rules | Feasible times with named local zones; no private event details. |
agreeToProposal |
Member session or guest credential, verified contact, proposal version and shared-detail digest | Awaiting host approval, never Booked. |
reviseProposal / declineRequest / withdrawRequest |
Authorized role, current revision and lifecycle | New revision or closed status; old decisions cannot be reused. |
approveProposal |
Authenticated host, separate exact-version confirmation | Durable booking job and Booking pending. |
readReceipt / savePrivateNote |
Current participant access / owning host after booking | Confirmed details / host-only note. |
Mutations contain resourceId, expectedRevision, proposalVersion when relevant, and an idempotencyKey. Identity and confirmation evidence are derived server-side. Same-input retries return the recorded outcome after reauthorization; stale revisions or a reused key with different input fail. Responses expose stable statuses and safe error categories, not provider messages or another user's data.
2.2.2. Data model
These are logical target records, not the current SQL schema. UUIDs identify records; time instants are UTC with the user's IANA zone retained for interpretation. Credentials are encrypted or stored as keyed hashes. Unique constraints enforce one current proposal version per request and one logical booking per request.
| Record | Main fields and relationships |
|---|---|
Host |
id, unique handle, confirmed setup state; owns rules, requests and agent grants. |
HostRules |
host_id, version, IANA time zone and confirmed constraints. |
CalendarGrant |
Optional Google connection for host or guest request, encrypted credential reference and status; guest consent grants availability reads only. |
ManualCalendarEntry |
Host, time interval, entry type and revision for a calendar maintained inside CalTalk. |
Request / RequestGrant |
Host, selected calendar source, optional member guest, revision, status and current proposal; nonmember request-scoped hashed token and expiry. |
MemberPreference |
Member account, version and confirmed scheduling preferences saved through the AI conversation. |
Conversation |
Request or member preference profile, audience and session; host and guest histories are separate. |
Proposal |
Request, version, shared-detail digest and exact UTC interval. |
Agreement / HostDecision |
Proposal, matching digest and decision time; each refers to one immutable version. |
Booking / BookingAttempt |
Unique request, selected calendar source, fixed source-specific event ID, frozen payload and attempt state. |
PrivateNote / DeliveryOutbox |
Booking and host linkage for private notes; request, status and delivery key for notices. |
AgentGrant |
Host, client, scope and revocation time. |
CALENDAR_GRANT is needed only for Google access; an internal calendar uses the host's ManualCalendarEntry records. Guest Google access supplies availability only. A member's saved preferences are scoped to that account and used only for its own request. PROPOSAL and decision records are immutable. Shared-detail changes invalidate guest agreement and host approval; a changed calendar source, manual entries, time zone, meeting window, location, travel buffer or private host exception invalidates host approval and immediately re-evaluates affected open requests. If a shared detail changes or a proposed time is no longer feasible, the old proposal is withdrawn and the guest must agree to a new version before host approval. Host-private conversations and notes have their own access path; notes never appear in agent responses, guest views, reminders or invitations. Nonmember guest credentials are request-scoped, expire, and lose mutation authority on closure.
2.2.3. Voice input
Voice recognition is a web input mode. A user presses Speak, grants microphone permission, sees a recording indicator and presses Stop. The server uses ElevenLabs Speech to Text (Scribe) to transcribe English/Korean audio into an editable draft; only Send submits it. Permission denial, silence or poor recognition keeps safe draft text and offers Retry or Type instead. The application does not retain raw audio after transcription by default. A spoken “yes” or “approve” never records agreement or approval: both require a separate action on the current proposal card.
2.2.4. Scheduling algorithm
For each requested window, the evaluator:
- Intersects host working windows with the requester's stated availability. It excludes busy/focus periods from the selected Google or internal calendar plus confirmed general buffers. Optional guest Calendar consent can exclude guest busy periods; denied consent does not imply the guest is free. Member preferences guide ranking within the feasible set.
- For an in-person meeting, checks travel from the prior commitment to the meeting and from the meeting to the next commitment. Each gap must cover its route estimate and extra confirmed travel buffer. Missing location, route or travel mode requires clarification or an explicit host allowance, never zero travel.
- Applies hard rules and current private preference decisions. Only the host can confirm a preference exception; hard conflicts cannot be waived. Only feasible times reach AI ranking or the requester. A published option is not a reservation.
The exact chosen interval is evaluated again immediately before booking. A failed Google Calendar read means availability is unknown, not free; an internal-calendar booking checks the latest saved entries and revision. Each participant sees the same instant in a named local time zone.
2.2.5. Approval, booking and recovery
The request revision, unique booking record and host reservation serialize concurrent decisions. For an internal calendar, one database transaction rechecks the current entries, creates a unique event and commits Booked together. For Google Calendar, a worker lease does not authorize another insert. After an uncertain provider response, the request stays Booking pending, retaining its frozen event ID and reservation. Recovery looks up that same event; an immediate lookup miss does not prove noncreation. A definitive pre-dispatch conflict returns the request to negotiation for a new proposal and decisions.
After an event is confirmed, CalTalk immediately checks the same host's open requests for overlapping selected proposals or candidate times. It removes those times, invalidates affected agreements or approvals, returns the requests to negotiation and notifies their requesters that the time is already booked without disclosing the private booking; notification failure is tracked separately. The confirmed event in the chosen calendar source is the source for the protected receipt, calendar invitation and confirmation email. For an internal event, CalTalk generates the invitation from those same saved details. Delivery failure is tracked separately and cannot recreate the event. A lost nonmember guest link requires contact verification before a short-lived replacement credential is issued. Withdrawal or decline closes an open request; if a Google Calendar dispatch may have started, the result remains pending until reconciled. Reminders require opt-in and stop on opt-out.
2.2.6. Implementation decisions and security
| Concern | Design |
|---|---|
| Concurrency | Lock the current request for decisions; compare revisions; commit state, audit and jobs together. Do not hold a transaction during provider calls. |
| Idempotency | Persist one booking identity and source-specific event ID. Enforce a unique internal event per request; reconcile unknown Google writes before any new attempt. |
| Availability caching | Do not use cached free/busy results as booking authority; re-read Google availability or lock current internal entries immediately before booking. |
| Authorization | Check host identity, ownership, role, grant scope and revocation on every read, stream and command; require completed setup before public availability or booking. MCP OAuth is distinct from Google consent and host approval. |
| Data access | RLS restricts direct rows; privileged operations also enforce server-side resource checks. Separate host-private and guest projections. |
| Secrets and retention | Keep keys out of source and client bundles. Encrypt Calendar credentials; hash continuation tokens. Do not log raw events, audio, codes or private notes. Set retention/deletion rules before launch. |
| Accessible web UI | Use a responsive design that adapts to both mobile and desktop, so the layout does not break on mobile and users can use the UI intuitively. |
| Responsiveness | Show feedback within two seconds for local UI actions at the pilot target of 100 active requests; longer provider work shows pending status and recovery. |
2.3. Design patterns
The patterns currently applied in the checked-in Expo prototype are a module-level Singleton and a Repository-style data access module. The target booking worker and outbox described above are not presented as implemented patterns.
2.3.1. Module-level Singleton
- Implementation:
apps/mobile/lib/supabase.ts, exportedsupabaseclient. - Problem and choice: Screens and request functions need the same configured Auth/database client. A module-level instance avoids creating a client on each call; unlike a global mutable variable, its creation stays inside one importable module.
- Benefit: One place configures storage and session persistence for the prototype.
- Roles:
createClientis the factory;supabaseis the concrete shared client; importing modules are consumers.
export const supabase = createClient(url || 'https://placeholder.supabase.co', anonKey || 'placeholder-anon-key', {
auth: { storage: AsyncStorage, autoRefreshToken: true, persistSession: true, detectSessionInUrl: false },
});
The planned server application needs separate server-side client creation because request credentials must not be shared across users.
2.3.2. Repository-style data access module
- Implementation:
apps/mobile/lib/requests.ts,getRequestsandupdateRequestStatus. - Problem and choice: UI code needs request reads and decision writes. A dedicated module centralizes Supabase calls instead of repeating table and RPC names in screens.
- Benefit: UI components depend on typed request functions, and the data boundary can be replaced as the server API is built.
- Roles:
BookingRequestis the returned data shape; exported functions are the access interface; Supabase table/RPC calls are the concrete persistence mechanism; screens are consumers.
export async function updateRequestStatus(
id: string, status: 'approved' | 'rejected', expectedVersion: number
) {
const { error } = await supabase.rpc('respond_to_booking_request', {
request_id: id, response: status, expected_version: expectedVersion
});
if (error) throw error;
}
The current RPC changes prototype status; it does not implement the new guest-agreement, host-confirmation and booking guarantees. Those operations belong behind the target scheduling API.