# GoCalGoo — Implementation Plan ## Overview GoCalGoo is a single Go application with four surfaces sharing one service layer: 1. **CLI** — direct human use via cobra 2. **HTTP API** — programmatic access (REST/JSON) 3. **MCP server** — tool-style integration (stdio + HTTP) 4. **Shared service layer** — underneath all three ## Architecture ``` cmd/gocalgoo/ ← main entrypoint internal/app/ ← app wiring, lifecycle internal/config/ ← config loading, validation, profiles internal/auth/ ← OAuth2, PKCE, token lifecycle, callback server internal/google/ ← Google client init, raw API adapters internal/calendar/ ← business logic: calendars, events internal/contacts/ ← business logic: contacts internal/httpapi/ ← REST/JSON API handlers internal/mcp/ ← MCP server (stdio + HTTP) internal/security/ ← API key auth, middleware, secret redaction internal/store/ ← token store, API key store, local state internal/output/ ← CLI tables/json/yaml rendering internal/telemetry/ ← structured logging, tracing (optional) ``` ## Key Design Decisions - **No CLI→API calling**: HTTP API and MCP layer call shared services directly, not the CLI. - **Google types at the edge**: Convert Google API types to internal types immediately. - **Interfaces at the call site**: Interface definitions live in the package that uses them. - **Config precedence**: CLI flags > env vars > profile config > base config file > defaults. - **SQLite for local metadata**: API keys, audit log, local state. - **Token file permissions**: 0600, never world-readable. - **API keys**: Hashed at rest (bcrypt). Show raw key once on creation only. ## Core Interfaces ```go type AuthManager interface { LoginLoopback(ctx context.Context, port int) error LoginManual(ctx context.Context, port int) error Status(ctx context.Context) (AuthStatus, error) Logout(ctx context.Context) error } type CalendarService interface { ListCalendars(ctx context.Context) ([]Calendar, error) ListEvents(ctx context.Context, req ListEventsRequest) ([]Event, error) AddEvent(ctx context.Context, req AddEventRequest) (*Event, error) UpdateEvent(ctx context.Context, req UpdateEventRequest) (*Event, error) DeleteEvent(ctx context.Context, calendarID, eventID string) error } type ContactsService interface { ListContacts(ctx context.Context, req ListContactsRequest) ([]Contact, error) AddContact(ctx context.Context, req AddContactRequest) (*Contact, error) } type APIKeyService interface { CreateKey(ctx context.Context, req CreateAPIKeyRequest) (*IssuedAPIKey, error) ValidateKey(ctx context.Context, raw string) (*Principal, error) RevokeKey(ctx context.Context, id string) error } ``` ## OAuth2 Plan Google installed-app / desktop-style flow with Authorization Code + PKCE. ### Login modes | Mode | Flag | Behavior | |------|------|----------| | Fixed-port loopback | `--port 53682` | Bind `127.0.0.1:`, open browser, receive code | | Random-port loopback | `--port 0` | OS picks port, prints actual port before browser launch | | Manual fallback | `--manual` | Print URL, user pastes redirect or code, CLI exchanges | ### Scopes (v1) - `https://www.googleapis.com/auth/calendar` - `https://www.googleapis.com/auth/contacts` ## CLI Commands ``` gocalgoo auth login [--port 53682] [--manual] gocalgoo auth status gocalgoo auth logout gocalgoo calendars list gocalgoo events list --calendar primary [--from RFC3339] [--to RFC3339] gocalgoo events add --calendar primary --title "..." --start RFC3339 --end RFC3339 gocalgoo events update --calendar primary --id ID --title "..." gocalgoo events delete --calendar primary --id ID gocalgoo contacts list gocalgoo contacts add --given-name NAME --family-name NAME --email EMAIL gocalgoo serve api gocalgoo serve mcp gocalgoo serve all gocalgoo admin api-keys create --name NAME --perm events.read [--perm events.write] gocalgoo admin api-keys list gocalgoo admin api-keys revoke --id ID gocalgoo config validate ``` ## HTTP API Base path: `/api/v1` | Method | Path | Description | |--------|------|-------------| | POST | /api/v1/auth/login/start | Begin OAuth login | | POST | /api/v1/auth/login/complete | Complete OAuth login | | GET | /api/v1/auth/status | Auth status | | POST | /api/v1/auth/logout | Logout | | GET | /api/v1/calendars | List calendars | | GET | /api/v1/calendars/{calendarId}/events | List events | | POST | /api/v1/calendars/{calendarId}/events | Add event | | PATCH | /api/v1/calendars/{calendarId}/events/{eventId} | Update event | | DELETE | /api/v1/calendars/{calendarId}/events/{eventId} | Delete event | | GET | /api/v1/contacts | List contacts | | POST | /api/v1/contacts | Add contact | | POST | /api/v1/admin/api-keys | Create API key | | GET | /api/v1/admin/api-keys | List API keys | | DELETE | /api/v1/admin/api-keys/{id} | Revoke API key | | GET | /healthz | Liveness | | GET | /readyz | Readiness | ## MCP Transports: stdio + Streamable HTTP ### Tools - `calendars_list` - `events_list` - `events_add` - `events_update` - `events_delete` - `contacts_list` - `contacts_add` ### Resources - `gocalgoo://calendars` - `gocalgoo://calendar/{id}/events` - `gocalgoo://contacts` ### Auth - stdio: rely on environment/config (no transport auth) - HTTP MCP: require API key (`X-API-Key` header) ## API Key Design - Header: `X-API-Key: ` or `Authorization: Bearer ` - Storage: hashed secret (bcrypt), never raw after creation - Fields: id, hashed_secret, name, scopes, created_at, last_used_at, disabled - Permissions: `calendars.read`, `events.read`, `events.write`, `contacts.read`, `contacts.write`, `mcp.call` ## Security Requirements - Bind OAuth callback loopback to `127.0.0.1` only - Validate OAuth state parameter - Use PKCE - Redact secrets/codes from logs - Token file permissions: 0600 - Hash API keys at rest - Show raw API key once on creation only - Admin endpoints disabled by default - Require API key for HTTP API and MCP HTTP ## Delivery Phases | Phase | Status | Description | |-------|--------|-------------| | 1 | ✅ In progress | Foundation: repo scaffold, config, logging, token store, OAuth2 CLI | | 2 | ⏳ Pending | Core business logic: calendars, events, contacts | | 3 | ⏳ Pending | CLI completion: output formats, validation, robust errors | | 4 | ⏳ Pending | HTTP API: auth middleware, REST endpoints, API key management | | 5 | ⏳ Pending | MCP: stdio transport, HTTP transport, tool/resource exposure | | 6 | ⏳ Pending | Hardening: audit log, retry/backoff, quota-aware errors, tests, packaging | ## Go Stack | Library | Purpose | |---------|---------| | `github.com/spf13/cobra` | CLI framework | | `github.com/spf13/viper` | Config management | | `go.uber.org/zap` | Structured logging | | `github.com/go-chi/chi/v5` | HTTP routing | | `golang.org/x/oauth2` | OAuth2 plumbing | | `google.golang.org/api` | Google API clients | | `github.com/stretchr/testify` | Test assertions | | `golang.org/x/crypto/bcrypt` | API key hashing | | SQLite | Local metadata (API keys, audit log) |