Content is user-generated and unverified.

Exam Sharing System Design & Implementation Plan

1. Database Schema Design

Current Schema (Assumed)

javascript
// Users Collection
{
  _id: ObjectId,
  email: String,
  name: String,
  subscription_tier: String, // 'free', 'premium'
  created_at: Date
}

// Exams Collection
{
  _id: ObjectId,
  title: String,
  content: Object,
  author_id: ObjectId,
  created_at: Date,
  updated_at: Date
}

// Results Collection
{
  _id: ObjectId,
  exam_id: ObjectId,
  student_id: ObjectId,
  answers: Array,
  score: Number,
  completed_at: Date
}

New Schema Additions

Exam Shares Collection

javascript
{
  _id: ObjectId,
  exam_id: ObjectId,          // Reference to the exam
  owner_id: ObjectId,         // Original exam author
  shared_with_id: ObjectId,   // User receiving access
  permission_level: String,   // 'view', 'edit'
  status: String,            // 'pending', 'accepted', 'declined', 'revoked'
  created_at: Date,
  accepted_at: Date,
  expires_at: Date,          // Optional expiration
  share_token: String,       // Unique token for invite links
  metadata: {
    shared_by_name: String,
    shared_by_email: String,
    exam_title: String
  }
}

Updated Exams Collection

javascript
{
  _id: ObjectId,
  title: String,
  content: Object,
  author_id: ObjectId,
  created_at: Date,
  updated_at: Date,
  // New fields
  sharing_enabled: Boolean,   // Author can disable sharing
  shared_count: Number,       // Track how many times shared
  collaboration_history: [{   // Track changes when multiple editors
    user_id: ObjectId,
    action: String,
    timestamp: Date,
    changes: Object
  }]
}

2. Permission System Architecture

Permission Levels

  • VIEW: Can see exam content, view results dashboard, cannot modify
  • EDIT: Can modify exam content, view results, cannot delete or share further
  • OWNER: Full control (original author only)

Permission Inheritance Rules

  1. Owner always has full control
  2. Shared users cannot share with others (prevents permission sprawl)
  3. Edit permission includes view permission
  4. Premium feature: Only premium users can share exams
  5. Premium feature: Only premium users can receive edit permissions

3. API Design

Flask Backend Routes

Share Management Endpoints

python
# Create a share invitation
POST /api/exams/{exam_id}/share
Body: {
    "email": "colleague@example.com",
    "permission_level": "edit",
    "expires_in_days": 30,
    "message": "Please help me review this exam"
}

# List all shares for an exam (owner only)
GET /api/exams/{exam_id}/shares

# Accept/decline share invitation
POST /api/shares/{share_id}/respond
Body: {"action": "accept|decline"}

# Revoke a share (owner only)
DELETE /api/shares/{share_id}

# Get user's received shares
GET /api/user/shares/received

# Get user's sent shares
GET /api/user/shares/sent

Permission Check Endpoints

python
# Check user's permission for specific exam
GET /api/exams/{exam_id}/permissions

# Get all exams user has access to
GET /api/user/exams?include_shared=true

Permission Middleware

python
from functools import wraps
from flask import request, jsonify

def require_exam_permission(permission_level):
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            exam_id = kwargs.get('exam_id') or request.view_args.get('exam_id')
            user_id = get_current_user_id()
            
            if not has_exam_permission(user_id, exam_id, permission_level):
                return jsonify({'error': 'Insufficient permissions'}), 403
            
            return f(*args, **kwargs)
        return decorated_function
    return decorator

# Usage example
@app.route('/api/exams/<exam_id>/edit', methods=['PUT'])
@require_exam_permission('edit')
def update_exam(exam_id):
    # Implementation here
    pass

4. React Frontend Components

Share Management UI Components

ShareModal Component

jsx
const ShareModal = ({ examId, onClose }) => {
  const [shareData, setShareData] = useState({
    email: '',
    permission: 'view',
    expiresInDays: 30,
    message: ''
  });

  const handleShare = async () => {
    try {
      await api.post(`/exams/${examId}/share`, shareData);
      // Show success message
      onClose();
    } catch (error) {
      // Handle premium requirement or other errors
    }
  };

  return (
    <Modal>
      <form onSubmit={handleShare}>
        <input 
          type="email" 
          placeholder="Colleague's email"
          value={shareData.email}
          onChange={(e) => setShareData({...shareData, email: e.target.value})}
        />
        
        <select 
          value={shareData.permission}
          onChange={(e) => setShareData({...shareData, permission: e.target.value})}
        >
          <option value="view">View Only</option>
          <option value="edit">Edit Access</option>
        </select>
        
        <textarea 
          placeholder="Optional message"
          value={shareData.message}
          onChange={(e) => setShareData({...shareData, message: e.target.value})}
        />
        
        <button type="submit">Send Invitation</button>
      </form>
    </Modal>
  );
};

SharedExamsList Component

