Skip to content

Conversation

@Custard7
Copy link
Collaborator

@Custard7 Custard7 commented Dec 18, 2025

feat: Add defaultPermissions for Boosts

Summary

This PR implements defaultPermissions for Boosts, allowing boost creators to grant permissions to all authenticated users without explicitly assigning roles. This enables use cases like community badges where anyone can issue credentials.

Changes

Core Implementation

  • packages/learn-card-types/src/lcn.ts - Added defaultPermissions field to BoostValidator
  • services/learn-card-network/brain-service/src/models/Boost.ts - Added defaultRole relationship to Boost model
  • services/learn-card-network/brain-service/src/accesslayer/role/relationships/create.ts - Added addDefaultPermissionsForBoost function
  • services/learn-card-network/brain-service/src/accesslayer/role/relationships/update.ts - Created updateDefaultPermissionsForBoost and removeDefaultPermissionsForBoost functions
  • services/learn-card-network/brain-service/src/routes/boosts.ts - Added defaultPermissions handling to createBoost, createChildBoost, and updateBoost routes

Permission System Refactor

Refactored the permission system to integrate defaultPermissions into the central getBoostPermissions function:

  • getBoostPermissions now fetches defaultRole and uses it as the base permissions
  • canProfileEditBoost and canProfileIssueBoost simplified to use getBoostPermissions instead of custom queries
  • This DRY approach means adding new permissions automatically works without updating multiple functions

Network Plugin

  • packages/plugins/learn-card-network/src/plugin.ts - Updated createBoost and createChildBoost to pass defaultPermissions through metadata

Tests

Added comprehensive test coverage in services/learn-card-network/brain-service/test/default-permissions.spec.ts:

  • 35 tests covering:
    • Creation with defaultPermissions
    • Issuance via defaultPermissions.canIssue
    • Editing via defaultPermissions.canEdit
    • All supported permissions (canRevoke, canManagePermissions, canViewAnalytics)
    • Updating defaultPermissions on existing boosts
    • Permission merging with explicit roles
    • Child boost behavior
    • Admin interactions

Documentation

  • docs/core-concepts/credentials-and-data/boost-credentials.md - Added "Default Permissions" section with use cases, examples, and supported permissions table
  • docs/tutorials/create-a-boost.md - Added link to new Default Permissions documentation

Usage

// Create a boost that anyone can issue
const boostUri = await learnCard.invoke.createBoost(credential, {
  name: 'Community Badge',
  defaultPermissions: {
    canIssue: true,
    canViewAnalytics: true,
  },
});

// Any authenticated user can now issue this boost
await anyUser.invoke.sendBoost('recipient-id', boostUri, signedCredential);

Supported Permissions

Permission Description
canIssue Allows any user to issue the Boost to recipients
canEdit Allows any user to edit the Boost metadata
canRevoke Allows any user to revoke issued credentials
canManagePermissions Allows any user to manage Boost permissions
canViewAnalytics Allows any user to view Boost analytics

Testing

All 994 tests pass, including 35 new tests for defaultPermissions.

How to Test this PR:

  • pnpm install completed at repo root

1: Run Automated Tests

# Run the defaultPermissions unit tests (35 tests)
pnpm nx run network-brain-service:test -- default-permissions.spec.ts --run

# Run all brain-service tests (994 tests)
pnpm nx run network-brain-service:test --run

Expected: All tests pass.


2: Manual Testing via CLI

Step 0: Start Services

pnpm dev

Step 1: Start the LearnCard CLI

Terminal

pnpm nx start cli 

Step 2: Create Profiles

User A:

a = await initLearnCard({ seed: 'a', network: 'http://localhost:4000/trpc' })
await a.invoke.createProfile({ profileId: 'user-a', displayName: 'User A' });

User B

b = await initLearnCard({ seed: 'b', network: 'http://localhost:4000/trpc' })
await a.invoke.createProfile({ profileId: 'user-b', displayName: 'User B' });

Step 3: Create a Boost with defaultPermissions (User A)

const credential = {
  '@context': [
    'https://www.w3.org/2018/credentials/v1',
    'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.1.json',
    'https://ctx.learncard.com/boosts/1.0.3.json',
  ],
  type: ['VerifiableCredential', 'OpenBadgeCredential', 'BoostCredential'],
  name: 'Community Badge',
  issuer: a.id.did(),
  issuanceDate: new Date().toISOString(),
  credentialSubject: {
    type: ['AchievementSubject'],
    achievement: {
      type: ['Achievement'],
      name: 'Community Helper',
      description: 'Awarded for helping the community',
      criteria: { narrative: 'Be helpful!' },
    },
  },
};

const boostUri = await learnCard.invoke.createBoost(credential, {
  name: 'Community Badge',
  category: 'Social Badge',
  defaultPermissions: {
    canIssue: true,
    canViewAnalytics: true,
  },
});

