chore: bump version to 8.1.2, add sticker wall docs and design spec
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
100
docs/external-downstream-stickerwalls.md
Normal file
100
docs/external-downstream-stickerwalls.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# Sticker Wall Images — Integration Guide
|
||||
|
||||
The vote-app renders per-session sticker walls as 1920×1080 PNG images with transparent backgrounds. These can be loaded directly as `<img>` sources to display a session's sticker wall.
|
||||
|
||||
## Endpoints
|
||||
|
||||
### Retrieve Sticker Wall Image
|
||||
|
||||
```
|
||||
GET /stickerwalls/{sessionID}.png
|
||||
```
|
||||
|
||||
**Authentication:** None (public endpoint)
|
||||
|
||||
**Response:**
|
||||
- `200 OK` — image/png body, `Cache-Control: public, max-age=3600`
|
||||
- `404 Not Found` — no render has been performed for this session yet
|
||||
|
||||
**Usage:** Load directly as an image source:
|
||||
```html
|
||||
<img src="https://vote-app.example.com/stickerwalls/42.png" />
|
||||
```
|
||||
|
||||
### Trigger Render
|
||||
|
||||
```
|
||||
POST /api/stickerwalls/{sessionID}/render
|
||||
```
|
||||
|
||||
**Authentication:** Required — `X-API-Key` header with the upstream API key.
|
||||
|
||||
**Response:**
|
||||
- `200 OK` — image/png body with the rendered sticker wall
|
||||
- `403 Forbidden` — missing or invalid API key
|
||||
- `404 Not Found` — session has no placed stickers
|
||||
|
||||
**Response Headers:**
|
||||
- `X-Sticker-Wall-Rendered: true` — a fresh render was performed
|
||||
- `X-Sticker-Wall-Rendered: false` — served from cache (no new stickers since last render)
|
||||
|
||||
## Behavior
|
||||
|
||||
### Active Sessions
|
||||
|
||||
During an active session, stickers are placed by voters and stored in the database. The sticker wall image is **not** automatically re-rendered on each sticker purchase (to avoid thrashing).
|
||||
|
||||
To get a fresh image during an active session:
|
||||
1. Call `POST /api/stickerwalls/{sessionID}/render`
|
||||
2. If new stickers were placed since the last render, a fresh image is generated
|
||||
3. The response contains the image bytes directly
|
||||
|
||||
### Session End
|
||||
|
||||
When a session ends, the vote-app automatically renders the final sticker wall image. After this point:
|
||||
- The image is **immutable** — it will never be re-rendered
|
||||
- `GET /stickerwalls/{sessionID}.png` returns the final image directly
|
||||
- `POST /api/stickerwalls/{sessionID}/render` returns the cached final image (with `X-Sticker-Wall-Rendered: false`)
|
||||
|
||||
### Historical Sessions
|
||||
|
||||
Sessions that existed before this feature was deployed will be rendered on first request (via the render endpoint). Once rendered, they are cached and served normally.
|
||||
|
||||
## Suggested Integration
|
||||
|
||||
### Post-Session Retrieval (most common)
|
||||
|
||||
After a session ends, load the sticker wall for display or archival:
|
||||
|
||||
```javascript
|
||||
const sessionId = 42;
|
||||
const img = new Image();
|
||||
img.src = `https://vote-app.example.com/stickerwalls/${sessionId}.png`;
|
||||
img.onload = () => { /* display it */ };
|
||||
img.onerror = () => { /* no sticker wall for this session */ };
|
||||
```
|
||||
|
||||
### Active Session Preview
|
||||
|
||||
To show a "live preview" of the current sticker wall during a session:
|
||||
|
||||
```javascript
|
||||
async function refreshStickerWall(sessionId) {
|
||||
const res = await fetch(`/api/stickerwalls/${sessionId}/render`, {
|
||||
method: 'POST',
|
||||
headers: { 'X-API-Key': API_KEY }
|
||||
});
|
||||
if (res.ok) {
|
||||
const blob = await res.blob();
|
||||
const url = URL.createObjectURL(blob);
|
||||
document.getElementById('sticker-wall-preview').src = url;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Image Format
|
||||
|
||||
- **Dimensions:** 1920×1080 pixels
|
||||
- **Format:** PNG with alpha transparency
|
||||
- **Background:** Fully transparent — overlay on any background
|
||||
- **Sticker rendering:** Positioned, scaled, and rotated to match the live display
|
||||
Reference in New Issue
Block a user