Skip to content

API Lineage Validation Report

This document validates that the API provides complete lineage chains for navigating the learning content hierarchy:

Domain → Trails → Concepts → Sparks

Executive Summary

All core lineage endpoints are implemented and functional.

The API provides comprehensive navigation capabilities in both forward and reverse directions through the content hierarchy.


Lineage Chain Validation

1. Domain → Trails ✅

Forward Navigation (Domain to Trails)

Endpoint Method Status Implementation
GET /api/v1/domains/{slug}?include_trails=true GET ✅ Implemented src/routes/domains.ts:148-199
GET /api/v1/trails?domain={slug} GET ✅ Implemented src/routes/trails.ts:84-94

Details: - ✅ Domain endpoint supports include_trails=true parameter - ✅ Returns trails with stats (concept_count, spark_count) - ✅ Trails endpoint supports domain={slug} filter - ✅ Both endpoints respect snapshot versioning

Example Response:

{
  "id": "...",
  "name": "Machine Learning",
  "slug": "machine-learning",
  "trails": [
    {
      "id": "...",
      "title": "Intro to ML",
      "slug": "intro-to-ml",
      "concept_count": 5,
      "spark_count": 12
    }
  ]
}


2. Trail → Concepts ✅

Forward Navigation (Trail to Concepts)

Endpoint Method Status Implementation
GET /api/v1/trails/{slug}?include_concepts=true GET ✅ Implemented src/routes/trails.ts:159-226
GET /api/v1/concepts?trail={slug} GET ✅ Implemented src/routes/concepts.ts:82-92

Details: - ✅ Trail endpoint supports include_concepts=true parameter - ✅ Returns concepts with spark_count - ✅ Concepts endpoint supports trail={slug} filter - ✅ Concepts are ordered by order_index - ✅ Both endpoints respect snapshot versioning

Example Response:

{
  "id": "...",
  "title": "Intro to ML",
  "slug": "intro-to-ml",
  "concepts": [
    {
      "id": "...",
      "title": "Neural Networks",
      "slug": "neural-networks",
      "order_index": 1,
      "spark_count": 3
    }
  ]
}


3. Concept → Sparks ✅

Forward Navigation (Concept to Sparks)

Endpoint Method Status Implementation
GET /api/v1/concepts/{slug}?include_sparks=true GET ✅ Implemented src/routes/concepts.ts:152-225
GET /api/v1/sparks?concept={slug} GET ✅ Implemented src/routes/sparks.ts:101-127

Details: - ✅ Concept endpoint supports include_sparks=true parameter - ✅ Returns sparks ordered by order_index from junction table - ✅ Sparks endpoint supports concept={slug} filter - ✅ Both endpoints respect snapshot versioning

Example Response:

{
  "id": "...",
  "title": "Neural Networks",
  "slug": "neural-networks",
  "sparks": [
    {
      "id": "...",
      "title": "Intro to Neural Nets",
      "slug": "intro-to-neural-nets",
      "estimated_mins": 8
    }
  ]
}


Reverse Navigation (Bottom-Up)

4. Spark → Concepts ✅

Endpoint Method Status Implementation
GET /api/v1/sparks/{slug}?include_concepts=true GET ✅ Implemented src/routes/sparks.ts:267-280

Details: - ✅ Spark endpoint supports include_concepts=true parameter - ✅ Returns all concepts that contain this spark (many-to-many relationship)


5. Concept → Trail ✅

Endpoint Method Status Implementation
GET /api/v1/concepts/{slug}?include_trail=true GET ✅ Implemented src/routes/concepts.ts:182-194

Details: - ✅ Concept endpoint supports include_trail=true parameter - ✅ Returns the trail that contains this concept


6. Trail → Domain ✅

Endpoint Method Status Implementation
GET /api/v1/trails/{slug}?include_domain=true GET ✅ Implemented src/routes/trails.ts:190-202

Details: - ✅ Trail endpoint supports include_domain=true parameter - ✅ Returns the domain that contains this trail


Complete Lineage Traversal Examples

Forward Traversal (Top-Down)

# Step 1: Get domain with all trails
GET /api/v1/domains/machine-learning?include_trails=true

# Step 2: Get trail with all concepts
GET /api/v1/trails/intro-to-ml?include_concepts=true

# Step 3: Get concept with all sparks
GET /api/v1/concepts/neural-networks?include_sparks=true

Reverse Traversal (Bottom-Up)

# Step 1: Get spark with concepts
GET /api/v1/sparks/intro-to-neural-nets?include_concepts=true

# Step 2: Get concept with trail
GET /api/v1/concepts/neural-networks?include_trail=true

# Step 3: Get trail with domain
GET /api/v1/trails/intro-to-ml?include_domain=true

Filter-Based Navigation

# Get all trails in a domain
GET /api/v1/trails?domain=machine-learning

# Get all concepts in a trail
GET /api/v1/concepts?trail=intro-to-ml

# Get all sparks in a concept
GET /api/v1/sparks?concept=neural-networks

API Coverage in api.http

The api.http file includes tests for:

Domains: - List domains - Get domain by slug - Get domain with trails (include_trails=true)

Trails: - List trails - List trails by domain (?domain=) - Get trail by slug - Get trail with concepts (include_concepts=true)

Concepts: - List concepts - List concepts by trail (?trail=) - Get concept by slug - Get concept with sparks (include_sparks=true)