console.log('Boost URI:', boostUri);

Step 4: Verify User B Can See Permissions

// Replace with the boostUri from Step 3
const permissions = await b.invoke.getBoostPermissions(boostUri);
console.log(permissions);
// Should show: { canIssue: true, canViewAnalytics: true, ... }

Step 5: Verify User B Can Issue

// Create a credential to issue
const credential = {
  '@context': [
    'https://www.w3.org/2018/credentials/v1',
    'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.1.json',
    'https://ctx.learncard.com/boosts/1.0.3.json',
  ],
  type: ['VerifiableCredential', 'OpenBadgeCredential', 'BoostCredential'],
  name: 'Community Badge',
  issuer: b.id.did(),
  issuanceDate: new Date().toISOString(),
  credentialSubject: {
    id: 'did:example:recipient',
    type: ['AchievementSubject'],
    achievement: {
      type: ['Achievement'],
      name: 'Community Helper',
      description: 'Awarded for helping the community',
      criteria: { narrative: 'Be helpful!' },
    },
  },
};

const signedCred = await b.invoke.issueCredential(credential);

// This should succeed because defaultPermissions.canIssue = true
const credUri = await b.invoke.sendBoost('user-a', boostUri, signedCred);
console.log('Sent credential:', credUri);

What to Verify

Test Case Expected Result
User B calls getBoostPermissions Returns canIssue: true, canViewAnalytics: true
User B calls sendBoost Succeeds (no UNAUTHORIZED error)
Create boost without defaultPermissions User B gets canIssue: false and sendBoost fails

✨ PR Description

Purpose: Add defaultPermissions field to Boosts to grant permissions to all authenticated users without explicit role assignment, enabling open collaboration and community-driven credential issuance.

Main changes:

  • Added defaultPermissions field to Boost schema and data model with Role relationship
  • Refactored permission resolution to merge defaultPermissions with direct and inherited role permissions
  • Added updateDefaultPermissionsForBoost and removeDefaultPermissionsForBoost functions to manage default role lifecycle
  • Extended createBoost, createChildBoost, and updateBoost endpoints to accept and manage defaultPermissions
  • Updated published Boost editing restrictions to allow defaultPermissions modifications alongside meta updates

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 Dec 18, 2025

🦋 Changeset detected

Latest commit: cb32b5e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 46 packages
Name Type
@learncard/types Patch
@learncard/network-brain-service Patch
@learncard/chapi-example Patch
@learncard/snap-example-dapp Patch
@learncard/lca-api-client Patch
@learncard/create-http-bridge Patch
@learncard/cli Patch
@learncard/core Patch
@learncard/helpers Patch
@learncard/init Patch
@learncard/react Patch
@learncard/network-brain-client Patch
@learncard/learn-cloud-client Patch
@learncard/simple-signing-client Patch
@learncard/ceramic-plugin Patch
@learncard/chapi-plugin Patch
@learncard/claimable-boosts-plugin Patch
@learncard/did-web-plugin Patch
@learncard/didkey-plugin Patch
@learncard/didkit-plugin Patch
@learncard/encryption-plugin Patch
@learncard/idx-plugin Patch
@learncard/network-plugin Patch
@learncard/learn-card-plugin Patch
@learncard/learn-cloud-plugin Patch
@learncard/linked-claims-plugin Patch
@learncard/open-badge-v2-plugin Patch
@learncard/vc-api-plugin Patch
@learncard/vc-templates-plugin Patch
@learncard/vc-plugin Patch
@learncard/vpqr-plugin Patch
learn-card-discord-bot Patch
@learncard/meta-mask-snap Patch
@learncard/lca-api-service Patch
@learncard/learn-cloud-service Patch
@learncard/simple-signing-service Patch
learn-card-app Patch
scoutpass-app Patch
@learncard/snap-chapi-example Patch
learn-card-base Patch
@learncard/expiration-plugin Patch
@learncard/crypto-plugin Patch
@learncard/dynamic-loader-plugin Patch
@learncard/ethereum-plugin Patch
@learncard/lca-api-plugin Patch
@learncard/simple-signing-plugin Patch

Not sure what this means? Click here to learn what changesets are.

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

@netlify
Copy link

netlify bot commented Dec 18, 2025

Deploy Preview for staging-learncardapp canceled.

Name Link
🔨 Latest commit cb32b5e
🔍 Latest deploy log https://app.netlify.com/projects/staging-learncardapp/deploys/6945763569ae0e0007d175b5

@netlify
Copy link

netlify bot commented Dec 18, 2025

Deploy Preview for learncarddocs canceled.

Name Link
🔨 Latest commit cb32b5e
🔍 Latest deploy log https://app.netlify.com/projects/learncarddocs/deploys/694576353bb26b0008b71bdd

