# LittleShop Development - Technical Lessons Learned ## 🔑 Critical Discoveries & Solutions ### 1. **ASP.NET Core 9.0 Authentication Architecture** - **Dual Authentication Schemes**: Successfully implemented both Cookie (for MVC Admin Panel) and JWT Bearer (for API) authentication in the same application - **Key Learning**: Must specify authentication scheme explicitly when using multiple schemes - **Implementation**: Cookie auth uses `[Authorize(AuthenticationSchemes = "Cookies")]`, JWT uses `[Authorize(AuthenticationSchemes = "Bearer")]` ### 2. **Entity Framework Core with SQLite** - **Decimal Ordering Issue**: SQLite cannot order by decimal columns directly - **Solution**: Load data into memory first, then apply ordering ```csharp // Won't work in SQLite: .OrderBy(sr => sr.MinWeight) // Solution: var rates = await _context.ShippingRates.ToListAsync(); return rates.OrderBy(sr => sr.MinWeight); ``` ### 3. **Service Constructor Dependencies** - **ProductService Evolution**: Initially had IMapper dependency, later changed to IWebHostEnvironment for file handling - **CategoryService**: Simplified to only require DbContext, no mapper needed - **Lesson**: Services evolved based on actual needs rather than anticipated patterns ### 4. **Model Property Naming Conventions** - **Initial Design**: Used non-standard names (BasePrice, ProductWeight, ProductWeightUnit) - **Refactored To**: Standard e-commerce names (Price, Weight, WeightUnit) - **Impact**: Required updating all DTOs, services, views, and tests - **Lesson**: Follow industry-standard naming conventions from the start ### 5. **Test Project Configuration** - **Mock Dependencies**: Use Moq for IWebHostEnvironment in unit tests - **In-Memory Database**: Works well for testing with `UseInMemoryDatabase()` - **Authentication in Tests**: Create JWT tokens manually for integration tests ```csharp var token = JwtTokenHelper.GenerateJwtToken(); _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); ``` ### 6. **File Upload Implementation** - **LINQ Translation Issues**: Complex LINQ queries with DefaultIfEmpty() don't translate to SQL - **Solution**: Use nullable casts and null coalescing ```csharp // Problematic: .Select(pp => pp.SortOrder).DefaultIfEmpty(0).Max() // Solution: .Select(pp => (int?)pp.SortOrder).MaxAsync() ?? 0 ``` ### 7. **Git Commit in Windows/WSL** - **Issue**: Complex multi-line commit messages fail with standard quotes - **Solution**: Write commit message to file, use `-F` flag ```bash git commit -F commit_msg.txt ``` ### 8. **API Security Design Decision** - **Critical Requirement**: NO public endpoints - all require authentication - **Implementation**: Every API endpoint requires JWT token - **Rationale**: Client applications handle public presentation after authentication - **Impact**: Simplified security model, consistent authorization ### 9. **WSL2 Development Environment** - **Command Execution**: Must use `cmd.exe /c` for .NET commands in WSL - **File Locking**: Application must be stopped before rebuilding (common WSL issue) - **Path Handling**: Use `/mnt/c/` for Windows paths in WSL ### 10. **Client SDK Design Patterns** - **Retry Policies**: Polly integration for transient failure handling - **Error Handling**: Middleware pattern for consistent error responses - **DI Integration**: Extension methods for easy service registration - **Response Wrapping**: ApiResponse pattern for consistent error handling ## 📊 Database Design Decisions ### Shipping Information - **Added to Orders**: Full shipping details (Name, Address, City, PostCode, Country) - **Separate ShippingRates Table**: Weight-based calculation system - **Lesson**: E-commerce requires comprehensive shipping information upfront ### Payment Status Evolution - **Original Enum Values**: Pending, Confirmed, Failed - **Changed To**: Pending, Paid, Failed, Expired, Cancelled - **Reason**: Better alignment with cryptocurrency payment lifecycle ### Order Status Values - **Original**: Pending, Processing, Shipped - **Updated**: PendingPayment, PaymentReceived, Processing, Shipped, Delivered, Cancelled - **Benefit**: More granular order tracking ## 🏗️ Architecture Patterns That Worked ### 1. **Service Layer Pattern** - Clean separation between controllers and business logic - Each service has its interface - Easy to mock for testing ### 2. **DTO Pattern** - Separate DTOs for Create, Update, and View operations - Prevents over-posting attacks - Clear API contracts ### 3. **Repository Pattern (via EF Core)** - DbContext acts as Unit of Work - No need for additional repository layer with EF Core - Simplified data access ### 4. **Areas for Admin Panel** - `/Areas/Admin/` structure keeps admin code separate - Own controllers, views, and routing - Clear separation of concerns ## 🐛 Common Issues & Fixes ### View Compilation Issues - **Problem**: Runtime changes to views not reflected - **Solution**: Restart application in production mode - **Better Solution**: Use development mode for active development ### ModelState Validation - **Issue**: Empty validation summaries appearing - **Cause**: ModelState checking even for GET requests - **Fix**: Only display validation summary on POST ### Nullable Reference Warnings - **Common in Views**: `Model.Property` warnings - **Solution**: Use null-conditional operator `Model?.Property` - **Alternative**: Use `new()` initialization in view model ## 🚀 Performance Optimizations ### 1. **Query Optimization** - Use `.Include()` for eager loading - Use `.AsNoTracking()` for read-only queries - Project to DTOs in queries to reduce data transfer ### 2. **Pagination Implementation** - Always implement pagination for list endpoints - Return metadata (total count, page info) - Client-side should handle pagination UI ### 3. **File Upload Strategy** - Store files on disk, not in database - Save only file paths in database - Implement file size limits ## 🔒 Security Best Practices Implemented ### 1. **Authentication** - JWT tokens expire after 60 minutes - Refresh token mechanism available - No sensitive data in JWT claims ### 2. **Password Security** - PBKDF2 with 100,000 iterations - Unique salt per password - Never store plain text passwords ### 3. **Input Validation** - FluentValidation for complex validation - Data annotations for simple validation - Server-side validation always enforced ### 4. **CORS Configuration** - Configured for specific domains in production - AllowAll only in development - Credentials handled properly ## 🎯 Key Takeaways 1. **Start with Standard Naming**: Use industry-standard property names from the beginning 2. **Plan Authentication Early**: Decide on authentication strategy before implementation 3. **Test Continuously**: Fix test issues as they arise, don't let them accumulate 4. **Document as You Go**: Keep CLAUDE.md updated with decisions and patterns 5. **Consider the Database**: Some features (like decimal ordering) are database-specific 6. **Mock External Dependencies**: Always mock file system, email, etc. in tests 7. **Use DTOs Consistently**: Don't expose entities directly through APIs 8. **Handle Errors Gracefully**: Implement proper error handling at all layers 9. **Security First**: Never have public endpoints if not required 10. **Client SDK Value**: A well-designed client SDK greatly improves API usability ## 🔄 Refactoring Opportunities ### Future Improvements 1. **Caching Layer**: Add Redis for frequently accessed data 2. **Message Queue**: Implement for order processing 3. **Event Sourcing**: For order status changes 4. **API Versioning**: Prepare for future API changes 5. **Health Checks**: Add health check endpoints 6. **Metrics**: Implement application metrics 7. **Rate Limiting**: Add rate limiting to API endpoints 8. **Background Jobs**: Use Hangfire or similar for async processing ## 📝 Development Workflow Tips 1. **Always Check CLAUDE.md**: Project-specific instructions override defaults 2. **Use TodoWrite Tool**: Track multi-step tasks systematically 3. **Build Frequently**: Catch compilation errors early 4. **Commit Logically**: Group related changes in commits 5. **Test After Major Changes**: Run tests after significant refactoring 6. **Document Decisions**: Record why, not just what 7. **Consider Side Effects**: Model changes affect DTOs, services, views, and tests ## 🛠️ Tool-Specific Lessons ### Visual Studio Code / WSL - Use `cmd.exe /c` wrapper for Windows commands - File watchers don't always work in WSL - Hot reload is unreliable with WSL ### Entity Framework Core - Migrations not always needed for development - `EnsureCreated()` sufficient for prototyping - Use migrations for production deployments ### Git in Mixed Environments - Line ending issues (CRLF vs LF) - Use `.gitattributes` to standardize - Commit from consistent environment ## Final Wisdom **"All endpoints must be authenticated"** - This single decision simplified the entire security model and eliminated a class of vulnerabilities. Sometimes the most restrictive choice is the best choice. **"Standard names matter"** - Using `Price` instead of `BasePrice` seems trivial, but non-standard names cascade through the entire codebase, tests, and documentation. **"Test the workflow, not just the code"** - Creating sample data that demonstrates the complete order workflow (pending → paid → shipped → delivered) helps validate the business logic, not just the technical implementation.