100 lines
4.8 KiB
Markdown
100 lines
4.8 KiB
Markdown
# MessageWeave
|
|
|
|
**[中文文档 / Chinese documentation → README.zh-CN.md](README.zh-CN.md)**
|
|
|
|
> One Telegram bot per mailbox. New mail arrives as metadata; the original is always
|
|
> fetched read-only from your own JMAP server.
|
|
|
|
## 1. What it is
|
|
|
|
MessageWeave sits between a JMAP mail server (for example Stalwart) and a Telegram bot.
|
|
|
|
- **Inbound.** A JMAP push subscription tells the service that a message changed. Nothing
|
|
is polled at rest.
|
|
- **Outbound.** Each event becomes a short, **metadata-only** Telegram notification:
|
|
sender, subject, timestamp. Mail bodies are never sent to Telegram.
|
|
- **On demand.** When you ask, the service reads the original through a fresh JMAP read
|
|
call. Nothing is cached in between.
|
|
- **Optionally summarised.** If you explicitly opt in, an OpenAI-compatible LLM returns a
|
|
short summary. Requests, responses and attachment bytes are never persisted.
|
|
|
|
State is an architectural boundary here, not a preference.
|
|
|
|
- **Redis is the only state store.** No database, no embedded store, no second store.
|
|
- **The process writes nothing to disk.** No log files, no data files, no local volume.
|
|
- **No long-lived connections.** No SSE, no WebSocket, no long polling.
|
|
- **Logs go to stdout only.** The platform's collector owns log storage and retention.
|
|
- **What it is not.** It is not a mail client, not a proxy, and not a relay. It forwards
|
|
metadata to one bot; it does not read arbitrary URLs, open tunnels, or broker traffic.
|
|
|
|
## 2. 5-minute setup
|
|
|
|
Requires a reachable Redis 7 instance and a JMAP session plus a Telegram bot token.
|
|
|
|
```sh
|
|
cp .env.example .env # fill REDIS_URL and CONFIG_ENCRYPTION_KEY
|
|
docker build -t messageweave:latest .
|
|
docker run --env-file .env -p 8080:8080 messageweave:latest
|
|
```
|
|
|
|
Then open `http://localhost:8080` in a browser. The first-boot SPA calls
|
|
`POST /api/bootstrap`, stores the business secrets in Redis, and creates the admin session.
|
|
From that point the browser configures the service through Redis — no environment variable
|
|
is read or written again for business configuration.
|
|
|
|
For local builds without Docker: `cargo build --locked` produces the `message-weave` binary.
|
|
|
|
If the service answers requests but does nothing useful, check the logs for a startup
|
|
warning: a missing required variable does **not** crash the process. It serves a
|
|
read-only setup router over in-memory state instead. See §3.
|
|
|
|
## 3. Configuration entry points
|
|
|
|
Three layers. They are not interchangeable.
|
|
|
|
**Boot-time environment — 2 required, 2 optional.**
|
|
|
|
| Variable | Required | Default |
|
|
|---|---|---|
|
|
| `REDIS_URL` | yes | — |
|
|
| `CONFIG_ENCRYPTION_KEY` | yes | — |
|
|
| `PORT` | no | `8080` |
|
|
| `RUN_MODE` | no | `webhook` |
|
|
|
|
`RUN_MODE` accepts `webhook` or `reconcile`. `.env.example` ships only the two required
|
|
variables; the rest are documented defaults.
|
|
|
|
**Business configuration — Redis, written by the browser.**
|
|
`POST /api/bootstrap` is the one-shot trust bootstrap; `PUT /api/business-config` hot-
|
|
reloads individual settings within about one second. The process never reads business
|
|
secrets from the environment in normal operation.
|
|
|
|
**Health.**
|
|
`GET /healthz` returns 200 unconditionally — it is liveness, not readiness. `GET /ready`
|
|
returns 503 until configuration, Redis, and both upstreams (a JMAP session `GET` and
|
|
Telegram `getMe`, 3s each) are reachable. Probe `/ready`, not `/healthz`, when deciding
|
|
whether to route traffic — but `/ready` is the heavier probe (~3s worst case), so a monitor
|
|
that must stay cheap should watch the gateway's aggregated `/healthz`.
|
|
|
|
## 4. Security boundary, in one sentence
|
|
|
|
> All state lives in Redis; the process reads only two environment variables and writes
|
|
> nothing to disk.
|
|
|
|
One corollary matters for setup: the bootstrap one-shot token is the **password component of
|
|
`REDIS_URL`**. The Redis ACL credential is therefore both the application connection
|
|
credential and the trust root for bootstrap — keep it private and rotate it as one value.
|
|
|
|
## 5. Where to read more
|
|
|
|
| Document | What it answers |
|
|
|---|---|
|
|
| [`docs/design.md`](docs/design.md) | Why the system is shaped this way: data flow, JMAP semantics, Redis streams, AI consent rules |
|
|
| [`docs/deployment.md`](docs/deployment.md) | How to deploy: Dockerfile, secrets, Redis hosting, webhook/push/reconcile routing, multi-instance load balancing |
|
|
| [`docs/reference.md`](docs/reference.md) | **Single source of truth for verifiable facts** — Redis keys and TTLs, error codes, routes, environment layers, budgets |
|
|
| [`docs/roadmap.md`](docs/roadmap.md) | Gaps, blockers and the next phase |
|
|
| [`docs/retired.md`](docs/retired.md) | What was tried and dropped — abandoned routes, unreleased designs, and names that never existed |
|
|
| [`AGENTS.md`](AGENTS.md) | Contribution rules, hard boundaries, the stable-ID index for cross-document references |
|
|
|
|
Facts that matter are traceable. If two documents disagree, `docs/reference.md` wins.
|