Contents
Project structure
A typical monorepo for this stack looks like this:
project/
├── backend/ # .NET Web API
│ ├── src/
│ ├── tests/
│ └── backend.sln
├── frontend/ # Angular
│ ├── src/
│ └── package.json
├── docker-compose.yml
├── .mcp.json
└── CLAUDE.md
CLAUDE.md — project template
Create CLAUDE.md in the repository root:
# Project
[Name and short description]
## Stack
### Backend
- .NET 10, C# 14
- ASP.NET Core Web API
- Entity Framework Core (MySQL)
- MongoDB.Driver (MongoDB)
- FluentValidation, MediatR (CQRS)
### Frontend
- Angular 20 (standalone components, Signals)
- TypeScript (strict: true)
- Angular Material / PrimeNG
- RxJS / httpResource()
### Infrastructure
- Docker + Docker Compose
- MySQL 8.4 LTS
- MongoDB 7
## Commands
### Backend
- `dotnet build` — build
- `dotnet test` — run tests
- `dotnet run --project src/Api` — run API (port 5000)
- `dotnet ef migrations add <Name>` — new EF migration
- `dotnet ef database update` — apply migrations
### Frontend
- `npm run start` — dev server (port 4200)
- `npm run build` — prod build
- `npm run test` — tests (Karma/Jest)
- `npm run lint` — ESLint
### Docker
- `docker compose up -d` — bring up the whole environment
- `docker compose down` — stop
- `docker compose logs -f api` — backend logs
## Conventions
### Backend (C#)
- Folders: `Controllers/`, `Services/`, `Repositories/`, `Models/`, `DTOs/`
- Naming: PascalCase for classes, camelCase for fields
- Async/await everywhere there's IO
- Don't use `var` if the type isn't obvious
- Repository pattern for DB access
- DTOs for API requests and responses, don't return entities directly
### Frontend (Angular)
- Standalone components only (no NgModules)
- OnPush change detection where possible
- Services in `src/app/core/services/`
- Components in `src/app/features/<feature>/`
- Use `inject()` instead of constructor injection
## Don't touch
- `src/Migrations/` — generated automatically
- `dist/` — Angular build output
- `.env` files — don't commit secrets
.claude/settings.json — permissions
{
"permissions": {
"allow": [
"Bash(dotnet *)",
"Bash(npm run *)",
"Bash(ng *)",
"Bash(docker compose *)",
"Bash(docker logs *)",
"Bash(docker ps *)",
"Bash(git diff *)",
"Bash(git status)",
"Bash(git log *)",
"Bash(git add *)",
"Bash(git commit *)"
],
"deny": [
"Bash(git push *)",
"Bash(docker compose down --volumes)",
"Bash(dotnet ef database drop *)"
]
}
}
Confirmation required before push and before destructive DB operations.
.mcp.json — connecting tools
How MCP works and why you need it is covered in a separate article. The config for our stack:
{
"mcpServers": {
"mysql": {
"command": "npx",
"args": ["-y", "@benborla29/mcp-server-mysql"],
"env": {
"MYSQL_HOST": "localhost",
"MYSQL_PORT": "3306",
"MYSQL_USER": "${MYSQL_USER}",
"MYSQL_PASS": "${MYSQL_PASSWORD}",
"MYSQL_DB": "${MYSQL_DATABASE}"
}
},
"mongodb": {
"command": "npx",
"args": ["-y", "mongodb-mcp-server"],
"env": {
"MDB_MCP_CONNECTION_STRING": "${MONGODB_URI}"
}
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
}
}
}
}
Keep secrets in .env (don't commit) — Claude picks up environment variables from the shell.
Skills — ready-made commands
The skill format in detail is in the Skills article; an extended collection for this stack is in Top Skills for .NET + Angular + Docker.
/migrate — create and apply an EF migration
Create .claude/commands/migrate.md:
# Migrate
Create a new EF Core migration named $ARGUMENTS and apply it.
1. Go to the backend/ folder
2. Run: `dotnet ef migrations add $ARGUMENTS --project src/Infrastructure --startup-project src/Api`
3. Inspect the generated migration — check there are no unwanted changes
4. Run: `dotnet ef database update --project src/Infrastructure --startup-project src/Api`
5. Report which tables/columns were changed
Usage: /migrate AddUserEmailIndex
/feature — scaffold a new feature
Create .claude/commands/feature.md:
# Feature
Scaffold a new feature named $ARGUMENTS.
## Backend
1. `Controllers/$ARGUMENTSController.cs` — REST controller with basic CRUD endpoints
2. `Services/I$ARGUMENTSService.cs` + `Services/$ARGUMENTSService.cs`
3. `Repositories/I$ARGUMENTSRepository.cs` + `Repositories/$ARGUMENTSRepository.cs`
4. `DTOs/$ARGUMENTSDto.cs` — Request and Response DTOs
5. Register the service and repository in DI (Program.cs or extension)
## Frontend
1. `src/app/features/$arguments/` — feature folder
2. `$arguments.component.ts` — standalone component (OnPush)
3. `$arguments.service.ts` — service for API access
4. `$arguments.routes.ts` — routes
Use the existing conventions from CLAUDE.md.
Usage: /feature Products
/check — pre-commit check
Create .claude/commands/check.md:
# Check
Check the project before committing.
## Backend
1. `cd backend && dotnet build` — must be 0 errors
2. `dotnet test` — all tests green
3. No `TODO`, `FIXME`, `Console.WriteLine` in the code (except tests)
## Frontend
1. `cd frontend && npm run lint` — 0 ESLint errors
2. `npm run build` — build passes
If everything is fine — write "Ready to commit" and propose a commit message.
If something failed — describe what exactly and how to fix it.
/logs — inspect Docker logs
Create .claude/commands/logs.md:
# Logs
Show and analyze the latest logs of container $ARGUMENTS.
1. `docker compose logs --tail=100 $ARGUMENTS`
2. Highlight errors and warnings
3. If there are errors — explain the cause and propose a fix
If $ARGUMENTS is not provided — show logs of all containers for the last 5 minutes.
Usage: /logs api or /logs
Environment variables
Create .env.example in the root (committed) and .env (in .gitignore):
# .env.example
MYSQL_USER=app
MYSQL_PASSWORD=changeme
MYSQL_DATABASE=myapp
MONGODB_URI=mongodb://localhost:27017/myapp
GITHUB_TOKEN=
Claude Code automatically reads environment variables from the current shell — just run source .env or use direnv.
docker-compose.yml for development
services:
mysql:
image: mysql:8.4
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
mongodb:
image: mongo:7
ports:
- "27017:27017"
volumes:
- mongo_data:/data/db
api:
build: ./backend
ports:
- "5000:8080"
environment:
ConnectionStrings__MySQL: "Server=mysql;Database=${MYSQL_DATABASE};User=${MYSQL_USER};Password=${MYSQL_PASSWORD};"
ConnectionStrings__MongoDB: "mongodb://mongodb:27017/${MYSQL_DATABASE}"
depends_on:
- mysql
- mongodb
volumes:
mysql_data:
mongo_data:
Typical tasks with Claude Code
# Add a new endpoint
"Add POST /api/products with FluentValidation
and saving to MySQL via EF Core"
# Fix from log error
/logs api
"Fix the error from the logs"
# Create an Angular component
"Create a standalone ProductListComponent with pagination
and search, data from ProductService"
# Write tests
"Write unit tests for ProductService, use xUnit and Moq"
# Inspect DB schema and write a query
"Look at the orders table schema and write a query for a sales
report for the month grouped by category"
Summary
CLAUDE.mdin the root — stack description, commands, conventions.claude/settings.json— permissions: yes todotnet,npm,docker compose; no to push and DB drop.mcp.json— connect MySQL and MongoDB MCPs to work with schema and data- Ready-made skills:
/migrate,/feature,/check,/logs - Secrets — only via environment variables, not in configs
Discussion
No comments yet. Be the first.