planning_context.md•5.69 kB
# PLANNING.md (CLEAN SCOPE)
> Google‑only MCP “router” for scheduling & confirmations. MVP scope only. No Docker/k8s/CD. No Slack/Discord. No post‑MVP polish.
## 0) Objectives & Non‑Goals (MVP)
- **Objectives**: expose 5 tools; enforce policy server‑side; minimize token and risk; deliver staging‑ready MVP.
- **Non‑Goals**: containers, production rollout strategies, multi‑region HA, SMS/Slack/Discord, reschedule flows, ICS attachments.
## 1) Milestones (2 weeks)
- **Week 1 — MVP path**
- [ ] Repo scaffold (TS/Node 20, Fastify, AJV, googleapis, openid-client, luxon, pino, prom‑client, vitest, nock)
- [ ] JSON Schemas for all 5 tools; validators wired
- [ ] OAuth + encrypted token store; refresh path
- [ ] Adapters: Google Calendar (freebusy, events.list/insert/delete), Gmail send (templated)
- [ ] Policy rules: working hours, allowlist, overlap prevention
- [ ] Idempotency store (key+fingerprint → outcome)
- [ ] Implement tools: time.resolve → find_free_slots → create_event → cancel_event → email.send
- **Week 2 — Hardening & DX**
- [ ] Structured logs, Prometheus metrics, OpenTelemetry traces
- [ ] Rate limit/backoff; error normalization; test fixtures
- [ ] Contract/policy/adapter/idempotency/time tests all green
- [ ] Staging runbook pass (book/cancel + confirm email)
## 2) Repository Structure (no Docker)
```
src/
server.ts
mcp/
index.ts
tools/
calendar.find_free_slots.ts
calendar.create_event.ts
calendar.cancel_event.ts
email.send.ts
time.resolve.ts
schemas/
calendar.find_free_slots.request.json
calendar.find_free_slots.response.json
...
adapters/
google-calendar.ts
gmail-send.ts
policy/
calendars.json
rules.ts
auth/
oauth.ts
token-store.ts
templates/
meeting_confirm.hbs
cancel_confirm.hbs
util/
time.ts
errors.ts
idempotency.ts
test/
unit/*.spec.ts
contracts/*.spec.ts
README.md
```
## 3) Tools — Contracts (authoritative)
> Uniform wrapper: `{ ok: boolean, data?: T, error?: { code, message, provider_code?, retry_after_ms? } }`.
### 3.1 `calendar.find_free_slots`
- **Req** `{ duration_min=30, window_start_iso, window_end_iso, attendees?:string[], work_hours_only=true, tz="America/Chicago" }`
- **Res** `{ slots:[{start_iso,end_iso}], source_calendar_ids:string[], confidence:"HIGH"|"MEDIUM"|"LOW" }`
- **Policy** clamp to work hours; calendar allowlist; attendee freebusy if visible.
### 3.2 `calendar.create_event`
- **Req** `{ title, start_iso, end_iso, attendees:[{email,required?}], calendar_id?, location?, video=true, idempotency_key }`
- **Res** `{ event_id, html_link, status:"CREATED"|"UPDATED" }`
- **Policy** reject overlaps; weekdays only; 08:00–18:00 CT.
### 3.3 `calendar.cancel_event`
- **Req** `{ event_id, calendar_id?, reason?, idempotency_key }`
- **Res** `{ status:"CANCELLED"|"NOOP" }`
### 3.4 `email.send`
- **Req** `{ to:[string|{name,email}][], subject, template:"MEETING_CONFIRM"|"CANCEL_CONFIRM", vars:object }`
- **Res** `{ message_id }`
### 3.5 `time.resolve`
- **Req** `{ input, tz="America/Chicago", now_iso?, duration_min_default=30 }`
- **Res** `{ start_iso, end_iso, did_assume_date, did_assume_duration }`
## 4) Business Rules
- Workdays Mon–Fri; hours 08:00–18:00 CT.
- Default duration 30m; bounds 15–120m.
- Calendar allowlist: `primary`, optional `work@domain.com`.
- Idempotency required for mutations; 24h cache TTL.
## 5) Security & Observability
- **OAuth**: PKCE; refresh before expiry; AES‑GCM encrypted tokens.
- **Scopes**: `calendar.events`, `gmail.send` only.
- **Logs**: pino JSON; mask emails.
- **Metrics**: `tool_calls_total`, `tool_latency_ms_bucket`, `oauth_refresh_total`.
- **Tracing**: OpenTelemetry; propagate `traceparent`.
## 6) Testing Strategy
- Contract: AJV round‑trips for all tools.
- Policy: off‑hours `FORBIDDEN`; overlap `CONFLICT`; duration bounds.
- Adapter: Calendar (ok/rateLimitExceeded/5xx), Gmail (ok/401 refresh).
- Idempotency: replay create/cancel.
- Time: deterministic with `now_iso`, DST boundaries.
## 7) Staging Runbook
- Complete OAuth; verify token store; book a 30m slot next weekday; email confirm received; cancel; email cancel received; check logs/metrics.
---
# CONTEXT.md (CLEAN SCOPE)
## A) System Overview (MVP)
- Actors: Caller → Voice Agent → LLM (Realtime) → MCP Router → Google APIs.
- Goal: schedule meetings with minimal tools and strong server‑side policy.
## B) Flows
**Booking**: time.resolve → find_free_slots → propose → create_event → email.send → summarize.
**Cancel**: cancel_event → email.send → summarize.
## C) Scopes & Least Privilege
- Calendar: `calendar.events` only.
- Gmail: `gmail.send` only.
## D) Prompt Strategy
- Short, policy‑centric; routing rules only; schemas guide usage.
## E) Error Model
- Codes: `INVALID_ARGUMENT`, `UNAUTHENTICATED`, `FORBIDDEN`, `NOT_FOUND`, `CONFLICT`, `RATE_LIMITED`, `INTERNAL`.
## F) NFRs (MVP‑useful only)
- Availability 99.9% (best‑effort in single region).
- p95 budgets: resolve ≤150ms; find_free_slots ≤700ms; create_event ≤900ms; email.send ≤350ms.
## G) Threat Model (excerpt)
- Token leakage → AES‑GCM + KMS; rotate monthly (staging).
- Over‑permissive actions → allowlists + server policy guardrails.
- Prompt injection via titles → sanitize/escape; deny user HTML in templates.
## H) Test Matrix (excerpt)
- Happy booking; overlap conflict; off‑hours; cancel idempotent; time resolve DST.
## I) Out‑of‑Scope (explicit)
- Containers, CD/canary, multi‑region HA.
- Slack/Discord/SMS; inbox reads; rescheduling; ICS.