deckhearth/scripts/add-collaboration-features.js
Randall Stillwell 23d995102f 🎉 COMPLETED: Full Collaborative Collections System
 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! 🎯
2025-07-25 08:34:28 -05:00

115 lines
4.3 KiB
JavaScript
Executable file
Raw Permalink Blame History

#!/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();