- Ensure Docker Desktop (or a compatible engine) is running.
- From the repo root (
<repo-root>):docker compose up --build
- Browse to
http://localhost:8080/swaggerand hit Authorize with a token from the login endpoint (see below). - When done, stop containers:
docker compose down
Choose the workflow that fits your machine. Replace <repo-root> with the path where you cloned the repository (use $(pwd) in Git Bash if you are already in the project folder).
cd <repo-root>
MSYS_NO_PATHCONV=1 docker run --rm \
-v "$(pwd)":/workspace \
-w /workspace \
mcr.microsoft.com/dotnet/sdk:8.0 \
dotnet restore
MSYS_NO_PATHCONV=1 docker run --rm \
-v "$(pwd)":/workspace \
-w /workspace \
mcr.microsoft.com/dotnet/sdk:8.0 \
dotnet buildUse the same containerized pattern for dotnet test, dotnet ef, or any other CLI command by swapping the final subcommand.
cd <repo-root>
# Restore dependencies
dotnet restore
# Compile all projects
dotnet build
# Run unit tests
dotnet testThe API self-applies EF Core migrations on startup.
# Local SDK
dotnet run --project src/Deckio.Api/Deckio.Api.csproj
# Docker SDK with forwarded ports
MSYS_NO_PATHCONV=1 docker run --rm \
-v "$(pwd)":/workspace \
-w /workspace \
-p 5000:5000 -p 5001:5001 \
mcr.microsoft.com/dotnet/sdk:8.0 \
dotnet run --project src/Deckio.Api/Deckio.Api.csprojKestrel listens on http://localhost:5000 and https://localhost:5001 in this mode.
| UserId | Username | Primary JWT Claim |
|---|---|---|
| 1 | User 1 | ClaimTypes.NameIdentifier = 1 |
| 2 | User 2 | ClaimTypes.NameIdentifier = 2 |
Login is username-only. Submit this payload via Swagger or curl:
{
"Username": "User 1"
}The response includes a JWT token. Copy it into the Swagger Authorize dialog as Bearer <token>.
After authorizing with a token:
-
Read cart (GET route)
GET /api/cart/users/{userId}/contentReturns the user’s active cart when the caller can put the identifier in the route.
-
Read cart (POST body alias)
{ "UserId": 1 }POST /api/cart/contentperforms the same read as the GET endpoint but accepts the identifier in the body. Sample response:{ "UserId": 1, "Name": "User 1", "Cart": [ { "ItemId": 2, "Name": "Item 2", "Price": 2.22, "Quantity": 2 } ], "UpdatedAtUtc": "2025-10-12T20:30:00Z" } -
Replace cart (write)
{ "UserId": 1, "Cart": [ { "ItemId": 2, "Quantity": 2 }, { "ItemId": 3, "Quantity": 1 } ] }PUT /api/cart/contentoverwrites the cart with the supplied items and records a snapshot.
All cart endpoints require the Authorization: Bearer <token> header.
GET /api/users– lists all seeded users.GET /api/users/{id}– retrieves a specific user by identifier.
– Overview of every published endpoint after compose boots.
– Successful login showing the issued JWT.
– Copy the token into Swagger’s Authorize dialog before calling PUT.
– GETcart response with seeded sample data.
Swagger UI is available at http://localhost:8080/swagger.
Deckio follows a layered, hexagon-inspired architecture that keeps HTTP concerns at the edge and business logic in the center.
- Deckio.Domain: Entity models (
User,Item,Cart,CartItem,CartSnapshot), value semantics, and relationships. - Deckio.Application: Request/response DTOs, service interfaces (
IAuthenticationService,ICartService,IItemService), and FluentValidation validators. - Deckio.Infrastructure: EF Core persistence (
DeckioDbContext, entity configurations, migrations), JWT token generation, service implementations. - Deckio.Api: ASP.NET Core host with controllers (
AuthController,CartController), middleware pipeline, DI wiring, health checks, and Swagger setup. - Tests (Deckio.Tests): xUnit projects using EF Core InMemory and Moq for authentication and cart workflows.
Key characteristics:
- CQRS-lite: DTOs represent requests/responses; services handle command/query logic.
- Persistence abstraction: Application layer interacts with interfaces; EF Core details stay in Infrastructure.
- Observability first: OpenTelemetry tracing, structured logging, health checks, and problem details with trace IDs are enabled out of the box.
- Security: JWT authentication with per-user authorization checks, configurable via
JwtOptionsand environment variables.
Deckio.sln
├── src/
│ ├── Deckio.Api/
│ │ ├── Controllers/
│ │ ├── Program.cs
│ │ └── Swagger/ # Schema filters for Swagger examples
│ ├── Deckio.Application/
│ │ ├── DTOs/
│ │ ├── Interfaces/
│ │ └── Validators/
│ ├── Deckio.Domain/
│ │ └── Entities/
│ └── Deckio.Infrastructure/
│ ├── Extensions/
│ ├── Options/
│ ├── Persistence/
│ │ ├── Configurations/
│ │ └── Migrations/
│ └── Services/
├── tests/
│ └── Deckio.Tests/
├── docs/
│ └── images/ # Placeholder for screenshots referenced above
├── Dockerfile
├── docker-compose.yml
└── README.md
- Program startup (
Program.cs): configures services, problem details withtraceId, OpenTelemetry tracing, FluentValidation, JWT auth, and Swagger. Applies EF Core migrations (dbContext.Database.Migrate()). - Request entry: Controllers receive HTTP requests and map them to application-layer services via interfaces.
- Validation: FluentValidation runs automatically on DTOs; invalid payloads yield HTTP 400 with detailed messages.
- Domain logic: Application services orchestrate queries/commands, leverage validators, and project entities into responses.
- Persistence: Infrastructure layer executes EF Core operations, manages transactions, and records cart snapshots.
- Response: Controllers translate service results into HTTP responses (e.g., 200 with DTO payloads, 204 for
PUT, 401/403/404 as appropriate).
- Health checks:
GET http://localhost:8080/healthreports readiness. - OpenTelemetry: ASP.NET Core and outgoing HTTP spans exported to console (
docker logs deckio-api). - Problem details: Error responses include
traceIdfor correlation. - Logging: Standard ASP.NET Core logs available via
docker logs deckio-apiordocker compose logs -f.
| Purpose | Command |
|---|---|
| Build & run stack | docker compose up --build |
| Run without rebuild | docker compose up -d |
| View logs | docker compose logs -f or docker logs deckio-api |
| Stop containers | docker compose down |
| Reset containers & data | docker compose down -v |
| Stop only API | docker stop deckio-api |
| Run tests in SDK container | MSYS_NO_PATHCONV=1 docker run --rm -v "$(pwd)":/workspace -w /workspace mcr.microsoft.com/dotnet/sdk:8.0 dotnet test |
Environment overrides (connection string, JWT options) are defined in docker-compose.yml and can be adjusted per environment. The default SQL credentials are sa / YourStrong!Passw0rd inside the container.