chore: scaffold oO monorepo with architecture, roadmap, and module stubs

This commit is contained in:
2026-04-13 14:19:56 +00:00
commit cf4c7a0eb4
36 changed files with 494 additions and 0 deletions

13
services/README.md Normal file
View File

@@ -0,0 +1,13 @@
# services/
Backend microservices. Each directory is independently deployable, ships a `Dockerfile`, a `/health` endpoint, and its own `README.md` describing its contract.
| Dir | Role | Phase introduced |
|---|---|---|
| `gateway/` | BFF for clients; auth check; fan-out to services | 0 |
| `auth/` | OAuth (Google/Apple), sessions, JWT | 0 |
| `profile/` | user profile, preferences, consents | 0 |
| `integrations/` | third-party connectors + encrypted token vault (Todoist first) | 0 |
| `recommender/` | `POST /recommend` — policy-driven tip selection | 0 |
| `events/` | event bus ingress + durable signal store | 1 |
| `notifier/` | push/email/web delivery with quiet-hours | 3 |

0
services/auth/.gitkeep Normal file
View File

14
services/auth/README.md Normal file
View File

@@ -0,0 +1,14 @@
# auth
OAuth-based identity. **Do not roll your own crypto or session logic** — back this with Auth.js or Ory Kratos+Hydra.
## Responsibilities
- Google OAuth (Phase 0), Apple OAuth (Phase 0.5), extensible to others.
- Issue short-lived JWTs + rotating refresh tokens; HttpOnly cookies for web.
- Expose `GET /me` (who am I), `POST /logout`, OIDC-style `/.well-known` endpoints.
## Non-goals
- Password auth. Ever.
- User-profile data — that lives in `profile/`.

0
services/events/.gitkeep Normal file
View File

View File

View File

View File

@@ -0,0 +1,28 @@
# integrations
Third-party connectors and the token vault.
## Connector interface
```ts
interface Connector {
id: string // e.g. "todoist"
beginOAuth(user): Promise<{ redirectUrl, state }>
finishOAuth(code, state): Promise<StoredCredential>
fetchSignals(user, since?): AsyncIterable<NormalizedEvent>
// optional write-back, e.g. mark task done
act?(user, action): Promise<void>
}
```
## Token vault
- Credentials encrypted at rest (libsodium sealed box); key from env/KMS.
- Refresh handled transparently; consumers never see raw tokens.
- One row per `(user, provider)` with provider-specific `meta`.
## Roadmap
- Phase 0: **Todoist** (OAuth2, read tasks, complete task).
- Phase 2: Google Calendar, Apple Health (web import), generic webhook ingress.
- Phase 5: public SDK so third parties can ship connectors.

View File

View File

View File

View File

@@ -0,0 +1,27 @@
# recommender
The core of oO. Takes a user + a context, returns **one** tip.
## Contract
```
POST /recommend
{ user_id, context?: { time, timezone, client, ... } }
→ { tip: { id, kind: "todo"|"advice", title, body, source, deep_link, meta } }
POST /feedback
{ user_id, tip_id, reaction: "done"|"snooze"|"dismiss", at }
```
## Internals (stable seams)
- **Candidate sources** — pluggable async generators. v0: Todoist tasks via `integrations`. Later: advice library, calendar nudges, health prompts.
- **Context assembler** — merges request context with features (inline now, feature-store later).
- **Policy** — `Policy.pick(candidates, context) → tip`. Registered by name:
- `random` — v0 (Phase 0).
- `bandit.linucb` — v1 (Phase 1).
- `remote` — delegates to `ml/serving` FastAPI scorer (Phase 1+).
## Phase 0 goal
`RandomPolicy` only. The service, contract, and seams exist; the brain does not yet.