@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.

@Custard7 Custard7 marked this pull request as ready for review December 18, 2025 22:48
@Custard7 Custard7 had a problem deploying to learn-card-app-production December 18, 2025 22:48 — with GitHub Actions Failure
@Custard7 Custard7 had a problem deploying to learn-card-app-production December 18, 2025 22:48 — with GitHub Actions Failure
@Custard7
Copy link
Collaborator Author

@claude please review and provide a recommendation for merging

@claude
Copy link
Contributor

claude bot commented Dec 18, 2025

Claude finished @Custard7's task —— View job


Code Review Complete ✅

Review Tasks

  • Analyze core implementation changes
  • Review permission system refactor for security
  • Check test coverage and quality
  • Verify documentation accuracy
  • Provide merge recommendation

Review Summary

RECOMMENDATION: APPROVED FOR MERGE

This is a well-implemented feature that adds significant value to the LearnCard platform while maintaining security and code quality standards.

Strengths

🏗️ Solid Architecture

  • Clean separation of concerns with dedicated functions for default permission management
  • Proper database modeling with defaultRole relationship
  • Type-safe implementation throughout the stack

🔒 Security-First Design

  • Default permissions serve as base permissions that enhance rather than compromise security
  • Centralized permission checking through getBoostPermissions() reduces attack surface
  • Proper cleanup of orphaned Role nodes prevents data leakage

🧪 Comprehensive Testing

  • 35 test cases covering all supported permissions and edge cases
  • Tests verify both positive and negative scenarios
  • Proper test isolation with cleanup between tests

📚 Excellent Documentation

  • Clear explanation of use cases (community badges, open issuance)
  • Complete API examples and supported permissions table
  • Proper GitBook formatting with helpful hints and diagrams

🎯 Value-Added Feature

  • Enables new use cases like community-managed credentials
  • Maintains backward compatibility
  • Follows established patterns in the codebase

Technical Details Verified

  1. Type Safety: Proper Zod validation and TypeScript integration
  2. Database: Clean Neo4j model with appropriate relationships
  3. Permission Logic: Secure base + merge pattern for permission resolution
  4. CRUD Operations: Complete create/read/update/delete functionality
  5. Error Handling: Appropriate TRPC error responses
  6. Integration: Proper flow from types → service → plugin → tests

Minor Notes

  • The feature is well-scoped and doesn't introduce unnecessary complexity
  • Code follows established patterns and conventions
  • All 994 existing tests pass according to PR description
  • Documentation accurately reflects the implementation

This PR represents high-quality software development and is ready for production deployment.


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

LGTM

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

@gitstream-cm
Copy link
Contributor

gitstream-cm bot commented Dec 18, 2025

This PR is missing a Jira ticket reference in the title or description.
Please add a Jira ticket reference to the title or description of this PR.

@Custard7
Copy link
Collaborator Author

@claude please re-review and provide a recommendation for merging

@claude
Copy link
Contributor

claude bot commented Dec 19, 2025

Claude finished @Custard7's task —— View job


Re-reviewing PR: Default Permissions for Boosts ✅

Review Tasks

  • Analyze core implementation changes
  • Review permission system refactor for security
  • Check test coverage and quality
  • Verify documentation accuracy
  • Provide merge recommendation

RECOMMENDATION: APPROVED FOR MERGE

This is a well-implemented feature that adds significant value to the LearnCard platform while maintaining security and code quality standards.

Strengths

🏗️ Solid Architecture

  • Clean separation of concerns with dedicated functions (addDefaultPermissionsForBoost, updateDefaultPermissionsForBoost, removeDefaultPermissionsForBoost)
  • Proper database modeling with defaultRole relationship in Neo4j schema (services/learn-card-network/brain-service/src/models/Boost.ts:28,116)
  • Type-safe implementation throughout the stack with proper Zod validation (packages/learn-card-types/src/lcn.ts:238)

🔒 Security-First Design

  • Default permissions serve as base permissions that enhance rather than compromise security
  • Centralized permission checking through refactored getBoostPermissions() function reduces attack surface (services/learn-card-network/brain-service/src/accesslayer/boost/relationships/read.ts:724-771)
  • Proper cleanup of orphaned Role nodes prevents data leakage (services/learn-card-network/brain-service/src/accesslayer/role/relationships/update.ts:18-30)
  • Permission merging logic properly combines default + explicit permissions without conflicts

🧪 Comprehensive Testing

  • 35 test cases covering all supported permissions and edge cases (services/learn-card-network/brain-service/test/default-permissions.spec.ts)
  • Tests verify both positive and negative scenarios
  • Proper test isolation with cleanup between tests
  • Tests cover creation, issuance, updating, and permission merging scenarios

