Add customer communication system
This commit is contained in:
231
DEVELOPMENT_LESSONS.md
Normal file
231
DEVELOPMENT_LESSONS.md
Normal file
@@ -0,0 +1,231 @@
|
||||
# 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<T> 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.
|
||||
Reference in New Issue
Block a user