D&D Campaign Management Platform — organize sessions, manage players, and run your tabletop world.
Built with TanStack Start, React, and a retro pixel-art aesthetic.
git clone https://github.com/biozal/cartyx-app.git
cd cartyx-app
npm install
cp .env.example .env # fill in credentials (see docs/deployment.md)
npm run dev # http://localhost:3000- OAuth Authentication — Google, GitHub, Apple Sign-In (via JOSE/JWT)
- Campaign Management — Create, edit, and manage D&D campaigns
- Player Invites — Share invite codes for players to join
- Session Scheduling — Weekly/bi-weekly/monthly with timezone support
- Image Uploads — Campaign images stored on Cloudflare R2
- Access Control — GM and player roles with owner-only actions
| Layer | Technology |
|---|---|
| Framework | TanStack Start (full-stack React) |
| UI | React 19 + Tailwind CSS v4 |
| Routing | TanStack Router (file-based, type-safe) |
| Auth | Custom OAuth (Google, GitHub, Apple) via JOSE JWT |
| Database | MongoDB Atlas (Mongoose) |
| Image Storage | Cloudflare R2 (S3-compatible) |
| Dates | Day.js with timezone + relative time plugins |
| Build | Vite + Nitro |
| Testing | Vitest + React Testing Library |
| Linting | ESLint (flat config) + Prettier |
| Hosting | Vercel (serverless) |
| CDN | Cloudflare (DNS + R2 CDN) |
All application code lives in app/:
app/
├── components/ # React components + Storybook stories
├── hooks/ # Custom React hooks (useAuth, useCampaigns)
├── routes/ # TanStack Router file-based routes
├── server/
│ ├── functions/ # Server functions (auth, campaigns, uploads)
│ ├── models/ # Mongoose models
│ └── utils/ # Server utilities (OAuth, helpers)
├── styles/ # Global CSS (Tailwind)
├── utils/ # Client utilities (date, image compression)
├── client.tsx # Client entry point
├── router.tsx # TanStack Router config
└── ssr.tsx # SSR entry point
tests/ # Vitest test files (mirrors app/ structure)
.storybook/ # Storybook configuration and mocks
npm run dev # Vite dev server with HMR
npm run build # Production build
npm run typecheck # TypeScript type checking
npm run lint # ESLint check
npm run lint:fix # Auto-fix lint issues
npm run format # Prettier format
npm test # Run tests
npm run test:watch # TDD watch mode
npm run test:coverage # Coverage reportStandalone Python scripts for seeding and clearing test data in MongoDB. These are intentionally separate from the app's TypeScript codebase — simple, dependency-free (just pymongo), and easy to modify.
# One-time setup
python3 -m venv scripts/.venv
scripts/.venv/bin/pip install -r scripts/requirements.txt
# Seed 3 test campaigns with sessions, characters, and placeholder images
npm run dev:seed
# Wipe all campaign data (interactive confirmation)
npm run dev:clear
npm run dev:clear -- --force # skip confirmationBoth scripts require MONGODB_URI to be set and refuse to run against production databases.
Cartyx runs its own self-hosted observability stack — no third-party analytics providers:
- glitchtip.cartyx.io — error tracking (Sentry-protocol ingest). Client and server errors are captured via
app/utils/telemetry-client.tsandapp/server/utils/telemetry.ts. - umami.cartyx.io — privacy-friendly page-view and event analytics.
- grafana.cartyx.io — cluster metrics, logs, and dashboards.
Telemetry is configured via GLITCHTIP_DSN / UMAMI_WEBSITE_ID (server, runtime) and VITE_PUBLIC_GLITCHTIP_DSN / VITE_PUBLIC_UMAMI_WEBSITE_ID (client, baked in at build time) — all four are optional and default to a safe no-op when unset. See .env.example.
URLs, logins, and day-to-day usage for all three UIs: docs/observability.md.
The published Storybook is available at https://biozal.github.io/cartyx-app.
For contributor setup, story-writing patterns, interaction tests, and Storybook-specific project conventions, see docs/STORYBOOK.md.
| Environment | URL | Branch | Database |
|---|---|---|---|
| Production | app.cartyx.io |
main |
MongoDB Atlas (prod) |
| Staging | dev.cartyx.io |
dev |
MongoDB Atlas (dev) |
| PR Preview | *.vercel.app |
any PR branch | MongoDB Atlas (dev) |
| Local | localhost:3000 |
any | Local or Atlas dev |
feature/my-feature → PR against dev → preview URL → merge to dev (staging)
→ PR dev→main → production
- Feature branches target
dev dev→dev.cartyx.io(stable staging)main→app.cartyx.io(production)- Every PR gets an automatic Vercel preview URL
See docs/deployment.md for complete setup instructions including:
- Vercel project configuration
- MongoDB Atlas setup
- OAuth provider setup (Google, GitHub, Apple)
- Cloudflare DNS and R2 image storage
- Environment variables reference
See CONTRIBUTING.md for development standards, testing requirements, and PR checklist.
MIT — see LICENSE