Skip to content

[LC-1468] Add Ed.link LMS integration for automatic credential issuance (POC)#975

Open
AlexFicachi wants to merge 16 commits intomainfrom
lc-1468-edlink
Open

[LC-1468] Add Ed.link LMS integration for automatic credential issuance (POC)#975
AlexFicachi wants to merge 16 commits intomainfrom
lc-1468-edlink

Conversation

@AlexFicachi
Copy link
Collaborator

@AlexFicachi AlexFicachi commented Jan 30, 2026

Overview

https://www.loom.com/share/f7c1cd97e16642e78f887d45260ea1a4

🎟 Relevant Jira Issues

LC-1468

πŸ“š What is the context and goal of this PR?

Adds Ed.link LMS integration that automatically issues credentials to students when they complete assignments. Schools connect their LMS (Google Classroom, Canvas, etc.) via Ed.link, and the system polls for assignment completions every 5 minutes, issuing credentials to students via email (using the inbox claim flow).

πŸ₯΄ TL;DR:

Connect LMS β†’ Teacher returns graded assignment β†’ Credential auto-issued to student

πŸ’‘ Feature Breakdown

Backend:

  • Polling service checks Ed.link every 5 mins for new completions
  • Issues credentials via issueToInbox()
  • Tracks issued credentials in Neo4j to prevent duplicates
  • New routes: create/delete connections, toggle auto-issue, view issued credentials

Frontend:

  • School Portal dashboard at /school-portal
  • View LMS connections, assignment completions, issued credentials
  • Toggle auto-issuance per connection
  • Delete connections and credential records (for testing)

Feature Flags:

  • Frontend: edLinkEnabled via LaunchDarkly (hot toggle)
  • Backend: EDLINK_ENABLED env var (requires restart)
  • Polling: EDLINK_POLLING_ENABLED sub-flag

πŸ›  Important tradeoffs made:

  1. POC uses hardcoded system issuer - Not per-connection signing authorities. Sufficient for POC, but not prod ready.
  2. Routes are unauthenticated - openRoute used for all Ed.link endpoints. Sufficient for POC, needs auth before prod.
  3. Non-atomic deduplication - Race condition possible if concurrent polls.
  4. Inefficient completion queries - Fetches all classes β†’ all assignments β†’ all submissions on every poll. No incremental/delta fetching, so refetches already-processed data every 5 minutes.

πŸ” Types of Changes

  • New feature (non-breaking change which adds functionality)

πŸ’³ Does This Create Any New Technical Debt?

  • Yes
    • Auth needed on routes before production
    • Replace hardcoded issuer with per-connection signing authorities
    • Prevent concurrent poll races

Testing

πŸ”¬ How Can Someone QA This?

Watch Here (Same loom video at the top of this post under "Overview")

  1. Set EDLINK_ENABLED=true and EDLINK_POLLING_ENABLED=true in brain service
  2. Enable edLinkEnabled flag in LaunchDarkly
  3. Navigate to /school-portal
  4. Connect an LMS via Ed.link onboarding flow
  5. Toggle auto-issuance ON for the connection
  6. Have a student complete an assignment in the LMS
  7. Wait up to 5 minutes (or check brain service logs for poll)
  8. Verify credential appears in student's notifications/inbox

πŸ“± πŸ–₯ Which devices?

Chromium, tested in Docker local environment

πŸ§ͺ Code Coverage

  • Unit tests in brain-service/test/edlink.spec.ts covering:
    • Connection CRUD
    • Issued credential tracking
    • Deduplication logic
    • Polling service functions

Documentation

πŸ“ Documentation Checklist

User-Facing Docs

  • N/A for POC

Internal/AI Docs

  • Code comments - Polling service and helpers documented with file-level JSDoc headers
  • Feature doc - brain-service/docs/edlink-auto-issuance.md covers architecture, key files, feature flags, and POC limitations

πŸ’­ Documentation Notes

βœ… PR Checklist

  • Related to a Jira issue
  • My code follows style guidelines
  • I have manually tested common end-2-end cases
  • I have reviewed my code
  • I have commented my code, particularly where ambiguous
  • New and existing unit tests pass locally with my changes
  • I have completed the Documentation Checklist above

