Quality & Delivery: Testing, Security, Performance, and CI in Mes Recettes

Quality & Delivery pillars: Testing · Security · Performance · CI/CD

Quality & Delivery: Testing, Security, Performance, and CI in Mes Recettes

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.

LayerStatusNotes
Model validationImplementedRating bounds, required fields
RelationshipsImplementedBook–Author–Recipe integrity
Auth flow testsTODOMock Supabase auth
Integration testsPlannedSupabase staging schema
UI component testsDeferredAdd 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)

ConcernApproach
AuthSupabase GoTrue (email/password today)
TransportHTTPS via hosting/CDN
RLSPolicy patterns drafted (enforce user scoping)
Input sanitizationLeverage encoding + validation
Secret handlingKeys via configuration (move to env vars in CI)
Least privilegeDB 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:

AreaMitigation
Payload sizeTree-shake, lazy future component modules
OverfetchAdd pagination & range queries (Supabase .Range())
Duplicate callsIntroduce in-memory cache decorator
Perceived latencyOptimistic UI for inserts, skeleton placeholders
Search latencyAdd 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:

  1. Restore
  2. Build (fail fast)
  3. Test (gate)
  4. (Future) Lint & security scan
  5. Publish static output
  6. Deploy to CDN/static host

Workflow skeleton (excerpt):

- name: Test
  run: dotnet test --no-build --verbosity normal

Add-ons to consider:

EnhancementTooling
Code coveragecoverlet + report badge
SASTCodeQL or Semgrep
Dependency auditdotnet list package --vulnerable
DB migrations diffCustom action + pg_dump

Observability Roadmap

LayerNear-TermLater
LoggingConsole + browser devtoolsStructured logs → remote sink
MetricsManual timings in devWASM → OpenTelemetry export (experimental)
ErrorsBlazor error boundaryCentralized exception pipeline
Frontend perfLighthouse local runsAutomated 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)

RiskMitigation
Schema drift vs. docsAdd migration notes in /docs
Vendor coupling (Supabase)Abstract service interfaces incrementally
Growth of untested UI logicIntroduce component tests when branching paths arise
Auth edge cases (token refresh)Monitor logs; add explicit refresh handling if needed

Immediate Next Quality Steps

  1. Add RLS + user_id column migrations
  2. Wire minimal integration test against throwaway Supabase project
  3. Introduce coverage reporting badge
  4. Start error boundary + logging wrapper for dialogs

Source: https://github.com/mongeon/RecettesIndex



See also