7.0 KiB
7.0 KiB
GoCalGoo — Implementation Plan
Overview
GoCalGoo is a single Go application with four surfaces sharing one service layer:
- CLI — direct human use via cobra
- HTTP API — programmatic access (REST/JSON)
- MCP server — tool-style integration (stdio + HTTP)
- 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
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:<port>, 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/calendarhttps://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_listevents_listevents_addevents_updateevents_deletecontacts_listcontacts_add
Resources
gocalgoo://calendarsgocalgoo://calendar/{id}/eventsgocalgoo://contacts
Auth
- stdio: rely on environment/config (no transport auth)
- HTTP MCP: require API key (
X-API-Keyheader)
API Key Design
- Header:
X-API-Key: <key>orAuthorization: Bearer <service-key> - 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.1only - 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) |