Chapter 23: Development Environment Setup
Overview
This chapter provides complete, step-by-step instructions for setting up your development environment for the POS platform. By the end, you will have a fully functional local development stack.
Prerequisites
Required Software
| Software | Version | Purpose |
|---|---|---|
| .NET SDK | 8.0+ | Backend development |
| PostgreSQL | 16+ | Primary database |
| Docker | 24.0+ | Containerization |
| Docker Compose | 2.20+ | Multi-container orchestration |
| Node.js | 20 LTS | Frontend tooling |
| Git | 2.40+ | Version control |
Hardware Requirements
| Component | Minimum | Recommended |
|---|---|---|
| RAM | 8 GB | 16 GB |
| Storage | 20 GB free | 50 GB SSD |
| CPU | 4 cores | 8 cores |
Project Structure
/volume1/docker/pos-platform/
├── CLAUDE.md # AI assistant guidance
├── README.md # Quick start guide
├── .gitignore # Git ignore patterns
├── .env.example # Environment template
├── pos-platform.sln # .NET solution file
│
├── docker/
│ ├── docker-compose.yml # Development stack
│ ├── docker-compose.prod.yml # Production overrides
│ ├── Dockerfile # API container build
│ ├── Dockerfile.web # Web container build
│ └── .env # Docker environment (gitignored)
│
├── src/
│ ├── PosPlatform.Core/ # Domain layer
│ │ ├── Entities/ # Domain entities
│ │ ├── ValueObjects/ # Immutable value objects
│ │ ├── Events/ # Domain events
│ │ ├── Exceptions/ # Domain exceptions
│ │ ├── Interfaces/ # Repository interfaces
│ │ └── Services/ # Domain services
│ │
│ ├── PosPlatform.Infrastructure/ # Infrastructure layer
│ │ ├── Data/ # EF Core contexts
│ │ ├── Repositories/ # Repository implementations
│ │ ├── Services/ # External service integrations
│ │ ├── Messaging/ # Event bus, queues
│ │ └── MultiTenant/ # Tenant resolution
│ │
│ ├── PosPlatform.Api/ # API layer
│ │ ├── Controllers/ # REST endpoints
│ │ ├── Middleware/ # Request pipeline
│ │ ├── Filters/ # Action filters
│ │ ├── DTOs/ # Data transfer objects
│ │ └── Program.cs # Application entry
│ │
│ └── PosPlatform.Web/ # Blazor frontend
│ ├── Components/ # Blazor components
│ ├── Pages/ # Routable pages
│ ├── Services/ # Frontend services
│ └── wwwroot/ # Static assets
│
├── tests/
│ ├── PosPlatform.Core.Tests/ # Unit tests
│ ├── PosPlatform.Api.Tests/ # API integration tests
│ └── PosPlatform.E2E.Tests/ # End-to-end tests
│
└── database/
├── migrations/ # EF Core migrations
├── seed/ # Seed data scripts
└── init.sql # Database initialization
Step 1: Install Prerequisites
Linux (Ubuntu/Debian)
# Update package manager
sudo apt update && sudo apt upgrade -y
# Install .NET 8 SDK
wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt update
sudo apt install -y dotnet-sdk-8.0
# Verify .NET installation
dotnet --version
# Install Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Log out and back in for group changes
# Verify Docker
docker --version
docker compose version
# Install Node.js 20 LTS
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
# Verify Node.js
node --version
npm --version
# Install Git
sudo apt install -y git
git --version
macOS
# Install Homebrew (if not installed)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Install .NET 8 SDK
brew install dotnet-sdk
# Install Docker Desktop
brew install --cask docker
# Install Node.js
brew install node@20
# Install Git
brew install git
Windows
# Install with winget (Windows Package Manager)
winget install Microsoft.DotNet.SDK.8
winget install Docker.DockerDesktop
winget install OpenJS.NodeJS.LTS
winget install Git.Git
# Alternatively, download installers from:
# - https://dotnet.microsoft.com/download
# - https://docker.com/products/docker-desktop
# - https://nodejs.org/
# - https://git-scm.com/
Step 2: Create Project Structure
Initialize Repository
# Create project directory
mkdir -p /volume1/docker/pos-platform
cd /volume1/docker/pos-platform
# Initialize Git repository
git init
git branch -M main
# Create initial structure
mkdir -p docker src tests database/migrations database/seed
Create .gitignore
cat > .gitignore << 'EOF'
# Build outputs
bin/
obj/
publish/
# IDE
.vs/
.vscode/
.idea/
*.user
*.suo
# Environment
.env
*.env.local
appsettings.*.json
!appsettings.json
!appsettings.Development.json
# Logs
logs/
*.log
# Docker
docker/.env
# Node
node_modules/
dist/
# Database
*.db
*.sqlite
# OS
.DS_Store
Thumbs.db
# Secrets
*.pem
*.key
secrets/
EOF
Create Solution File
# Create .NET solution
dotnet new sln -n pos-platform
# Create projects
dotnet new classlib -n PosPlatform.Core -o src/PosPlatform.Core
dotnet new classlib -n PosPlatform.Infrastructure -o src/PosPlatform.Infrastructure
dotnet new webapi -n PosPlatform.Api -o src/PosPlatform.Api
dotnet new blazorserver -n PosPlatform.Web -o src/PosPlatform.Web
# Create test projects
dotnet new xunit -n PosPlatform.Core.Tests -o tests/PosPlatform.Core.Tests
dotnet new xunit -n PosPlatform.Api.Tests -o tests/PosPlatform.Api.Tests
# Add projects to solution
dotnet sln add src/PosPlatform.Core/PosPlatform.Core.csproj
dotnet sln add src/PosPlatform.Infrastructure/PosPlatform.Infrastructure.csproj
dotnet sln add src/PosPlatform.Api/PosPlatform.Api.csproj
dotnet sln add src/PosPlatform.Web/PosPlatform.Web.csproj
dotnet sln add tests/PosPlatform.Core.Tests/PosPlatform.Core.Tests.csproj
dotnet sln add tests/PosPlatform.Api.Tests/PosPlatform.Api.Tests.csproj
# Add project references
dotnet add src/PosPlatform.Infrastructure/PosPlatform.Infrastructure.csproj reference src/PosPlatform.Core/PosPlatform.Core.csproj
dotnet add src/PosPlatform.Api/PosPlatform.Api.csproj reference src/PosPlatform.Infrastructure/PosPlatform.Infrastructure.csproj
dotnet add src/PosPlatform.Api/PosPlatform.Api.csproj reference src/PosPlatform.Core/PosPlatform.Core.csproj
dotnet add src/PosPlatform.Web/PosPlatform.Web.csproj reference src/PosPlatform.Core/PosPlatform.Core.csproj
dotnet add tests/PosPlatform.Core.Tests/PosPlatform.Core.Tests.csproj reference src/PosPlatform.Core/PosPlatform.Core.csproj
dotnet add tests/PosPlatform.Api.Tests/PosPlatform.Api.Tests.csproj reference src/PosPlatform.Api/PosPlatform.Api.csproj
Step 3: Docker Configuration
docker-compose.yml
# /volume1/docker/pos-platform/docker/docker-compose.yml
version: '3.8'
services:
# PostgreSQL Database
postgres:
image: postgres:16-alpine
container_name: pos-postgres
environment:
POSTGRES_USER: ${DB_USER:-pos_admin}
POSTGRES_PASSWORD: ${DB_PASSWORD:-PosDevPass2025!}
POSTGRES_DB: ${DB_NAME:-pos_platform}
ports:
- "5434:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ../database/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-pos_admin} -d ${DB_NAME:-pos_platform}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- pos-network
# Redis for Caching and Sessions
redis:
image: redis:7-alpine
container_name: pos-redis
ports:
- "6380:6379"
volumes:
- redis_data:/data
command: redis-server --appendonly yes
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- pos-network
# RabbitMQ for Event Bus
rabbitmq:
image: rabbitmq:3-management-alpine
container_name: pos-rabbitmq
environment:
RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-pos_user}
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASS:-PosRabbit2025!}
ports:
- "5673:5672" # AMQP
- "15673:15672" # Management UI
volumes:
- rabbitmq_data:/var/lib/rabbitmq
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "check_running"]
interval: 30s
timeout: 10s
retries: 5
networks:
- pos-network
# POS API (Development)
api:
build:
context: ..
dockerfile: docker/Dockerfile
container_name: pos-api
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://+:8080
- ConnectionStrings__DefaultConnection=Host=postgres;Port=5432;Database=${DB_NAME:-pos_platform};Username=${DB_USER:-pos_admin};Password=${DB_PASSWORD:-PosDevPass2025!}
- Redis__ConnectionString=redis:6379
- RabbitMQ__Host=rabbitmq
- RabbitMQ__Username=${RABBITMQ_USER:-pos_user}
- RabbitMQ__Password=${RABBITMQ_PASS:-PosRabbit2025!}
ports:
- "5100:8080"
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
rabbitmq:
condition: service_healthy
volumes:
- ../src:/app/src:ro
- api_logs:/app/logs
networks:
- pos-network
# POS Web (Development)
web:
build:
context: ..
dockerfile: docker/Dockerfile.web
container_name: pos-web
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://+:8080
- ApiBaseUrl=http://api:8080
ports:
- "5101:8080"
depends_on:
- api
networks:
- pos-network
volumes:
postgres_data:
redis_data:
rabbitmq_data:
api_logs:
networks:
pos-network:
driver: bridge
Dockerfile for API
# /volume1/docker/pos-platform/docker/Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build
WORKDIR /src
# Copy solution and project files
COPY *.sln ./
COPY src/PosPlatform.Core/*.csproj ./src/PosPlatform.Core/
COPY src/PosPlatform.Infrastructure/*.csproj ./src/PosPlatform.Infrastructure/
COPY src/PosPlatform.Api/*.csproj ./src/PosPlatform.Api/
# Restore dependencies
RUN dotnet restore src/PosPlatform.Api/PosPlatform.Api.csproj
# Copy source code
COPY src/ ./src/
# Build and publish
WORKDIR /src/src/PosPlatform.Api
RUN dotnet publish -c Release -o /app/publish --no-restore
# Runtime image
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine AS runtime
WORKDIR /app
# Install culture support
RUN apk add --no-cache icu-libs
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
# Copy published app
COPY --from=build /app/publish .
# Create non-root user
RUN adduser -D -u 1000 appuser && chown -R appuser:appuser /app
USER appuser
EXPOSE 8080
ENTRYPOINT ["dotnet", "PosPlatform.Api.dll"]
Dockerfile for Web
# /volume1/docker/pos-platform/docker/Dockerfile.web
FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build
WORKDIR /src
# Copy solution and project files
COPY *.sln ./
COPY src/PosPlatform.Core/*.csproj ./src/PosPlatform.Core/
COPY src/PosPlatform.Web/*.csproj ./src/PosPlatform.Web/
# Restore dependencies
RUN dotnet restore src/PosPlatform.Web/PosPlatform.Web.csproj
# Copy source code
COPY src/ ./src/
# Build and publish
WORKDIR /src/src/PosPlatform.Web
RUN dotnet publish -c Release -o /app/publish --no-restore
# Runtime image
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine AS runtime
WORKDIR /app
RUN apk add --no-cache icu-libs
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
COPY --from=build /app/publish .
RUN adduser -D -u 1000 appuser && chown -R appuser:appuser /app
USER appuser
EXPOSE 8080
ENTRYPOINT ["dotnet", "PosPlatform.Web.dll"]
Environment Template
# /volume1/docker/pos-platform/docker/.env.example
# Database
DB_USER=pos_admin
DB_PASSWORD=PosDevPass2025!
DB_NAME=pos_platform
# RabbitMQ
RABBITMQ_USER=pos_user
RABBITMQ_PASS=PosRabbit2025!
# API Keys (development)
JWT_SECRET=dev-jwt-secret-key-min-32-characters-long
ENCRYPTION_KEY=dev-encryption-key-32-chars-long
Step 4: Database Initialization
init.sql
-- /volume1/docker/pos-platform/database/init.sql
-- Create extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pg_trgm";
-- Create shared schema for platform-wide data
CREATE SCHEMA IF NOT EXISTS shared;
-- Tenants table (platform-wide)
CREATE TABLE shared.tenants (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
code VARCHAR(10) NOT NULL UNIQUE,
name VARCHAR(100) NOT NULL,
domain VARCHAR(255),
status VARCHAR(20) NOT NULL DEFAULT 'active',
settings JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ
);
-- Platform users (super admins)
CREATE TABLE shared.platform_users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
full_name VARCHAR(100) NOT NULL,
role VARCHAR(50) NOT NULL DEFAULT 'admin',
is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Function to create tenant schema
CREATE OR REPLACE FUNCTION shared.create_tenant_schema(tenant_code VARCHAR)
RETURNS VOID AS $$
BEGIN
EXECUTE format('CREATE SCHEMA IF NOT EXISTS tenant_%s', tenant_code);
-- Create tenant-specific tables
EXECUTE format('
CREATE TABLE tenant_%s.locations (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
code VARCHAR(10) NOT NULL UNIQUE,
name VARCHAR(100) NOT NULL,
address JSONB,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW()
)', tenant_code);
EXECUTE format('
CREATE TABLE tenant_%s.users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
employee_id VARCHAR(20) UNIQUE,
full_name VARCHAR(100) NOT NULL,
email VARCHAR(255),
pin_hash VARCHAR(255),
role VARCHAR(50) NOT NULL,
location_id UUID REFERENCES tenant_%s.locations(id),
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW()
)', tenant_code, tenant_code);
EXECUTE format('
CREATE TABLE tenant_%s.products (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
sku VARCHAR(50) NOT NULL UNIQUE,
name VARCHAR(255) NOT NULL,
description TEXT,
category_id UUID,
base_price DECIMAL(10,2) NOT NULL,
cost DECIMAL(10,2),
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ
)', tenant_code);
END;
$$ LANGUAGE plpgsql;
-- Insert default platform admin
INSERT INTO shared.platform_users (email, password_hash, full_name, role)
VALUES (
'admin@posplatform.local',
'$2a$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/X4.vttYqBZq.kxVQ6', -- "admin123"
'Platform Administrator',
'super_admin'
);
-- Insert demo tenant
INSERT INTO shared.tenants (code, name, domain, status, settings)
VALUES (
'DEMO',
'Demo Retail Store',
'demo.posplatform.local',
'active',
'{"timezone": "America/New_York", "currency": "USD", "taxRate": 0.07}'
);
-- Create demo tenant schema
SELECT shared.create_tenant_schema('demo');
COMMENT ON SCHEMA shared IS 'Platform-wide shared data';
Step 5: IDE Setup
VS Code Configuration
// /volume1/docker/pos-platform/.vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "ms-dotnettools.csharp",
"omnisharp.enableRoslynAnalyzers": true,
"omnisharp.enableEditorConfigSupport": true,
"dotnet.defaultSolution": "pos-platform.sln",
"files.exclude": {
"**/bin": true,
"**/obj": true,
"**/node_modules": true
},
"[csharp]": {
"editor.defaultFormatter": "ms-dotnettools.csharp"
}
}
// /volume1/docker/pos-platform/.vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch API",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build-api",
"program": "${workspaceFolder}/src/PosPlatform.Api/bin/Debug/net8.0/PosPlatform.Api.dll",
"args": [],
"cwd": "${workspaceFolder}/src/PosPlatform.Api",
"console": "internalConsole",
"stopAtEntry": false,
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
{
"name": "Launch Web",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build-web",
"program": "${workspaceFolder}/src/PosPlatform.Web/bin/Debug/net8.0/PosPlatform.Web.dll",
"args": [],
"cwd": "${workspaceFolder}/src/PosPlatform.Web",
"console": "internalConsole",
"stopAtEntry": false
}
]
}
Recommended VS Code Extensions
// /volume1/docker/pos-platform/.vscode/extensions.json
{
"recommendations": [
"ms-dotnettools.csharp",
"ms-dotnettools.csdevkit",
"ms-azuretools.vscode-docker",
"eamodio.gitlens",
"streetsidesoftware.code-spell-checker",
"editorconfig.editorconfig",
"humao.rest-client",
"mtxr.sqltools",
"mtxr.sqltools-driver-pg"
]
}
Step 6: Git Workflow
Branch Strategy
main # Production-ready code
|
+-- develop # Integration branch
|
+-- feature/* # New features
+-- bugfix/* # Bug fixes
+-- hotfix/* # Urgent production fixes
Initial Commit
cd /volume1/docker/pos-platform
# Stage all files
git add .
# Initial commit
git commit -m "Initial project structure with Docker development stack
- Created .NET 8 solution with 4 projects (Core, Infrastructure, Api, Web)
- Added docker-compose with PostgreSQL 16, Redis, RabbitMQ
- Configured multi-tenant database initialization
- Set up VS Code development environment
Generated with Claude Code"
# Create develop branch
git checkout -b develop
Quick Reference Commands
Start Development Stack
cd /volume1/docker/pos-platform/docker
# Copy environment file
cp .env.example .env
# Start all services
docker compose up -d
# View logs
docker compose logs -f
# Check status
docker compose ps
Database Access
# Connect to PostgreSQL
docker exec -it pos-postgres psql -U pos_admin -d pos_platform
# List schemas
\dn
# List tables in shared schema
\dt shared.*
# List tables in tenant schema
\dt tenant_demo.*
Build and Run Locally
cd /volume1/docker/pos-platform
# Restore dependencies
dotnet restore
# Build solution
dotnet build
# Run API (from project directory)
cd src/PosPlatform.Api
dotnet run
# Run tests
cd /volume1/docker/pos-platform
dotnet test
Stop and Clean
cd /volume1/docker/pos-platform/docker
# Stop services
docker compose down
# Stop and remove volumes (WARNING: deletes data)
docker compose down -v
# Remove unused images
docker image prune -f
Verification Checklist
After completing setup, verify each component:
-
dotnet --versionshows 8.0.x -
docker compose psshows all containers healthy - PostgreSQL accepts connections on port 5434
- Redis responds to ping on port 6380
- RabbitMQ management UI accessible at http://localhost:15673
- Solution builds without errors:
dotnet build - All tests pass:
dotnet test
Next Steps
With your development environment ready:
- Proceed to Chapter 24: Implementation Roadmap for the full build plan
- Begin Phase 1: Foundation in Chapter 25
- Reference Chapter 23 when adding new developers to the project
Chapter 23 Complete - Development Environment Setup