Part 3 of 3 in the Mes Recettes series: Part 1 – Overview · Part 2 – Architecture | 🇫🇷 Version
Testing Philosophy
Current focus: model correctness & validation rules. Keeping scope narrow avoids test brittleness while still guarding domain invariants.
Layer | Status | Notes |
---|---|---|
Model validation | Implemented | Rating bounds, required fields |
Relationships | Implemented | Book–Author–Recipe integrity |
Auth flow tests | TODO | Mock Supabase auth |
Integration tests | Planned | Supabase staging schema |
UI component tests | Deferred | Add once interactive logic increases |
Rating Validation Example
[Theory]
[InlineData(1,true)]
[InlineData(5,true)]
[InlineData(0,false)]
[InlineData(6,false)]
public void Rating_Range_Validation(int value, bool expected)
{
var recipe = new Recipe { Name = "Test", Rating = value };
var ctx = new ValidationContext(recipe);
var results = new List<ValidationResult>();
var valid = Validator.TryValidateObject(recipe, ctx, results, true);
Assert.Equal(expected, valid);
}
Security Posture (Planned + Active)
Concern | Approach |
---|---|
Auth | Supabase GoTrue (email/password today) |
Transport | HTTPS via hosting/CDN |
RLS | Policy patterns drafted (enforce user scoping) |
Input sanitization | Leverage encoding + validation |
Secret handling | Keys via configuration (move to env vars in CI) |
Least privilege | DB policies will gate row visibility |
Sample RLS concept:
ALTER TABLE recettes ENABLE ROW LEVEL SECURITY;
CREATE POLICY select_own ON recettes
FOR SELECT USING (auth.uid() = user_id);
(Assumes a user_id
column—additive migration required.)
Performance Strategy
Early-stage guidelines:
Area | Mitigation |
---|---|
Payload size | Tree-shake, lazy future component modules |
Overfetch | Add pagination & range queries (Supabase .Range() ) |
Duplicate calls | Introduce in-memory cache decorator |
Perceived latency | Optimistic UI for inserts, skeleton placeholders |
Search latency | Add GIN indexes + full-text vector |
Planned index example:
CREATE INDEX idx_recipes_search ON recettes USING gin(
to_tsvector('english', name || ' ' || coalesce(notes,''))
);
Caching Decorator Pattern (Planned)
public class CachedRecipeService : IRecipeService
{
private readonly IRecipeService _inner;
private readonly IMemoryCache _cache;
public async Task<List<Recipe>> GetRecipesAsync()
=> await _cache.GetOrCreateAsync("recipes_all",
_ => _inner.GetRecipesAsync());
}
Activate once query counts justify.
CI/CD Blueprint
Pipeline stages:
- Restore
- Build (fail fast)
- Test (gate)
- (Future) Lint & security scan
- Publish static output
- Deploy to CDN/static host
Workflow skeleton (excerpt):
- name: Test
run: dotnet test --no-build --verbosity normal
Add-ons to consider:
Enhancement | Tooling |
---|---|
Code coverage | coverlet + report badge |
SAST | CodeQL or Semgrep |
Dependency audit | dotnet list package --vulnerable |
DB migrations diff | Custom action + pg_dump |
Observability Roadmap
Layer | Near-Term | Later |
---|---|---|
Logging | Console + browser devtools | Structured logs → remote sink |
Metrics | Manual timings in dev | WASM → OpenTelemetry export (experimental) |
Errors | Blazor error boundary | Centralized exception pipeline |
Frontend perf | Lighthouse local runs | Automated thresholds in CI |
Deployment Targets
Initial: GitHub Pages / Azure Static Web Apps (build + deploy static wwwroot
).
Future: Add minimal server (hybrid hosting) if SSR, protected endpoints, or PDF generation needed.
Risk Register (Condensed)
Risk | Mitigation |
---|---|
Schema drift vs. docs | Add migration notes in /docs |
Vendor coupling (Supabase) | Abstract service interfaces incrementally |
Growth of untested UI logic | Introduce component tests when branching paths arise |
Auth edge cases (token refresh) | Monitor logs; add explicit refresh handling if needed |
Immediate Next Quality Steps
- Add RLS +
user_id
column migrations - Wire minimal integration test against throwaway Supabase project
- Introduce coverage reporting badge
- Start error boundary + logging wrapper for dialogs
Source: https://github.com/mongeon/RecettesIndex