jsx
const SharedExamsList = () => {
  const [receivedShares, setReceivedShares] = useState([]);
  const [sentShares, setSentShares] = useState([]);

  return (
    <div className="shares-dashboard">
      <div className="received-shares">
        <h3>Exams Shared With Me</h3>
        {receivedShares.map(share => (
          <ShareCard 
            key={share._id}
            share={share}
            type="received"
            onAction={handleShareAction}
          />
        ))}
      </div>
      
      <div className="sent-shares">
        <h3>My Shared Exams</h3>
        {sentShares.map(share => (
          <ShareCard 
            key={share._id}
            share={share}
            type="sent"
            onAction={handleShareAction}
          />
        ))}
      </div>
    </div>
  );
};

5. Business Logic Implementation

Permission Checking Service

python
class PermissionService:
    @staticmethod
    def has_exam_permission(user_id, exam_id, required_permission):
        # Check if user is the owner
        exam = db.exams.find_one({"_id": ObjectId(exam_id)})
        if exam and exam['author_id'] == ObjectId(user_id):
            return True
        
        # Check shared permissions
        share = db.exam_shares.find_one({
            "exam_id": ObjectId(exam_id),
            "shared_with_id": ObjectId(user_id),
            "status": "accepted"
        })
        
        if not share:
            return False
        
        # Check permission hierarchy
        user_permission = share['permission_level']
        
        permission_hierarchy = {
            'view': 1,
            'edit': 2,
            'owner': 3
        }
        
        return permission_hierarchy.get(user_permission, 0) >= permission_hierarchy.get(required_permission, 0)
    
    @staticmethod
    def create_share_invitation(owner_id, exam_id, email, permission_level, expires_in_days=30):
        # Verify owner has premium subscription
        owner = db.users.find_one({"_id": ObjectId(owner_id)})
        if owner['subscription_tier'] != 'premium':
            raise Exception("Premium subscription required for sharing")
        
        # Find user by email
        target_user = db.users.find_one({"email": email})
        if not target_user:
            raise Exception("User not found")
        
        # Check if already shared
        existing_share = db.exam_shares.find_one({
            "exam_id": ObjectId(exam_id),
            "shared_with_id": target_user['_id'],
            "status": {"$in": ["pending", "accepted"]}
        })
        
        if existing_share:
            raise Exception("Exam already shared with this user")
        
        # Create share invitation
        share_data = {
            "exam_id": ObjectId(exam_id),
            "owner_id": ObjectId(owner_id),
            "shared_with_id": target_user['_id'],
            "permission_level": permission_level,
            "status": "pending",
            "created_at": datetime.utcnow(),
            "expires_at": datetime.utcnow() + timedelta(days=expires_in_days),
            "share_token": generate_secure_token(),
            "metadata": {
                "shared_by_name": owner['name'],
                "shared_by_email": owner['email'],
                "exam_title": db.exams.find_one({"_id": ObjectId(exam_id)})['title']
            }
        }
        
        result = db.exam_shares.insert_one(share_data)
        
        # Send notification email
        NotificationService.send_share_invitation(share_data)
        
        return result.inserted_id

6. Premium Feature Integration

Subscription Validation

python
def validate_premium_feature(feature_name):
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            user_id = get_current_user_id()
            user = db.users.find_one({"_id": ObjectId(user_id)})
            
            if user['subscription_tier'] != 'premium':
                return jsonify({
                    'error': 'Premium subscription required',
                    'feature': feature_name,
                    'upgrade_url': '/upgrade'
                }), 402  # Payment Required
            
            return f(*args, **kwargs)
        return decorated_function
    return decorator

# Usage
@app.route('/api/exams/<exam_id>/share', methods=['POST'])
@validate_premium_feature('exam_sharing')
def create_exam_share(exam_id):
    # Implementation
    pass

7. Security Considerations

Data Validation

  • Validate permission levels against allowed values
  • Sanitize email inputs to prevent injection
  • Rate limiting on share invitations (prevent spam)
  • Token-based authentication for share links

Privacy Protection

  • Share tokens expire automatically
  • Audit logging for all permission changes
  • Option for exam owners to revoke all shares instantly
  • Clear data ownership boundaries

8. Implementation Phases

Phase 1: Core Infrastructure (2-3 weeks)

  • Database schema updates
  • Basic permission checking middleware
  • Core API endpoints for sharing

Phase 2: Frontend Integration (2 weeks)

  • Share modal and management UI
  • Permission-based UI rendering
  • Notification system integration

Phase 3: Premium Integration (1 week)

  • Subscription validation
  • Upgrade prompts and flows
  • Usage analytics

Phase 4: Advanced Features (2 weeks)

  • Collaboration history tracking
  • Bulk sharing operations
  • Advanced permission management

9. Monitoring & Analytics

Key Metrics to Track

  • Share invitation acceptance rate
  • Premium conversion from sharing prompts
  • Collaboration frequency per shared exam
  • Permission usage patterns

Database Indexes for Performance

javascript
// Exam Shares Collection Indexes
db.exam_shares.createIndex({"exam_id": 1, "shared_with_id": 1});
db.exam_shares.createIndex({"shared_with_id": 1, "status": 1});
db.exam_shares.createIndex({"owner_id": 1});
db.exam_shares.createIndex({"expires_at": 1});

// Exams Collection Additional Index
db.exams.createIndex({"author_id": 1, "created_at": -1});

This design provides a robust, scalable sharing system that integrates seamlessly with your existing platform while driving premium subscriptions through collaborative features.

Content is user-generated and unverified.
    Exam Sharing System Design & Implementation Plan | Claude