πŸš€ Ready to squash-and-merge?:

  • Code is backwards compatible
  • There is not a "Do Not Merge" label on this PR
  • I have thoughtfully considered the security implications of this change.
  • This change does not expose new public facing endpoints that do not have authentication
    • ⚠️ Ed.link routes use openRoute - acceptable for POC behind feature flag, needs auth before production

✨ PR Description

Purpose: Add Ed.link LMS integration with automatic credential issuance for completed assignments using polling-based synchronization and system-level credential signing.

Main changes:

  • Implemented Ed.link Graph API integration with Neo4j models for tracking connections and issued credentials with deduplication
  • Added background polling service that issues OpenBadgeCredentials to students via Universal Inbox when assignments are graded
  • Created School Portal UI with connection management, completion tracking, and auto-issuance toggle with instant credential preview

Generated by LinearB AI and added by gitStream.
AI-generated content may contain inaccuracies. Please verify before using.
πŸ’‘ Tip: You can customize your AI Description using Guidelines Learn how

@changeset-bot
Copy link

changeset-bot bot commented Jan 30, 2026

⚠️ No Changeset found

Latest commit: d2b7714

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@netlify
Copy link

netlify bot commented Jan 30, 2026

βœ… Deploy Preview for staging-learncardapp ready!

Name Link
πŸ”¨ Latest commit d2b7714
πŸ” Latest deploy log https://app.netlify.com/projects/staging-learncardapp/deploys/69b9df3bc71b900008bef3d9
😎 Deploy Preview https://deploy-preview-975--staging-learncardapp.netlify.app
πŸ“± Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Jan 30, 2026

βœ… Deploy Preview for learncarddocs canceled.

Name Link
πŸ”¨ Latest commit d2b7714
πŸ” Latest deploy log https://app.netlify.com/projects/learncarddocs/deploys/69b9df3b43de3f0008f8fb2c

@github-actions
Copy link
Contributor

πŸ‘‹ Hey there! It looks like you modified code, but didn't update the documentation in /docs.

If this PR introduces new features, changes APIs, or modifies behavior that users or developers need to know about, please consider updating the docs.


πŸ„ Windsurf Tip

You can ask Windsurf to help:

"Analyze the changes in this PR and update the gitbook docs in /docs accordingly."

Windsurf will review your changes and suggest appropriate documentation updates based on what was modified.


πŸ“š Documentation Guide
Change Type Doc Location
New feature/API docs/tutorials/ or docs/how-to-guides/
SDK/API changes docs/sdks/
New concepts docs/core-concepts/
App UI/UX flows docs/apps/ (LearnCard App, ScoutPass)
Internal patterns CLAUDE.md

This is an automated reminder. If no docs are needed, feel free to ignore this message.

@AlexFicachi AlexFicachi changed the title [DRAFT] Lc 1468 edlink [LC-1468] Add Ed.link LMS integration for automatic credential issuance (POC) Feb 6, 2026
@AlexFicachi AlexFicachi marked this pull request as ready for review February 7, 2026 01:59
Copy link
Contributor

@gitstream-cm gitstream-cm bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✨ PR Review

The PR implements a comprehensive Ed.link integration with good test coverage. However, there are two notable bugs: phantom connection creation on backend failures and silent data truncation in pagination logic.

2 issues detected:

🐞 Bug - Creates phantom connection in UI when backend save fails, leading to inconsistent state and confusing UX. πŸ› οΈ

Details: When backend save fails, the connection is still added to local state. This creates an inconsistent state where the connection appears in the UI but doesn't exist in the database. Any operations on this connection will fail, and the connection will disappear on page refresh, creating a confusing user experience.
File: apps/learn-card-app/src/pages/schoolPortal/SchoolPortalDashboard.tsx (57-62)
πŸ› οΈ A suggested code correction is included in the review comments.

🐞 Bug - Silently truncates data after 10 pages without warning, causing missing credentials for completions beyond the limit.

Details: The fetchAllPages function has a hardcoded maxPages default of 10, and silently stops fetching when this limit is reached. This can cause incomplete data fetching for classes, people, and enrollments, potentially resulting in missing credentials for students. If an LMS has more than 10 pages of any resource, those beyond page 10 will be silently ignored without any warning or logging.
File: services/learn-card-network/brain-service/src/helpers/edlink.helpers.ts

