# Development Guide

## Quick Start Commands

### Build Solution
```bash
dotnet build PowderCoatingApp.sln
```

### Run Web Application
```bash
cd src/PowderCoating.Web
dotnet run
```

### Run API
```bash
cd src/PowderCoating.Api
dotnet run
```

### Watch Mode (Auto-reload)
```bash
cd src/PowderCoating.Web
dotnet watch run
```

## Entity Framework Core Commands

### Add Migration
```bash
cd src/PowderCoating.Web
dotnet ef migrations add MigrationName --project ../PowderCoating.Infrastructure
```

### Update Database
```bash
dotnet ef database update --project ../PowderCoating.Infrastructure
```

### Remove Last Migration
```bash
dotnet ef migrations remove --project ../PowderCoating.Infrastructure
```

### Generate SQL Script
```bash
dotnet ef migrations script --project ../PowderCoating.Infrastructure --output migration.sql
```

### View Migrations
```bash
dotnet ef migrations list --project ../PowderCoating.Infrastructure
```

## Project Management

### Add New NuGet Package
```bash
cd src/PowderCoating.Core
dotnet add package PackageName
```

### Restore Packages
```bash
dotnet restore
```

### Clean Solution
```bash
dotnet clean
```

## Creating New Components

### Add New Entity

1. Create entity class in `PowderCoating.Core/Entities/`
2. Inherit from `BaseEntity`
3. Add DbSet to `ApplicationDbContext`
4. Add repository to `IUnitOfWork` and `UnitOfWork`
5. Create migration
6. Update database

Example:
```csharp
// 1. Create entity
public class NewEntity : BaseEntity
{
    public string Name { get; set; } = string.Empty;
    // ... properties
}

// 2. Add to DbContext
public DbSet<NewEntity> NewEntities { get; set; }

// 3. Add to IUnitOfWork
IRepository<NewEntity> NewEntities { get; }

// 4. Add to UnitOfWork
private IRepository<NewEntity>? _newEntities;
public IRepository<NewEntity> NewEntities => 
    _newEntities ??= new Repository<NewEntity>(_context);

// 5. Add migration
dotnet ef migrations add AddNewEntity --project ../PowderCoating.Infrastructure

// 6. Update database
dotnet ef database update --project ../PowderCoating.Infrastructure
```

### Add New Controller (Web)

1. Create in `PowderCoating.Web/Controllers/`
2. Inherit from `Controller`
3. Inject `IUnitOfWork` and `IMapper`
4. Create corresponding views in `Views/[ControllerName]/`

Example:
```csharp
public class NewController : Controller
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly IMapper _mapper;

    public NewController(IUnitOfWork unitOfWork, IMapper mapper)
    {
        _unitOfWork = unitOfWork;
        _mapper = mapper;
    }

    public async Task<IActionResult> Index()
    {
        var items = await _unitOfWork.NewEntities.GetAllAsync();
        return View(items);
    }
}
```

### Add New API Controller

1. Create in `PowderCoating.Api/Controllers/`
2. Add `[ApiController]` and `[Route("api/[controller]")]` attributes
3. Inject dependencies
4. Return appropriate `ActionResult<T>` types

Example:
```csharp
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class NewApiController : ControllerBase
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly IMapper _mapper;

    public NewApiController(IUnitOfWork unitOfWork, IMapper mapper)
    {
        _unitOfWork = unitOfWork;
        _mapper = mapper;
    }

    [HttpGet]
    public async Task<ActionResult<IEnumerable<NewDto>>> GetAll()
    {
        var items = await _unitOfWork.NewEntities.GetAllAsync();
        var dtos = _mapper.Map<IEnumerable<NewDto>>(items);
        return Ok(dtos);
    }
}
```

### Add New DTO

1. Create in `PowderCoating.Application/DTOs/[Module]/`
2. Create AutoMapper profile

Example:
```csharp
// DTO
public class NewDto
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
}

// AutoMapper Profile
public class NewProfile : Profile
{
    public NewProfile()
    {
        CreateMap<NewEntity, NewDto>();
        CreateMap<CreateNewDto, NewEntity>();
    }
}
```

## Best Practices

### Code Style
- Follow C# coding conventions
- Use meaningful variable and method names
- Add XML documentation for public APIs
- Keep methods focused (Single Responsibility)
- Use async/await for I/O operations

### Entity Framework
- Use async methods (`ToListAsync`, `FirstOrDefaultAsync`, etc.)
- Include related entities when needed (`Include`, `ThenInclude`)
- Use `.AsNoTracking()` for read-only queries
- Handle concurrency conflicts
- Use transactions for multi-step operations

