✅ ALL FEATURES IMPLEMENTED: 🔐 Advanced Permission System: - Role-based access control (Owner/Editor/Viewer) - Permission middleware for all API endpoints - Granular permissions for collection operations - Activity logging for complete audit trails 🌍 Collection Visibility Types: - Private: Owner-only access - Invite-Only: Controlled collaboration - Public: Community accessible - Dynamic permission checking across all endpoints 📧 Complete Email Integration: - Beautiful HTML invitation templates - Role-based permission descriptions - Personal message support - Accept/decline workflow with proper UX - Bulk invitation system for multiple users 🎨 Rich User Interface: - Permission indicators with tooltips - Activity log component with real-time updates - Collaboration management dashboard - Bulk invite modal with batch processing - Permission gates throughout the UI ⚡ Performance & Security: - Database indexes for optimal queries - Comprehensive error handling - CORS headers and preflight support - JWT-based authentication integration - Cascading deletes and data integrity 🚀 Ready for Production: - All API endpoints protected with permissions - Complete activity logging system - Beautiful email templates with Resend - Responsive UI components - Error handling and loading states This system now provides enterprise-level collaboration features for community-driven collection building! 🎯
115 lines
4.3 KiB
JavaScript
Executable file
115 lines
4.3 KiB
JavaScript
Executable file
#!/usr/bin/env node
|
||
|
||
import { config } from 'dotenv';
|
||
import { sql } from '@vercel/postgres';
|
||
|
||
// Load environment variables
|
||
config({ path: '.env.local' });
|
||
|
||
async function addCollaborationFeatures() {
|
||
try {
|
||
console.log('🔧 Adding collaboration features to database...\n');
|
||
|
||
// Add visibility and collaboration fields to collections table
|
||
console.log('📋 Updating collections table...');
|
||
await sql`
|
||
ALTER TABLE collections
|
||
ADD COLUMN IF NOT EXISTS visibility VARCHAR(20) DEFAULT 'private',
|
||
ADD COLUMN IF NOT EXISTS tcg VARCHAR(50) DEFAULT 'MTG',
|
||
ADD COLUMN IF NOT EXISTS tags TEXT
|
||
`;
|
||
console.log('✅ Updated collections table');
|
||
|
||
// Create collection_permissions table
|
||
console.log('<27><> Creating collection_permissions table...');
|
||
await sql`
|
||
CREATE TABLE IF NOT EXISTS collection_permissions (
|
||
id SERIAL PRIMARY KEY,
|
||
collection_id INTEGER REFERENCES collections(id) ON DELETE CASCADE,
|
||
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
||
role VARCHAR(20) NOT NULL CHECK (role IN ('owner', 'editor', 'viewer')),
|
||
status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active', 'pending', 'declined')),
|
||
invite_token VARCHAR(255) UNIQUE,
|
||
invited_by INTEGER REFERENCES users(id),
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
UNIQUE(collection_id, user_id)
|
||
)
|
||
`;
|
||
console.log('✅ Created collection_permissions table');
|
||
|
||
// Create collection_activity table for audit trail
|
||
console.log('📊 Creating collection_activity table...');
|
||
await sql`
|
||
CREATE TABLE IF NOT EXISTS collection_activity (
|
||
id SERIAL PRIMARY KEY,
|
||
collection_id INTEGER REFERENCES collections(id) ON DELETE CASCADE,
|
||
user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
||
action VARCHAR(50) NOT NULL,
|
||
details JSONB,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
)
|
||
`;
|
||
console.log('✅ Created collection_activity table');
|
||
|
||
// Add is_pending field to users table for invited users
|
||
console.log('👤 Updating users table...');
|
||
await sql`
|
||
ALTER TABLE users
|
||
ADD COLUMN IF NOT EXISTS is_pending BOOLEAN DEFAULT false
|
||
`;
|
||
console.log('✅ Updated users table');
|
||
|
||
// Create indexes for better performance
|
||
console.log('⚡ Creating indexes...');
|
||
await sql`
|
||
CREATE INDEX IF NOT EXISTS idx_collection_permissions_collection_id
|
||
ON collection_permissions(collection_id)
|
||
`;
|
||
await sql`
|
||
CREATE INDEX IF NOT EXISTS idx_collection_permissions_user_id
|
||
ON collection_permissions(user_id)
|
||
`;
|
||
await sql`
|
||
CREATE INDEX IF NOT EXISTS idx_collection_activity_collection_id
|
||
ON collection_activity(collection_id)
|
||
`;
|
||
await sql`
|
||
CREATE INDEX IF NOT EXISTS idx_collections_visibility
|
||
ON collections(visibility)
|
||
`;
|
||
console.log('✅ Created indexes');
|
||
|
||
// Migrate existing collections to have owner permissions
|
||
console.log('🔄 Migrating existing collections...');
|
||
const existingCollections = await sql`
|
||
SELECT c.id, c.user_id
|
||
FROM collections c
|
||
LEFT JOIN collection_permissions cp ON c.id = cp.collection_id AND c.user_id = cp.user_id
|
||
WHERE cp.id IS NULL
|
||
`;
|
||
|
||
for (const collection of existingCollections.rows) {
|
||
await sql`
|
||
INSERT INTO collection_permissions (collection_id, user_id, role, status)
|
||
VALUES (${collection.id}, ${collection.user_id}, 'owner', 'active')
|
||
ON CONFLICT (collection_id, user_id) DO NOTHING
|
||
`;
|
||
}
|
||
console.log(`✅ Migrated ${existingCollections.rows.length} existing collections`);
|
||
|
||
console.log('\n🎉 Collaboration features added successfully!');
|
||
console.log('\n📋 New Features:');
|
||
console.log(' • Collection visibility (private, invite-only, public)');
|
||
console.log(' • User permissions (owner, editor, viewer)');
|
||
console.log(' • Invitation system with email notifications');
|
||
console.log(' • Activity logging for audit trails');
|
||
console.log(' • Pending user support for email invitations');
|
||
|
||
} catch (error) {
|
||
console.error('❌ Migration failed:', error.message);
|
||
process.exit(1);
|
||
}
|
||
}
|
||
|
||
addCollaborationFeatures();
|