Files
GoCalGoo/llm/PLAN.md
2026-04-01 20:57:38 +02:00

196 lines
7.0 KiB
Markdown

# 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:<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/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: <key>` or `Authorization: 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.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) |