### API Development
- Use appropriate HTTP status codes
- Validate input with FluentValidation
- Use DTOs, never expose entities directly
- Document endpoints with XML comments for Swagger
- Implement proper error handling

### Security
- Always validate user input
- Use parameterized queries (EF Core does this)
- Implement authorization on controllers/actions
- Don't expose sensitive data in responses
- Use HTTPS in production
- Store secrets in user secrets or Azure Key Vault

### Performance
- Use pagination for large datasets
- Implement caching where appropriate
- Use projection (Select) to retrieve only needed fields
- Profile and optimize slow queries
- Use async for I/O-bound operations

## Common Patterns

### Service Pattern
```csharp
public interface IJobService
{
    Task<JobDto> GetByIdAsync(int id);
    Task<IEnumerable<JobDto>> GetAllAsync();
    Task<JobDto> CreateAsync(CreateJobDto dto);
    Task UpdateAsync(UpdateJobDto dto);
    Task DeleteAsync(int id);
}

public class JobService : IJobService
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly IMapper _mapper;

    public JobService(IUnitOfWork unitOfWork, IMapper mapper)
    {
        _unitOfWork = unitOfWork;
        _mapper = mapper;
    }

    // Implementation...
}
```

### Repository Pattern (Already Implemented)
```csharp
var customers = await _unitOfWork.Customers.FindAsync(c => c.IsActive);
var customer = await _unitOfWork.Customers.GetByIdAsync(id);
await _unitOfWork.Customers.AddAsync(newCustomer);
await _unitOfWork.SaveChangesAsync();
```

### Unit of Work with Transaction
```csharp
try
{
    await _unitOfWork.BeginTransactionAsync();
    
    // Multiple operations
    await _unitOfWork.Jobs.AddAsync(job);
    await _unitOfWork.JobItems.AddRangeAsync(items);
    
    await _unitOfWork.CommitTransactionAsync();
}
catch
{
    await _unitOfWork.RollbackTransactionAsync();
    throw;
}
```

## Debugging Tips

### Enable Sensitive Data Logging
In `appsettings.Development.json`:
```json
"Logging": {
  "LogLevel": {
    "Microsoft.EntityFrameworkCore.Database.Command": "Information"
  }
}
```

In `DbContext` configuration (development only):
```csharp
options.UseSqlServer(connectionString)
    .EnableSensitiveDataLogging()
    .EnableDetailedErrors();
```

### View Generated SQL
```csharp
var query = _context.Jobs.Where(j => j.Status == JobStatus.Pending);
var sql = query.ToQueryString();
Console.WriteLine(sql);
```

### Common Issues

**Issue**: Migration fails with "object already exists"
```bash
# Solution: Remove migration and try again
dotnet ef migrations remove --project ../PowderCoating.Infrastructure
dotnet ef migrations add NewMigration --project ../PowderCoating.Infrastructure
```

**Issue**: DbContext is disposed
```bash
# Solution: Ensure you're using proper DI scoping and not storing DbContext
# Use IUnitOfWork which has proper lifetime management
```

**Issue**: Circular reference in JSON
```csharp
// Solution: Use DTOs or configure JSON serialization
services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
    });
```

## Testing

### Unit Test Example
```csharp
public class CustomerServiceTests
{
    [Fact]
    public async Task GetByIdAsync_ReturnsCustomer_WhenExists()
    {
        // Arrange
        var mockUnitOfWork = new Mock<IUnitOfWork>();
        var customer = new Customer { Id = 1, CompanyName = "Test" };
        
        mockUnitOfWork
            .Setup(x => x.Customers.GetByIdAsync(1))
            .ReturnsAsync(customer);

        var service = new CustomerService(mockUnitOfWork.Object, mapper);

        // Act
        var result = await service.GetByIdAsync(1);

        // Assert
        Assert.NotNull(result);
        Assert.Equal("Test", result.CompanyName);
    }
}
```

## Deployment

### Publish Web Application
```bash
cd src/PowderCoating.Web
dotnet publish -c Release -o ./publish
```

### Publish API
```bash
cd src/PowderCoating.Api
dotnet publish -c Release -o ./publish
```

### Generate Database Script for Production
```bash
cd src/PowderCoating.Web
dotnet ef migrations script --project ../PowderCoating.Infrastructure --idempotent --output deploy.sql
```

## Resources

- [ASP.NET Core Documentation](https://docs.microsoft.com/aspnet/core)
- [Entity Framework Core Documentation](https://docs.microsoft.com/ef/core)
- [Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)
- [C# Coding Conventions](https://docs.microsoft.com/dotnet/csharp/fundamentals/coding-style/coding-conventions)