Generated by LinearB AI and added by gitStream.
AI-generated content may contain inaccuracies. Please verify before using.
πŸ’‘ Tip: You can customize your AI Review using Guidelines Learn how

Comment on lines +57 to +62
// Still update local state for UX
setConnections(prev => {
if (prev.some(c => c.id === connection.id)) return prev;
return [...prev, connection];
});
setSelectedConnection(connection);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐞 Bug - Phantom Connection: Remove the fallback local state update in the catch block (lines 58-62). Instead, show an error notification to the user when the backend save fails, so they know the connection was not created successfully.

Suggested change
// Still update local state for UX
setConnections(prev => {
if (prev.some(c => c.id === connection.id)) return prev;
return [...prev, connection];
});
setSelectedConnection(connection);
// TODO: Show error notification to the user
Is this review accurate? Use πŸ‘ or πŸ‘Ž to rate it

If you want to tell us more, use /gs feedback e.g. /gs feedback this review doesn't make sense, I disagree, and it keeps repeating over and over

@netlify
Copy link

netlify bot commented Mar 17, 2026

βœ… Deploy Preview for app-store-1-basic-launchpad-app canceled.

Name Link
πŸ”¨ Latest commit d2b7714
πŸ” Latest deploy log https://app.netlify.com/projects/app-store-1-basic-launchpad-app/deploys/69b9df3b15b89e000811bc90

@gitstream-cm
Copy link
Contributor

gitstream-cm bot commented Mar 17, 2026

πŸ₯· Code experts: TaylorBeeston, rhen92

TaylorBeeston, rhen92 have most πŸ‘©β€πŸ’» activity in the files.
TaylorBeeston, rhen92 have most 🧠 knowledge in the files.

See details

.github/workflows/test.yml

Activity based on git-commit:

TaylorBeeston rhen92
MAR
FEB 2 additions & 1 deletions
JAN
DEC
NOV 33 additions & 0 deletions
OCT

Knowledge based on git-blame:
TaylorBeeston: 20%

apps/learn-card-app/compose-local.yaml

Activity based on git-commit:

TaylorBeeston rhen92
MAR 1 additions & 1 deletions
FEB 15 additions & 0 deletions 49 additions & 0 deletions
JAN 297 additions & 233 deletions
DEC 2 additions & 2 deletions
NOV 247 additions & 0 deletions
OCT

Knowledge based on git-blame:
TaylorBeeston: 76%
rhen92: 13%

apps/learn-card-app/src/Routes.tsx

Activity based on git-commit:

TaylorBeeston rhen92
MAR 12 additions & 0 deletions
FEB 19 additions & 26 deletions
JAN
DEC
NOV 305 additions & 0 deletions
OCT

Knowledge based on git-blame:
TaylorBeeston: 73%
rhen92: 5%

packages/learn-card-types/src/index.ts

Activity based on git-commit:

TaylorBeeston rhen92
MAR
FEB
JAN
DEC
NOV 13 additions & 0 deletions
OCT

Knowledge based on git-blame:
TaylorBeeston: 86%

services/learn-card-network/brain-service/src/app.ts

Activity based on git-commit:

TaylorBeeston rhen92
MAR
FEB
JAN
DEC
NOV 6 additions & 0 deletions
OCT

Knowledge based on git-blame:
rhen92: 79%
TaylorBeeston: 8%

services/learn-card-network/brain-service/src/docker-entry.ts

Activity based on git-commit:

TaylorBeeston rhen92
MAR
FEB 21 additions & 9 deletions
JAN
DEC
NOV 32 additions & 0 deletions
OCT

Knowledge based on git-blame:
rhen92: 64%
TaylorBeeston: 27%

services/learn-card-network/brain-service/src/models/index.ts

Activity based on git-commit:

TaylorBeeston rhen92
MAR
FEB 94 additions & 197 deletions
JAN 3 additions & 0 deletions
DEC
NOV 37 additions & 0 deletions
OCT 86 additions & 7 deletions

Knowledge based on git-blame:
TaylorBeeston: 53%
rhen92: 27%

✨ Comment /gs review for LinearB AI review. Learn how to automate it here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants