docs: add llm/PLAN.md and llm/STATUS.md
This commit is contained in:
195
llm/PLAN.md
Normal file
195
llm/PLAN.md
Normal file
@@ -0,0 +1,195 @@
|
||||
# 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) |
|
||||
Reference in New Issue
Block a user