🔧 Debugging Improvements: - Optimize setup-auth endpoint to avoid timeouts - Add table existence checks before operations - Simplify permission system for faster setup - Add environment variable validation - Create test-db endpoint for connection debugging 🚀 Performance Optimizations: - Break down large SQL queries into smaller chunks - Add early returns for already-setup scenarios - Reduce permission complexity during initial setup - Better error messages for troubleshooting 🧪 New Debug Endpoints: - /api/test-db - Test database connectivity - /api/setup-auth - Optimized schema setup These changes should resolve timeout issues and provide better debugging information for authentication problems.
185 lines
No EOL
5.8 KiB
TypeScript
185 lines
No EOL
5.8 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
|
import { Pool } from 'pg';
|
|
|
|
const pool = new Pool({
|
|
connectionString: process.env.DATABASE_URL,
|
|
ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
|
|
});
|
|
|
|
export default async function handler(req: NextRequest) {
|
|
if (req.method !== 'POST') {
|
|
return new NextResponse(JSON.stringify({ error: 'Method not allowed' }), {
|
|
status: 405,
|
|
headers: { 'Content-Type': 'application/json' },
|
|
});
|
|
}
|
|
|
|
const client = await pool.connect();
|
|
|
|
try {
|
|
console.log('Setting up user authentication schema...');
|
|
|
|
// Check if users table already exists
|
|
const tableCheck = await client.query(`
|
|
SELECT EXISTS (
|
|
SELECT FROM information_schema.tables
|
|
WHERE table_schema = 'public'
|
|
AND table_name = 'users'
|
|
);
|
|
`);
|
|
|
|
if (tableCheck.rows[0].exists) {
|
|
return new NextResponse(JSON.stringify({
|
|
success: true,
|
|
message: 'User authentication schema already exists',
|
|
already_setup: true
|
|
}), {
|
|
status: 200,
|
|
headers: { 'Content-Type': 'application/json' },
|
|
});
|
|
}
|
|
|
|
// Create tables one by one
|
|
await client.query(`
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id SERIAL PRIMARY KEY,
|
|
username VARCHAR(50) UNIQUE NOT NULL,
|
|
email VARCHAR(100) UNIQUE NOT NULL,
|
|
password_hash VARCHAR(255) NOT NULL,
|
|
first_name VARCHAR(50),
|
|
last_name VARCHAR(50),
|
|
avatar_url TEXT,
|
|
is_active BOOLEAN DEFAULT true,
|
|
email_verified BOOLEAN DEFAULT false,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
last_login TIMESTAMP WITH TIME ZONE
|
|
);
|
|
`);
|
|
|
|
await client.query(`
|
|
CREATE TABLE IF NOT EXISTS roles (
|
|
id SERIAL PRIMARY KEY,
|
|
name VARCHAR(50) UNIQUE NOT NULL,
|
|
description TEXT,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
`);
|
|
|
|
await client.query(`
|
|
CREATE TABLE IF NOT EXISTS user_roles (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
|
role_id INTEGER REFERENCES roles(id) ON DELETE CASCADE,
|
|
assigned_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
assigned_by INTEGER REFERENCES users(id),
|
|
UNIQUE(user_id, role_id)
|
|
);
|
|
`);
|
|
|
|
await client.query(`
|
|
CREATE TABLE IF NOT EXISTS permissions (
|
|
id SERIAL PRIMARY KEY,
|
|
name VARCHAR(100) UNIQUE NOT NULL,
|
|
description TEXT,
|
|
resource VARCHAR(50),
|
|
action VARCHAR(50),
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
`);
|
|
|
|
await client.query(`
|
|
CREATE TABLE IF NOT EXISTS role_permissions (
|
|
id SERIAL PRIMARY KEY,
|
|
role_id INTEGER REFERENCES roles(id) ON DELETE CASCADE,
|
|
permission_id INTEGER REFERENCES permissions(id) ON DELETE CASCADE,
|
|
UNIQUE(role_id, permission_id)
|
|
);
|
|
`);
|
|
|
|
await client.query(`
|
|
CREATE TABLE IF NOT EXISTS user_sessions (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
|
token_hash VARCHAR(255) NOT NULL,
|
|
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
last_used TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
user_agent TEXT,
|
|
ip_address INET
|
|
);
|
|
`);
|
|
|
|
// Insert default roles
|
|
await client.query(`
|
|
INSERT INTO roles (name, description) VALUES
|
|
('user', 'Standard user with basic permissions'),
|
|
('admin', 'Administrator with full system access')
|
|
ON CONFLICT (name) DO NOTHING;
|
|
`);
|
|
|
|
// Insert basic permissions
|
|
const permissions = [
|
|
['cards.read', 'View cards'],
|
|
['collections.manage', 'Manage collections'],
|
|
['decks.manage', 'Manage decks'],
|
|
['admin.access', 'Access admin panel']
|
|
];
|
|
|
|
for (const [name, description] of permissions) {
|
|
await client.query(`
|
|
INSERT INTO permissions (name, description)
|
|
VALUES ($1, $2)
|
|
ON CONFLICT (name) DO NOTHING;
|
|
`, [name, description]);
|
|
}
|
|
|
|
// Assign permissions to roles
|
|
await client.query(`
|
|
INSERT INTO role_permissions (role_id, permission_id)
|
|
SELECT r.id, p.id
|
|
FROM roles r, permissions p
|
|
WHERE r.name = 'user'
|
|
AND p.name IN ('cards.read', 'collections.manage', 'decks.manage')
|
|
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
|
`);
|
|
|
|
await client.query(`
|
|
INSERT INTO role_permissions (role_id, permission_id)
|
|
SELECT r.id, p.id
|
|
FROM roles r, permissions p
|
|
WHERE r.name = 'admin'
|
|
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
|
`);
|
|
|
|
// Create indexes
|
|
await client.query(`
|
|
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
|
CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
|
|
CREATE INDEX IF NOT EXISTS idx_user_roles_user_id ON user_roles(user_id);
|
|
`);
|
|
|
|
console.log('✅ User authentication schema setup completed!');
|
|
|
|
return new NextResponse(JSON.stringify({
|
|
success: true,
|
|
message: 'User authentication schema setup completed successfully'
|
|
}), {
|
|
status: 200,
|
|
headers: { 'Content-Type': 'application/json' },
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('Schema setup failed:', error);
|
|
return new NextResponse(JSON.stringify({
|
|
success: false,
|
|
error: 'Schema setup failed',
|
|
details: (error as Error).message
|
|
}), {
|
|
status: 500,
|
|
headers: { 'Content-Type': 'application/json' },
|
|
});
|
|
} finally {
|
|
client.release();
|
|
}
|
|
}
|