{"id":50669378,"url":"https://github.com/troynt/dotnet-todo-app","last_synced_at":"2026-06-08T09:32:01.671Z","repository":{"id":360128642,"uuid":"1248670973","full_name":"troynt/dotnet-todo-app","owner":"troynt","description":"Exploring Aspire \u0026 Bun. This is an AI assisted prototype.","archived":false,"fork":false,"pushed_at":"2026-05-25T05:30:47.000Z","size":144,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-25T06:46:20.316Z","etag":null,"topics":["antdesign","aspire-dotnet","bun","dotnet","protobuf","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/troynt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-24T23:54:33.000Z","updated_at":"2026-05-25T05:30:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/troynt/dotnet-todo-app","commit_stats":null,"previous_names":["troynt/dotnet-todo-app"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/troynt/dotnet-todo-app","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troynt%2Fdotnet-todo-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troynt%2Fdotnet-todo-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troynt%2Fdotnet-todo-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troynt%2Fdotnet-todo-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/troynt","download_url":"https://codeload.github.com/troynt/dotnet-todo-app/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/troynt%2Fdotnet-todo-app/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34057158,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["antdesign","aspire-dotnet","bun","dotnet","protobuf","typescript"],"created_at":"2026-06-08T09:32:00.166Z","updated_at":"2026-06-08T09:32:01.659Z","avatar_url":"https://github.com/troynt.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Todo App\n\nA modern todo application built with ASP.NET Core gRPC (backend), React + TypeScript (frontend), and .NET Aspire for orchestration.\n\n## Tech Stack\n\n| Layer | Technology |\n|-------|-----------|\n| **Frontend** | React 19, TypeScript, Bun, Tailwind CSS v4, Ant Design, TanStack Query, Connect RPC / gRPC-Web |\n| **Backend** | ASP.NET Core (NET 10), gRPC, EF Core with SQLite, OpenTelemetry |\n| **Orchestration** | .NET Aspire |\n| **Contracts** | Protocol Buffers (buf) |\n\n## Project Structure\n\n```\n├── Todo.sln            # .NET Solution file – links all C# projects\n├── apphost.cs          # Aspire AppHost – orchestrates all resources\n├── protos/             # Protobuf definitions (single source of truth for the API)\n│   └── todo.proto\n├── be/                 # Backend – ASP.NET Core gRPC service\n│   ├── Data/           # EF Core models \u0026 DbContext\n│   ├── Features/       # Vertical slice handlers per use case\n│   ├── Services/       # gRPC service entry point (TodoServiceImpl)\n│   ├── Shared/         # Mapping extensions, shared validators\n│   └── appsettings.*.json\n├── be.Tests/           # Backend Tests – C# unit \u0026 integration tests\n├── fe/                 # Frontend – React + TypeScript app\n│   ├── src/\n│   │   ├── gen/        # Auto-generated protobuf/connect types (do not edit)\n│   │   ├── features/   # Feature folders (each has components/ and hooks/)\n│   │   ├── shared/     # Shared UI components \u0026 utilities\n│   │   ├── App.tsx     # Root layout / state coordinator\n│   │   └── client.ts   # gRPC-Web client configuration\n│   └── e2e/            # Playwright E2E tests\n└── aspire.config.json  # Aspire configuration\n```\n\n## Quick Start\n\n### Prerequisites\n\n- [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0)\n- [Bun](https://bun.sh/)\n- [Aspire CLI](https://learn.microsoft.com/dotnet/aspire/get-started/install-aspire)\n\n### Run the full app\n\n```bash\naspire start\n```\n\nThis builds the backend, generates TypeScript types from `protos/todo.proto`, starts the Bun dev server, and launches all resources under Aspire.\n\n\u003e **Tip:** Use `aspire start --isolated` to avoid port/state conflicts when working in git worktrees or multiple terminals.\n\n### Run individual parts\n\n```bash\n# Backend only (also triggers proto generation)\ndotnet build -c Debug   # run inside be/\n\n# Frontend dev server independently\ncd fe \u0026\u0026 bun run dev\n\n# Proto generation only\ncd fe \u0026\u0026 bun run generate-proto\n```\n\n## Available Commands\n\n### Aspire Orchestration\n\n| Command | Description |\n|---------|-------------|\n| `aspire start` | Start all resources (builds + generates protos) |\n| `aspire start --isolated` | Start in an isolated session (unique ports/state) |\n| `aspire stop` | Stop the running AppHost |\n| `aspire ps` | List currently running AppHosts |\n| `aspire describe` | Inspect resource states and endpoints (`--format Json`) |\n| `aspire wait \u003cresource\u003e` | Wait for a resource to become healthy (e.g. `be`, `fe`) |\n| `aspire logs [resource]` | View raw console logs |\n| `aspire otel logs [resource] --format Json` | View structured OpenTelemetry logs |\n| `aspire doctor` | Check local Aspire environment health |\n\n### Frontend\n\n| Command | Description |\n|---------|-------------|\n| `bun run dev` | Start Vite + React dev server (localhost:3000) |\n| `bun run build` | Build for production (runs proto gen + bundler) |\n| `bun run generate-proto` | Regenerate TypeScript from `.proto` files |\n| `bun run test:e2e` | Run Playwright E2E tests |\n\n### Backend\n\n| Command | Description |\n|---------|-------------|\n| `dotnet build` | Compile backend + generate C# types from protos |\n| `dotnet test` | Run backend C# tests (from the root or `be.Tests/` directory) |\n\n## Resource Endpoints\n\n| Resource | Type | URL |\n|----------|------|-----|\n| `fe` | Bun dev server | http://localhost:3000 |\n| `be` | .NET gRPC/HTTP | localhost:5165 (HTTP) / localhost:7218 (HTTPS) |\n| `aspire-dashboard` | Aspire dashboard | http://localhost:15189 / http://localhost:17020 |\n\n## Adding a New Feature\n\n### 1. Define the protobuf contract\n\nEdit `protos/todo.proto` to add new messages or service methods. Then regenerate types:\n\n```bash\ncd fe \u0026\u0026 bun run generate-proto   # generates TypeScript in fe/src/gen/\ndotnet build                      # generates C# in be/\n```\n\n### 2. Implement the backend slice\n\nEach use case gets its own class under `be/Features/\u003cFeatureName\u003e/`:\n\n1. Create a handler class (e.g., `be/Features/TodoLists/MyNewUseCase.cs`) that processes the request and uses `TodoDbContext` directly.\n2. Register it in `be/Services/TodoServiceImpl.cs` by overriding the corresponding gRPC method and delegating to your handler.\n\n### 3. Implement the frontend slice\n\n1. Create components under `fe/src/features/\u003cFeatureName\u003e/components/`.\n2. Create hooks (queries/mutations) under `fe/src/features/\u003cFeatureName\u003e/hooks/` using the auto-generated `@connectrpc/connect-query` types in `fe/src/gen/`.\n3. Wire everything together in `fe/src/App.tsx` if it affects global state or routing.\n\n### 4. Run and verify\n\n```bash\naspire start          # rebuilds everything and starts all resources\nbun run test:e2e      # run E2E tests (add new ones in fe/e2e/)\n```\n\n## Debugging\n\n1. **Resource not healthy?** → `aspire logs \u003cresource\u003e` or `aspire otel logs \u003cresource\u003e --format Json`\n2. **gRPC call failing?** → Confirm both resources are up (`aspire wait be \u0026\u0026 aspire wait fe`). Check `fe/src/client.ts` for the gRPC-Web endpoint config.\n3. **Stale generated types?** → Run `bun run generate-proto` in `fe/`, then `dotnet build` in `be/`.\n4. **Database issues?** → SQLite database is at `be/todo.db`, created on each startup via `EnsureCreated()`.\n\n## Architecture Notes\n\n- **Vertical Slice Architecture**: Both backend and frontend are organized by feature/domain rather than technical layer. Each use case (backend) or feature folder (frontend) is self-contained.\n- **Protobuf as the contract**: `protos/todo.proto` is the single source of truth for all API messages and service definitions. TypeScript and C# types are generated from it.\n- **gRPC-Web on the frontend**: The React app connects to the gRPC backend via Connect RPC / gRPC-Web (`fe/src/client.ts`). CORS headers (`Grpc-*`) are exposed on the backend.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftroynt%2Fdotnet-todo-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftroynt%2Fdotnet-todo-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftroynt%2Fdotnet-todo-app/lists"}