Sparks: - List sparks - List sparks by difficulty - Get spark by slug

All endpoints now in api.http: - ✅ GET /api/v1/sparks?concept={slug} - Filter sparks by concept - ✅ GET /api/v1/sparks/{slug}?include_concepts=true - Get spark with concepts - ✅ GET /api/v1/concepts/{slug}?include_trail=true - Get concept with trail - ✅ GET /api/v1/trails/{slug}?include_domain=true - Get trail with domain


Identified Gaps & Recommendations

1. Missing Test Cases in api.http ✅ FIXED

Issue: Some reverse navigation endpoints were not tested in api.http.

Status:FIXED - Added all missing test cases to api.http:

  • GET /api/v1/sparks/{slug}?include_concepts=true - Get spark with concepts
  • GET /api/v1/concepts/{slug}?include_trail=true - Get concept with trail
  • GET /api/v1/trails/{slug}?include_domain=true - Get trail with domain
  • GET /api/v1/sparks?concept={slug} - List sparks by concept

2. Potential Issue: Concept → Sparks Query ⚠️

Location: src/routes/concepts.ts:197-219

Issue: The query uses concept_sparks!inner(order_index) which may not properly handle the ordering when multiple concepts share sparks.

Current Implementation:

let sparksQuery = supabase
  .from("sparks")
  .select(`
    id, title, slug, summary, estimated_mins, difficulty, is_published,
    concept_sparks!inner(order_index)
  `)
  .eq("concept_sparks.concept_id", concept.id)
  .eq("is_published", true);

Recommendation: Verify that the ordering works correctly when a spark belongs to multiple concepts. Consider using a more explicit join or filtering approach.

3. Potential Issue: Trail → Domain Query ✅ FIXED

Location: src/routes/trails.ts:191-201

Issue: The domain query didn't filter by is_published, which could return unpublished domains.

Status:FIXED - Added is_published filter to domain query.

Fixed Implementation:

let domainQuery = supabase
  .from("domains")
  .select("id, name, slug")
  .eq("id", trail.domain_id)
  .eq("is_published", true);

4. Missing: Bulk Lineage Endpoints 💡

Enhancement Suggestion: Consider adding endpoints that return complete lineage in a single request:

# Get complete lineage from domain to all sparks
GET /api/v1/domains/{slug}?include_trails=true&include_concepts=true&include_sparks=true

# Get complete lineage from trail to all sparks
GET /api/v1/trails/{slug}?include_concepts=true&include_sparks=true

Current Workaround: Requires multiple API calls.

5. Missing: Lineage Depth Parameter 💡

Enhancement Suggestion: Add a depth parameter to control how deep to include nested resources:

# Include only immediate children (depth=1)
GET /api/v1/domains/{slug}?include_trails=true&depth=1

# Include all descendants (depth=all or depth=3)
GET /api/v1/domains/{slug}?include_trails=true&include_concepts=true&include_sparks=true&depth=all

Testing Recommendations

1. Run Validation Script

Use the provided validation script to test all endpoints:

# Set API base URL (optional, defaults to http://localhost:8000)
export API_BASE_URL=http://localhost:8000

# Run validation
deno run --allow-net --allow-env scripts/validate-lineage.ts

2. Manual Testing Checklist

  • Test forward navigation: Domain → Trails → Concepts → Sparks
  • Test reverse navigation: Spark → Concepts → Trail → Domain
  • Test filter endpoints: ?domain=, ?trail=, ?concept=
  • Test with snapshot versioning: ?snapshot_id=...
  • Test with pagination: ?page=1&per_page=10
  • Test error cases: Invalid slugs, missing resources
  • Test with empty results: Domain with no trails, Trail with no concepts, etc.

3. Integration Testing

Create integration tests that: 1. Create test data (domain → trail → concept → spark) 2. Test complete lineage traversal 3. Verify data consistency across endpoints 4. Test edge cases (orphaned concepts, unpublished content)


Summary

✅ Strengths

  1. Complete Forward Navigation: All forward navigation endpoints (Domain → Trails → Concepts → Sparks) are implemented
  2. Complete Reverse Navigation: All reverse navigation endpoints are implemented
  3. Filter Support: All filter endpoints (?domain=, ?trail=, ?concept=) are implemented
  4. Snapshot Support: All endpoints respect snapshot versioning
  5. Consistent API Design: All endpoints follow the same pattern with include_* parameters

⚠️ Areas for Improvement

  1. Test Coverage: All missing test cases added to api.http
  2. Query Robustness: Verify complex queries (concept_sparks join) work correctly
  3. Consistency: All queries now filter by is_published where appropriate
  4. Documentation: Add examples of complete lineage traversal to API docs

💡 Future Enhancements

  1. Bulk Lineage Endpoints: Single-request endpoints for complete lineage
  2. Depth Control: Parameter to control nesting depth
  3. Lineage Graph Endpoint: Return complete lineage as a graph structure
  4. Performance: Consider caching for frequently accessed lineage chains

Conclusion

The API provides complete and functional lineage navigation in both forward and reverse directions. All core endpoints are implemented correctly, with minor improvements recommended for test coverage and query robustness.

Overall Status: ✅ PASS - All required lineage endpoints are available and functional.


Generated: 2024-12-30 Validation Script: scripts/validate-lineage.ts