# Images API

Journal image storage, used to embed images (and rendered diagrams) in any markdown surface on the site.

## Upload

`POST /api/journal/images` with a browser session (JWT) or a PAT belonging to a journal member. A PAT must hold at least one of `entries:write`, `suggestions:write`, `comments:write` or `knowledge:write`, the scopes that write markdown an image can be embedded in; a reactions-only, trips-only, practice-only or scopeless PAT gets 403 `Token missing required scope: one of entries:write, suggestions:write, comments:write, knowledge:write` before the upload is read.

```bash
curl -X POST https://shanebackend-production.up.railway.app/api/journal/images \
  -H "Authorization: Bearer $PAT" \
  -F "file=@diagram.png;type=image/png"
# 201 {"id":"<uuid>","url":"/api/journal/images/<uuid>"}
```

Rules:

- Multipart field name must be `file`.
- The server sniffs magic bytes and ignores your Content-Type. Accepted: png, jpeg, gif, webp. SVG is deliberately rejected (XSS vector): 415.
- Max 5MB: 413. Empty or missing file: 400.
- Quota: 100 uploads per user per rolling 24h: 429 with an honest `Retry-After` (seconds until the oldest upload ages out).

## Serving

`GET /api/journal/images/:id` is fully public — the one `/api/journal` route the invite-only gate deliberately skips, because an `<img>` tag sends no `Authorization` header. It streams the stored bytes with the sniffed Content-Type and `Cache-Control: public, max-age=31536000, immutable`. Ids are unguessable UUIDs, so treat an image URL as a capability. There is no delete endpoint.

## Embedding

Embed the absolute backend URL in markdown, which is what the site's own editor does:

```markdown
![architecture](https://shanebackend-production.up.railway.app/api/journal/images/<uuid>)
```

The relative form `/api/journal/images/<uuid>` also renders on shanejli.com pages (rewrite), but breaks in external readers; prefer absolute.

## Diagrams

Journal entry bodies and appends render fenced ```mermaid code blocks natively, so prefer a mermaid block there. Upload rendered images instead when the diagram must show in comments or RSS/JSON feeds, or when it comes from a non-mermaid tool (graphviz, matplotlib): export PNG under 5MB, upload here, embed the URL.
