mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-17 18:09:40 +02:00
New service docs: - services/mana-stt/CLAUDE.md — FastAPI surface with Whisper MLX (local), WhisperX (rich), and Voxtral (local + Mistral API). Documents the lazy backend loading and the launchd plist setup on the Mac Mini. - services/mana-events/CLAUDE.md — Hono/Bun service for public RSVP and event-sharing. Documents the host (JWT) vs public (token) split, the rate-limit sweeper, and the createApp factory pattern that lets unit tests run without bootstrapping the production sweeper. Stale entries fixed: - mana-auth: dropped "rewritten from NestJS / drop-in replacement" — the rewrite is the only mana-auth there is now. Email channel updated from Brevo SMTP to self-hosted Stalwart (see docs/MAIL_SERVER.md). - mana-notify: same Brevo → Stalwart fix in the channel table and env var defaults. PORT_SCHEMA.md flagged as aspirational: - The doc was dated 2026-03-28 and presented as "single source of truth", but cross-checking against actual service source files (config.go, main.py, start.sh) shows nothing matches. Added a prominent warning at the top with the real ports + two confirmed collisions: * mana-image-gen and mana-video-gen both default to PORT 3026 * mana-voice-bot and mana-sync both default to PORT 3050 Today these are masked because image-gen + voice-bot live on the Windows GPU server while video-gen + sync live on the Mac Mini, but the moment they share a host they collide. Either execute the planned reorg or pick non-colliding ports and rewrite the doc to match reality — flagged as a real follow-up.
90 lines
3.4 KiB
Markdown
90 lines
3.4 KiB
Markdown
# mana-events
|
|
|
|
Public RSVP and event-sharing service. Hosts publish event snapshots from the Mana calendar/social modules; the public can RSVP via share-link tokens without needing an account.
|
|
|
|
## Tech Stack
|
|
|
|
| Layer | Technology |
|
|
|-------|------------|
|
|
| **Runtime** | Bun |
|
|
| **Framework** | Hono |
|
|
| **Database** | PostgreSQL + Drizzle ORM |
|
|
| **Auth** | EdDSA JWT validation via JWKS from mana-auth (`jose`) — host-side only; RSVP endpoints are intentionally unauthenticated |
|
|
|
|
## Port: 3065
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
cd services/mana-events
|
|
bun run dev # Watch mode
|
|
bun run db:push # Push Drizzle schema
|
|
bun run db:studio # Drizzle Studio
|
|
bun test # Bun unit tests
|
|
```
|
|
|
|
## Why a separate service?
|
|
|
|
The Mana unified app stores events in the user's local-first store and syncs them via mana-sync — but those events are private and encrypted at rest. Sharing an event with someone *outside* the user's account requires a public, server-rendered snapshot that lives in plaintext on a service the share-link target can hit without login. mana-events is that surface.
|
|
|
|
## API Endpoints
|
|
|
|
### Host-side (JWT auth)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| POST | `/publish` | Publish an event snapshot (mints share token) |
|
|
| PUT | `/:eventId/snapshot` | Update an existing published snapshot |
|
|
| DELETE | `/:eventId` | Unpublish |
|
|
| PUT | `/:eventId/items` | Set the items/tasks list (e.g. potluck dishes) |
|
|
| GET | `/:eventId/items` | Read items |
|
|
| GET | `/:eventId/rsvps` | List collected RSVPs |
|
|
|
|
### Public (no auth — share token in path)
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/:token` | Fetch the public event snapshot |
|
|
| POST | `/:token` | Submit an RSVP |
|
|
| POST | `/:token/items/:itemId/claim` | Claim a potluck-style item |
|
|
|
|
## Rate limiting
|
|
|
|
Public RSVP endpoints are rate-limited per share token (config: `rsvpPerTokenPerHour`, `rsvpMaxPerToken`) to prevent abuse of the unauthenticated surface. Stale rate-limit buckets are swept periodically by `lib/cleanup.ts` (`startRateBucketSweeper`) — important for long-published events that would otherwise accumulate buckets indefinitely.
|
|
|
|
## Code layout
|
|
|
|
```
|
|
src/
|
|
├── index.ts # Bootstrap (port, sweeper, DB connection)
|
|
├── app.ts # Hono app factory — separated so tests can import without bootstrap
|
|
├── config.ts # Env loading (PORT, DATABASE_URL, MANA_AUTH_URL, rate limits, CORS)
|
|
├── db/
|
|
│ ├── connection.ts
|
|
│ └── schema/
|
|
│ ├── events.ts # published event snapshots + items
|
|
│ └── index.ts
|
|
├── routes/
|
|
│ ├── events.ts # host-side (JWT)
|
|
│ ├── rsvp.ts # public (token)
|
|
│ └── health.ts
|
|
├── middleware/
|
|
│ ├── jwt-auth.ts # JWKS-based EdDSA verification
|
|
│ └── error-handler.ts
|
|
└── lib/
|
|
├── cleanup.ts # rate-limit bucket sweeper
|
|
└── errors.ts
|
|
```
|
|
|
|
The Hono app lives in `app.ts` (exporting a `createApp(db, config)` factory) so unit tests in `__tests__/` can wire a test DB without triggering the production sweeper or binding the port.
|
|
|
|
## Configuration
|
|
|
|
```env
|
|
PORT=3065
|
|
DATABASE_URL=postgresql://...
|
|
MANA_AUTH_URL=http://localhost:3001
|
|
CORS_ORIGINS=http://localhost:5173,https://mana.how
|
|
```
|
|
|
|
JWT verification fetches the JWKS from `${MANA_AUTH_URL}/api/auth/jwks` lazily on first use and caches the keyset in-process.
|