📚 Excellent Documentation

  • Clear explanation of use cases (community badges, open issuance) with practical examples
  • Complete API examples and supported permissions table
  • Proper GitBook formatting with helpful hints and Mermaid diagrams
  • Accurately reflects the implementation with correct code samples

🎯 Value-Added Feature

  • Enables new use cases like community-managed credentials without compromising security
  • Maintains backward compatibility - existing boosts work unchanged
  • Follows established patterns in the codebase (similar to claimPermissions)

Technical Details Verified

  1. Type Safety: Proper Zod validation (defaultPermissions: BoostPermissionsValidator.optional()) and TypeScript integration
  2. Database Schema: Clean Neo4j model with defaultRole relationship, proper cleanup logic
  3. Permission Logic: Secure base + merge pattern in getBoostPermissions() - default permissions serve as foundation, explicit permissions are layered on top
  4. CRUD Operations: Complete create/read/update/delete functionality for default permissions lifecycle
  5. Error Handling: Appropriate TRPC error responses and graceful degradation
  6. Integration: Proper flow from types → service → plugin → tests with consistent API

Code Quality Highlights

  • DRY refactor: canProfileEditBoost and canProfileIssueBoost now use centralized getBoostPermissions() instead of duplicate queries
  • Consistent patterns: Implementation mirrors existing claimPermissions approach
  • Clean abstractions: Well-named functions that clearly express intent
  • Proper error boundaries: Graceful handling of missing or invalid permissions

Minor Observations

  • The feature is well-scoped and doesn't introduce unnecessary complexity
  • Code follows established LearnCard conventions and patterns
  • All 994 existing tests pass according to PR description
  • Documentation accurately reflects the implementation

This PR represents high-quality software development with thorough testing, clear documentation, and solid architectural decisions. The feature enables valuable new use cases while maintaining security and backward compatibility.


@gitstream-cm
Copy link
Contributor

gitstream-cm bot commented Dec 19, 2025

🥷 Code experts: TaylorBeeston

Custard7, TaylorBeeston have most 👩‍💻 activity in the files.
Custard7, TaylorBeeston have most 🧠 knowledge in the files.

See details

docs/core-concepts/credentials-and-data/boost-credentials.md

Activity based on git-commit:

Custard7 TaylorBeeston
DEC 367 additions & 0 deletions
NOV
OCT
SEP
AUG
JUL

Knowledge based on git-blame:
Custard7: 100%

docs/tutorials/create-a-boost.md

Activity based on git-commit:

Custard7 TaylorBeeston
DEC 393 additions & 1 deletions 46 additions & 1 deletions
NOV
OCT
SEP
AUG
JUL

Knowledge based on git-blame:
Custard7: 89%
TaylorBeeston: 11%

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

Activity based on git-commit:

Custard7 TaylorBeeston
DEC 178 additions & 81 deletions 41 additions & 0 deletions
NOV 550 additions & 64 deletions
OCT 94 additions & 1 deletions
SEP
AUG 6 additions & 2 deletions 19 additions & 1 deletions
JUL 208 additions & 1 deletions 5 additions & 4 deletions

Knowledge based on git-blame:
Custard7: 63%
TaylorBeeston: 36%

services/learn-card-network/brain-service/src/accesslayer/boost/relationships/read.ts

Activity based on git-commit:

Custard7 TaylorBeeston
DEC
NOV 220 additions & 23 deletions
OCT
SEP
AUG 418 additions & 8 deletions
JUL 294 additions & 1 deletions

Knowledge based on git-blame:
TaylorBeeston: 54%
Custard7: 46%

services/learn-card-network/brain-service/src/accesslayer/role/relationships/create.ts

Activity based on git-commit:

Custard7 TaylorBeeston
DEC
NOV
OCT
SEP
AUG
JUL

Knowledge based on git-blame:
Custard7: 100%

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

Activity based on git-commit:

Custard7 TaylorBeeston
DEC
NOV 11 additions & 0 deletions
OCT
SEP
AUG 2 additions & 0 deletions
JUL 1 additions & 0 deletions

Knowledge based on git-blame:
Custard7: 89%
TaylorBeeston: 11%

services/learn-card-network/brain-service/src/routes/boosts.ts

Activity based on git-commit:

Custard7 TaylorBeeston
DEC 13 additions & 11 deletions 222 additions & 3 deletions
NOV 415 additions & 5 deletions
OCT 11 additions & 3 deletions
SEP 4 additions & 2 deletions
AUG 111 additions & 0 deletions
JUL 81 additions & 3 deletions

Knowledge based on git-blame:
Custard7: 68%
TaylorBeeston: 32%

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

@Custard7 Custard7 merged commit 3727c73 into main Dec 19, 2025
26 checks passed
@Custard7 Custard7 deleted the default-permissions-boosts branch December 19, 2025 16:08
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