{"id":46593058,"url":"https://github.com/igor47/csheet","last_synced_at":"2026-04-01T20:33:04.673Z","repository":{"id":321445594,"uuid":"1059026657","full_name":"igor47/csheet","owner":"igor47","description":"DnD digital character sheet","archived":false,"fork":false,"pushed_at":"2026-03-20T23:33:48.000Z","size":14390,"stargazers_count":4,"open_issues_count":18,"forks_count":3,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-21T13:00:02.689Z","etag":null,"topics":["character-sheet","dnd5e","dungeons-and-dragons","roleplaying","tabletop-gaming"],"latest_commit_sha":null,"homepage":"https://www.csheet.net","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/igor47.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-17T22:21:17.000Z","updated_at":"2026-03-20T23:33:19.000Z","dependencies_parsed_at":null,"dependency_job_id":"ab08a51f-5751-4fb4-90e0-a259d8bb9b10","html_url":"https://github.com/igor47/csheet","commit_stats":null,"previous_names":["igor47/csheet"],"tags_count":30,"template":false,"template_full_name":null,"purl":"pkg:github/igor47/csheet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igor47%2Fcsheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igor47%2Fcsheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igor47%2Fcsheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igor47%2Fcsheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/igor47","download_url":"https://codeload.github.com/igor47/csheet/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igor47%2Fcsheet/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31291678,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["character-sheet","dnd5e","dungeons-and-dragons","roleplaying","tabletop-gaming"],"created_at":"2026-03-07T14:02:30.078Z","updated_at":"2026-04-01T20:33:04.661Z","avatar_url":"https://github.com/igor47.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CSheet\n\n**For Players:** Visit **[www.csheet.net](https://www.csheet.net)** to create and manage your D\u0026D characters.\n\n**For Developers:** This README contains instructions for setting up a local development environment and self-hosting CSheet.\n\n---\n\n## About CSheet\n\nCSheet is an open-source, self-hostable D\u0026D 5th Edition character sheet application that supports both the 2014 (SRD 5.1) and 2024 (SRD 5.2) rulesets.\n\n**What CSheet Is:**\n- A companion tool for managing your D\u0026D characters\n- Support for tracking ability scores, skills, spells, hit points, and progression\n- Open-source software you can run on your own server\n- Designed for use alongside traditional tabletop play\n\n**What CSheet Is NOT:**\n- A virtual tabletop (VTT) platform\n- A dice rolling simulator\n- A replacement for sitting at the table with your friends\n\nCSheet is designed to help you track your character while you roll your own physical dice and engage with your fellow players around the table (or video call).\n\n## Prerequisites\n\nThis project uses **[mise](https://mise.jdx.dev/)** for managing tools and dependencies.\n\nTo install mise, visit the [mise installation guide](https://mise.jdx.dev/getting-started.html).\n\nOnce mise is installed, run:\n\n```bash\nmise install\n```\n\nThis will install all required tools including:\n- **Bun** - Fast JavaScript runtime and bundler\n- **dbmate** - Database migration tool\n- **jj** - Version control\n- **jq** - JSON processor\n\n## Getting Started\n\nInstall dependencies:\n\n```bash\nmise run install\n```\n\nStart Docker services (PostgreSQL and MinIO):\n\n```bash\nmise run deps:up\n```\n\nRun database migrations:\n\n```bash\nmise run db:upgrade\n```\n\nStart the development server:\n\n```bash\nmise run app:dev\n```\n\nThe `app:dev` task automatically starts Docker services if they're not running.\n\nThe application will be available at `http://localhost:3000`.\n\n## Task Runner\n\nThis project uses `mise run` for all common tasks:\n\n| Command | Description |\n|---------|-------------|\n| `mise run app:dev` | Start development server with hot reload |\n| `mise run app:prod` | Start production server |\n| `mise run app:container` | Build and run the app inside the local Docker Compose stack |\n| `mise run deploy:push` | Build and push the application image to Artifact Registry |\n| `mise run infra:preview` | Preview infrastructure changes (VPC, Cloud SQL, secrets, service accounts, Artifact Registry) |\n| `mise run infra:up` | Apply infrastructure changes |\n| `mise run infra:destroy` | Destroy the infrastructure stack |\n| `mise run deploy:preview` | Preview Cloud Run service and migration job changes |\n| `mise run deploy:up` | Deploy the Cloud Run service and migration job |\n| `mise run deploy:destroy` | Remove the Cloud Run service and migration job |\n| `mise run install` | Install dependencies with bun |\n| `mise run test` | Run all tests with test database |\n| `mise run deps:up` | Start all Docker services (PostgreSQL and MinIO) |\n| `mise run deps:down` | Stop all Docker services |\n| `mise run db:upgrade` | Run database migrations |\n| `mise run dbmate \u003ccommand\u003e` | Run dbmate commands (see Database section) |\n| `mise run db:psql` | Open PostgreSQL shell for the database |\n| `mise run check` | Run Biome linting/formatting checks and TypeScript validation |\n| `mise run check-fix` | Auto-fix linting/formatting issues and check types |\n\nThe containerized app uses the `app` compose profile. Stop it (and supporting services) with `docker compose --profile app down`.\n\n## Database\n\nCSheet uses **PostgreSQL 16** for data storage with **dbmate** for schema migrations.\n\n### Migrations\n\nMigrations are stored in the `migrations/` directory. Each migration file is timestamped and contains SQL to modify the database schema.\n\nCommon dbmate commands:\n\n```bash\n# Apply all pending migrations\nmise run db:upgrade\n\n# Create a new migration\nmise run dbmate new create_something\n\n# Rollback the last migration\nmise run dbmate down\n\n# Show migration status\nmise run dbmate status\n```\n\n### Test Database\n\nTests use a separate `csheet_test` database on the same PostgreSQL instance.\n\nThe test database is automatically created and migrated when you run:\n\n```bash\nmise run test\n```\n\nEach test runs inside a PostgreSQL transaction that is rolled back after the test completes, ensuring a clean database state between tests.\n\n### Database Schema\n\nThe database includes tables for:\n- **users** - User authentication\n- **characters** - Character base info (name, species, background, ruleset)\n- **character_levels** - Character class levels and progression\n- **character_abilities** - Ability scores (STR, DEX, CON, INT, WIS, CHA)\n- **character_skills** - Skill proficiencies and modifiers\n- **character_hp** - Hit points tracking\n- **character_hit_dice** - Hit dice tracking\n- **character_spell_slots** - Spell slot tracking\n- **character_spells_learned** - Spellbook/known spells\n- **character_spells_prepared** - Prepared spells\n\n### Database Shell\n\nOpen an interactive PostgreSQL shell:\n\n```bash\nmise run db:psql\n```\n\n## Architecture\n\nCSheet is built with modern web technologies focused on server-side rendering and progressive enhancement:\n\n### Tech Stack\n\n- **[Hono](https://hono.dev/)** - Lightweight web framework\n- **JSX Server-Side Rendering** - Components rendered on the server\n- **[htmx](https://htmx.org/)** - Client-side interactions without writing JavaScript\n- **[Bootstrap 5](https://getbootstrap.com/)** - CSS framework for styling\n- **[Bun](https://bun.sh/)** - Fast all-in-one JavaScript runtime\n\n### Server-Side Rendering\n\nAll pages are rendered server-side using JSX components.\nThe Hono framework provides JSX rendering out of the box, allowing you to write components that look like React but render to HTML on the server.\n\n### Client-Side Interactions\n\nInstead of a heavy JavaScript framework, CSheet uses **htmx** for dynamic interactions.\nhtmx allows you to:\n- Submit forms without page reloads\n- Update parts of the page with server responses\n- Trigger actions with minimal JavaScript\n\nExample: Updating a character's ability score sends a POST request and the server returns updated HTML that htmx swaps into the page.\n\n## Project Structure\n\n```\ncsheet/\n├── src/\n│   ├── app.ts                  # Main application, registers routes and middleware\n│   ├── config.ts               # Configuration (database path, ports, etc.)\n│   ├── db.ts                   # Database connection\n│   ├── middleware.ts           # Middleware registration\n│   ├── components/             # JSX components for rendering pages\n│   │   ├── Layout.tsx          # Main layout wrapper with navbar\n│   │   ├── Welcome.tsx         # Home page\n│   │   ├── ...\n│   │   └── ui/                 # Reusable UI components\n│   ├── routes/                 # Route handlers\n│   │   ├── index.tsx           # Home route (/)\n│   │   ├── auth.tsx            # Authentication routes\n│   │   ├── character.tsx       # Character CRUD and update routes\n│   │   └── spells.tsx          # Spell reference routes\n│   ├── middleware/             # Middleware\n│   │   ├── auth.ts             # Authentication middleware\n│   │   ├── flash.ts            # Flash messages\n│   │   └── cachingServeStatic.ts # Static file serving with caching\n│   ├── db/                     # Database models and queries\n│   │   ├── users.ts\n│   │   ├── char_hp.ts\n│   │   └── ...\n│   ├── services/               # Business logic\n│   │   ├── createCharacter.ts\n│   │   ├── computeCharacter.ts # Compute derived stats\n│   │   ├── longRest.ts\n│   │   └── ...\n│   └── lib/                    # Utilities and helpers\n│       ├── dnd/                # D\u0026D rules engine\n│       │   ├── rulesets.ts     # Ruleset loader\n│       │   ├── srd51.ts        # D\u0026D 5e SRD 5.1 rules\n│       │   └── srd52.ts        # D\u0026D 5e SRD 5.2 rules\n│       ├── schemas.ts          # Zod validation schemas\n│       └── ...\n├── migrations/                 # Database migrations\n├── db/                         # Database utilities\n│   ├── init.sql                # SQLite initialization\n│   └── schema.sql              # Full schema dump\n├── static/                     # Static assets (CSS, images, etc.)\n├── mise.toml                   # mise configuration\n└── main.ts                     # Application entry point\n```\n\n## D\u0026D Rulesets\n\nCSheet supports multiple D\u0026D 5th edition rulesets:\n\n- **SRD 5.1** - D\u0026D 5th Edition System Reference Document v5.1\n- **SRD 5.2** - D\u0026D 5th Edition System Reference Document v5.2 (2024 rules)\n\n### Ruleset System\n\nThe ruleset system is pluggable and defined in `src/lib/dnd/`:\n\n- `rulesets.ts` - Ruleset loader and interface\n- `srd51.ts` - SRD 5.1 class definitions, spells, species, etc.\n- `srd52.ts` - SRD 5.2 class definitions, spells, species, etc.\n\nEach character is associated with a ruleset, allowing players to use either the 2014 or 2024 rules. The ruleset determines:\n- Available species (races)\n- Class features and progressions\n- Spell lists\n- Ability score calculations\n- Proficiency bonuses\n\n## Self-Hosting Configuration\n\nWhen self-hosting CSheet, you can customize behavior with these environment variables:\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `SHOW_WELCOME_PAGE` | `true` | Show a welcome page to new users on first login. Set to `false` to skip. |\n\n## Development\n\n### Testing\n\nCSheet uses **Bun's built-in test runner** for testing with a comprehensive integration testing setup.\n\nRun all tests:\n\n```bash\nmise run test\n```\n\nRun specific test file:\n\n```bash\nmise run test src/routes/character.test.ts\n```\n\n#### Test Infrastructure\n\n- **Test Database**: Uses separate `csheet_test` database\n- **Transaction Isolation**: Each test runs in a transaction that auto-rolls back\n- **Factory Pattern**: Test fixtures created with [fishery](https://github.com/thoughtbot/fishery) and [@faker-js/faker](https://fakerjs.dev/)\n- **HTML Testing**: Server-rendered HTML validated with [linkedom](https://github.com/WebReflection/linkedom)\n- **Integration Tests**: Full-stack tests through HTTP requests (not unit tests)\n\n#### Writing Tests\n\nTests use RSpec-style nested describe blocks with fixtures:\n\n```typescript\nimport { describe, test, expect, beforeEach } from \"bun:test\"\nimport { useTestApp } from \"@src/test/app\"\nimport { userFactory } from \"@src/test/factories/user\"\nimport { makeRequest, parseHtml, expectElement } from \"@src/test/http\"\n\ndescribe(\"GET /characters\", () =\u003e {\n  const testCtx = useTestApp()\n\n  describe(\"when user is authenticated\", () =\u003e {\n    let user: User\n\n    beforeEach(async () =\u003e {\n      user = await userFactory.create({}, testCtx.db)\n    })\n\n    test(\"displays the character list\", async () =\u003e {\n      const response = await makeRequest(testCtx.app, \"/characters\", { user })\n      const document = await parseHtml(response)\n\n      const title = expectElement(document, \"title\")\n      expect(title.textContent).toContain(\"My Characters\")\n    })\n  })\n})\n```\n\nSee `src/routes/character.test.ts` for a complete example.\n\n### Code Quality\n\nThe project uses **Biome** for linting and formatting, and **TypeScript** for type checking.\n\nRun checks:\n\n```bash\nmise run check\n```\n\nAuto-fix issues:\n\n```bash\nmise run check-fix\n```\n\n### Project Guidelines\n\nSee [CLAUDE.md](./CLAUDE.md) for detailed development guidelines including:\n- Using Bun instead of Node.js\n- Hono framework patterns\n- Component structure\n- Authentication patterns\n- Database conventions\n- Testing patterns\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figor47%2Fcsheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Figor47%2Fcsheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figor47%2Fcsheet/lists"}