mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:21:09 +02:00
Lays the foundation for the Cards marketplace + community backend per
apps/cards/docs/MARKETPLACE_PLAN.md. Phase α scope: skeleton, schema,
JWT auth wiring, health endpoint. Routes follow in Phase β.
Stack: Hono + Bun + Drizzle + Postgres + jose-JWKS — mirrors the
mana-credits service template.
Schema: pgSchema('cards') inside mana_platform, 16 tables across six
groups in src/db/schema/:
- authors.ts: authors, author_follows
- decks.ts: decks, deck_versions, deck_cards (with cards_card_type
enum mirroring @mana/cards-core; per-card content_hash for
smart-merge; CHECK constraint that paid decks must use
Cards-Pro-Only-1.0 license)
- tags.ts: tag_definitions (hierarchical), deck_tags
- engagement.ts: deck_stars, deck_subscriptions, deck_forks
- discussions.ts: deck_pull_requests (with diff jsonb +
pr_status enum), card_discussions (bound to card_content_hash
so threads survive version bumps)
- moderation.ts: deck_reports (with category/status enums),
ai_moderation_log
- credits.ts: deck_purchases (snapshot price + author/mana split),
author_payouts
Phase λ's co_learn_sessions intentionally not yet here.
Service plumbing:
- src/index.ts: Hono entry on :3072, /health unauth, /v1 stub
- src/config.ts: env loader with author-payout BPS knobs
(defaults 80/20 standard, 90/10 verified-mana) and
community-verified thresholds
- src/middleware/jwt-auth.ts + service-auth.ts: JWKS validation
+ X-Service-Key check (mirrors mana-credits)
- src/lib/errors.ts: HttpError + named subclasses
- drizzle.config.ts pointing at mana_platform with schemaFilter:cards
- drizzle/0000_*.sql committed so other devs / prod migration path
has a reproducible starting point
Validated: tsc --noEmit clean, drizzle-kit generate produces
233-line SQL with all 16 tables + 5 enums + indexes.
Next (Phase α.4): Dockerfile + docker-compose + cloudflare tunnel
route cards-api.mana.how → :3072.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3.8 KiB
3.8 KiB
cards-server
Cards Marketplace + Community backend. Owns the published-deck side of
the Cards product (the standalone app at cards.mana.how is the
client). Phase α is the data skeleton — schema + bootstrap + JWT auth
in place; routes land progressively in Phase β onwards.
For the full design rationale, phasing, and contract decisions see
apps/cards/docs/MARKETPLACE_PLAN.md.
Tech Stack
| Layer | Tech |
|---|---|
| Runtime | Bun |
| Framework | Hono |
| Database | PostgreSQL (mana_platform.cards.* schema) + Drizzle ORM |
| Auth | JWT via JWKS from mana-auth (EdDSA, jose) |
| Money | mana-credits — never Stripe directly |
Port: 3072
Quick Start
# Schema push (writes to local mana_platform DB)
bun run db:push
# Dev server with watch
bun run dev
# Type check
bun run type-check
Database
Schema: cards inside the shared mana_platform DB. 17 tables across
six logical groups (matching the source files in src/db/schema/):
| File | Tables |
|---|---|
authors.ts |
cards.authors, cards.author_follows |
decks.ts |
cards.decks, cards.deck_versions, cards.deck_cards |
tags.ts |
cards.tag_definitions, cards.deck_tags |
engagement.ts |
cards.deck_stars, cards.deck_subscriptions, cards.deck_forks |
discussions.ts |
cards.deck_pull_requests, cards.card_discussions |
moderation.ts |
cards.deck_reports, cards.ai_moderation_log |
credits.ts |
cards.deck_purchases, cards.author_payouts |
co_learn_sessions (Phase λ) is intentionally not yet in the schema.
Every table is created via pgSchema('cards') per the Mana convention.
Auth model
Three middleware:
jwtAuth(authUrl)— validates Bearer tokens via JWKS. Setsc.set('user', { userId, email, role }). Used on every user-facing/v1/*route.serviceAuth(serviceKey)—X-Service-Keycheck for service-to- service calls (e.g. mana-credits-webhook → cards-server).- (planned)
optionalAuth— for routes that should respond differently when the caller is signed-in but never reject anonymous.
Phasing (per MARKETPLACE_PLAN §11)
| Phase | What lands | Where |
|---|---|---|
| α | Skeleton + schema + JWT + health | now |
| β | Author publish flow + AI-mod-first-pass | next |
| γ | Discovery (browse, search, tags, follow) | |
| δ | Subscribe + smart-merge | |
| ε | Pull-requests + discussions | |
| ζ | mana-credits marketplace | |
| η | Moderation + trust | |
| θ | Deep AI (auto-tags, embeddings, audio) | |
| ι | Optimisation + scale |
Environment Variables
PORT=3072
DATABASE_URL=postgresql://mana:devpassword@localhost:5432/mana_platform
MANA_AUTH_URL=http://localhost:3001
MANA_CREDITS_URL=http://localhost:3061
MANA_LLM_URL=http://localhost:3025
MANA_MEDIA_URL=http://localhost:3015
MANA_NOTIFY_URL=http://localhost:3040
MANA_SERVICE_KEY=dev-service-key
CORS_ORIGINS=http://localhost:5173,http://localhost:5180
# Author payout splits (basis points). Defaults: 80/20 standard,
# 90/10 verified-mana.
AUTHOR_PAYOUT_STANDARD_BPS=8000
AUTHOR_PAYOUT_VERIFIED_BPS=9000
# Community-verified auto-thresholds.
COMMUNITY_VERIFY_STARS=500
COMMUNITY_VERIFY_FEATURED=3
COMMUNITY_VERIFY_SUBSCRIBERS=200
Critical Rules
- Never call Stripe directly. All money flows through mana-credits.
/v1is the public contract — additive-only changes within v1, breaking changes go to/v2.- Content-hash everything. Per-card and per-version SHA-256s drive smart-merge, cache invalidation, and trust.
- Subscribed Decks are unidirectional. Author → Subscriber. Forks for the bidirectional case.
- Verification is binary, not numeric. Two flags (
verified_mana,verified_community), the UI shows badges. Never invent a "trust score".