feat: add MongoDB systemd service and database initialization
- Create mongodb-tractatus.service for systemd management - Add installation script for service setup - Create init-db.js with complete collection schemas and indexes - Configure 10 MongoDB collections: documents, blog_posts, media_inquiries, case_submissions, resources, moderation_queue, users, citations, translations, koha_donations - Add indexes for performance optimization - Include verification and statistics output MongoDB Port: 27017 Database: tractatus_dev Status: Ready for service installation
This commit is contained in:
parent
4445b0e8d0
commit
4f8de209f3
3 changed files with 292 additions and 0 deletions
202
scripts/init-db.js
Normal file
202
scripts/init-db.js
Normal file
|
|
@ -0,0 +1,202 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Database Initialization Script for Tractatus
|
||||||
|
*
|
||||||
|
* Creates all required collections and indexes for the Tractatus platform
|
||||||
|
* Run with: node scripts/init-db.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { MongoClient } = require('mongodb');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
// Load environment variables
|
||||||
|
require('dotenv').config({ path: path.join(__dirname, '../.env') });
|
||||||
|
|
||||||
|
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/tractatus_dev';
|
||||||
|
const DB_NAME = process.env.MONGODB_DB || 'tractatus_dev';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection schemas and indexes
|
||||||
|
*/
|
||||||
|
const COLLECTIONS = {
|
||||||
|
documents: {
|
||||||
|
indexes: [
|
||||||
|
{ keys: { slug: 1 }, options: { unique: true } },
|
||||||
|
{ keys: { quadrant: 1 } },
|
||||||
|
{ keys: { 'metadata.document_code': 1 } },
|
||||||
|
{ keys: { search_index: 'text' } },
|
||||||
|
{ keys: { 'metadata.date_created': -1 } }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
blog_posts: {
|
||||||
|
indexes: [
|
||||||
|
{ keys: { slug: 1 }, options: { unique: true } },
|
||||||
|
{ keys: { status: 1 } },
|
||||||
|
{ keys: { published_at: -1 } },
|
||||||
|
{ keys: { 'author.type': 1 } },
|
||||||
|
{ keys: { tags: 1 } }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
media_inquiries: {
|
||||||
|
indexes: [
|
||||||
|
{ keys: { 'contact.email': 1 } },
|
||||||
|
{ keys: { status: 1 } },
|
||||||
|
{ keys: { created_at: -1 } },
|
||||||
|
{ keys: { 'ai_triage.urgency': 1 } }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
case_submissions: {
|
||||||
|
indexes: [
|
||||||
|
{ keys: { 'submitter.email': 1 } },
|
||||||
|
{ keys: { 'moderation.status': 1 } },
|
||||||
|
{ keys: { submitted_at: -1 } },
|
||||||
|
{ keys: { 'ai_review.relevance_score': -1 } }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
resources: {
|
||||||
|
indexes: [
|
||||||
|
{ keys: { url: 1 }, options: { unique: true } },
|
||||||
|
{ keys: { category: 1 } },
|
||||||
|
{ keys: { status: 1 } },
|
||||||
|
{ keys: { alignment_score: -1 } }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
moderation_queue: {
|
||||||
|
indexes: [
|
||||||
|
{ keys: { item_type: 1 } },
|
||||||
|
{ keys: { status: 1 } },
|
||||||
|
{ keys: { priority: 1 } },
|
||||||
|
{ keys: { created_at: -1 } },
|
||||||
|
{ keys: { quadrant: 1 } }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
users: {
|
||||||
|
indexes: [
|
||||||
|
{ keys: { email: 1 }, options: { unique: true } },
|
||||||
|
{ keys: { role: 1 } },
|
||||||
|
{ keys: { created_at: -1 } }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
citations: {
|
||||||
|
indexes: [
|
||||||
|
{ keys: { document_id: 1 } },
|
||||||
|
{ keys: { citation_type: 1 } },
|
||||||
|
{ keys: { cited_at: -1 } }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
translations: {
|
||||||
|
indexes: [
|
||||||
|
{ keys: { original_id: 1, language: 1 }, options: { unique: true } },
|
||||||
|
{ keys: { language: 1 } },
|
||||||
|
{ keys: { status: 1 } }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
koha_donations: {
|
||||||
|
indexes: [
|
||||||
|
{ keys: { stripe_payment_id: 1 }, options: { unique: true } },
|
||||||
|
{ keys: { 'donor.email': 1 } },
|
||||||
|
{ keys: { frequency: 1 } },
|
||||||
|
{ keys: { timestamp: -1 } },
|
||||||
|
{ keys: { status: 1 } }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize database
|
||||||
|
*/
|
||||||
|
async function initializeDatabase() {
|
||||||
|
console.log('🚀 Starting Tractatus database initialization...\n');
|
||||||
|
console.log(`MongoDB URI: ${MONGODB_URI}`);
|
||||||
|
console.log(`Database: ${DB_NAME}\n`);
|
||||||
|
|
||||||
|
const client = new MongoClient(MONGODB_URI);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await client.connect();
|
||||||
|
console.log('✅ Connected to MongoDB\n');
|
||||||
|
|
||||||
|
const db = client.db(DB_NAME);
|
||||||
|
|
||||||
|
// Get existing collections
|
||||||
|
const existingCollections = await db.listCollections().toArray();
|
||||||
|
const existingNames = existingCollections.map(c => c.name);
|
||||||
|
|
||||||
|
// Create collections and indexes
|
||||||
|
for (const [collectionName, config] of Object.entries(COLLECTIONS)) {
|
||||||
|
console.log(`📦 Processing collection: ${collectionName}`);
|
||||||
|
|
||||||
|
// Create collection if it doesn't exist
|
||||||
|
if (!existingNames.includes(collectionName)) {
|
||||||
|
await db.createCollection(collectionName);
|
||||||
|
console.log(` ✓ Created collection`);
|
||||||
|
} else {
|
||||||
|
console.log(` ⊙ Collection already exists`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create indexes
|
||||||
|
const collection = db.collection(collectionName);
|
||||||
|
for (const indexSpec of config.indexes) {
|
||||||
|
try {
|
||||||
|
const indexName = await collection.createIndex(
|
||||||
|
indexSpec.keys,
|
||||||
|
indexSpec.options || {}
|
||||||
|
);
|
||||||
|
console.log(` ✓ Created index: ${indexName}`);
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code === 85 || error.code === 86) {
|
||||||
|
// Index already exists
|
||||||
|
console.log(` ⊙ Index already exists`);
|
||||||
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify collections
|
||||||
|
console.log('🔍 Verifying database setup...');
|
||||||
|
const finalCollections = await db.listCollections().toArray();
|
||||||
|
console.log(` ✓ Total collections: ${finalCollections.length}`);
|
||||||
|
|
||||||
|
// Display collection statistics
|
||||||
|
console.log('\n📊 Collection Statistics:');
|
||||||
|
for (const collectionName of Object.keys(COLLECTIONS)) {
|
||||||
|
const collection = db.collection(collectionName);
|
||||||
|
const count = await collection.countDocuments();
|
||||||
|
const indexes = await collection.indexes();
|
||||||
|
console.log(` ${collectionName}:`);
|
||||||
|
console.log(` Documents: ${count}`);
|
||||||
|
console.log(` Indexes: ${indexes.length}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n✨ Database initialization complete!\n');
|
||||||
|
console.log('Next steps:');
|
||||||
|
console.log(' 1. Run document migration: npm run migrate:docs');
|
||||||
|
console.log(' 2. Create admin user: npm run seed:admin');
|
||||||
|
console.log(' 3. Start development server: npm run dev\n');
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Error initializing database:', error);
|
||||||
|
process.exit(1);
|
||||||
|
} finally {
|
||||||
|
await client.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run initialization
|
||||||
|
if (require.main === module) {
|
||||||
|
initializeDatabase().catch(console.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { initializeDatabase, COLLECTIONS };
|
||||||
53
scripts/install-mongodb-service.sh
Executable file
53
scripts/install-mongodb-service.sh
Executable file
|
|
@ -0,0 +1,53 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Install mongodb-tractatus systemd service
|
||||||
|
# Run with: sudo ./install-mongodb-service.sh
|
||||||
|
#
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SERVICE_NAME="mongodb-tractatus.service"
|
||||||
|
SERVICE_FILE="./mongodb-tractatus.service"
|
||||||
|
SYSTEMD_DIR="/etc/systemd/system"
|
||||||
|
|
||||||
|
echo "Installing MongoDB Tractatus systemd service..."
|
||||||
|
|
||||||
|
# Check if running as root
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
echo "Error: This script must be run with sudo"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if service file exists
|
||||||
|
if [ ! -f "$SERVICE_FILE" ]; then
|
||||||
|
echo "Error: $SERVICE_FILE not found in current directory"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy service file to systemd directory
|
||||||
|
echo "Copying service file to $SYSTEMD_DIR..."
|
||||||
|
cp "$SERVICE_FILE" "$SYSTEMD_DIR/$SERVICE_NAME"
|
||||||
|
|
||||||
|
# Set correct permissions
|
||||||
|
chmod 644 "$SYSTEMD_DIR/$SERVICE_NAME"
|
||||||
|
|
||||||
|
# Reload systemd daemon
|
||||||
|
echo "Reloading systemd daemon..."
|
||||||
|
systemctl daemon-reload
|
||||||
|
|
||||||
|
# Enable service to start on boot
|
||||||
|
echo "Enabling service to start on boot..."
|
||||||
|
systemctl enable "$SERVICE_NAME"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "MongoDB Tractatus service installed successfully!"
|
||||||
|
echo ""
|
||||||
|
echo "Commands:"
|
||||||
|
echo " Start: sudo systemctl start $SERVICE_NAME"
|
||||||
|
echo " Stop: sudo systemctl stop $SERVICE_NAME"
|
||||||
|
echo " Restart: sudo systemctl restart $SERVICE_NAME"
|
||||||
|
echo " Status: sudo systemctl status $SERVICE_NAME"
|
||||||
|
echo " Logs: sudo journalctl -u $SERVICE_NAME -f"
|
||||||
|
echo ""
|
||||||
|
echo "To start the service now, run:"
|
||||||
|
echo " sudo systemctl start $SERVICE_NAME"
|
||||||
37
scripts/mongodb-tractatus.service
Normal file
37
scripts/mongodb-tractatus.service
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
[Unit]
|
||||||
|
Description=MongoDB Database Server for Tractatus
|
||||||
|
Documentation=https://docs.mongodb.org/manual
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=forking
|
||||||
|
User=theflow
|
||||||
|
Group=theflow
|
||||||
|
|
||||||
|
# MongoDB executable and configuration
|
||||||
|
ExecStart=/home/theflow/projects/mongodb/mongodb-server/bin/mongod \
|
||||||
|
--port 27017 \
|
||||||
|
--dbpath /home/theflow/projects/tractatus/data/mongodb \
|
||||||
|
--logpath /home/theflow/projects/tractatus/logs/mongodb.log \
|
||||||
|
--fork \
|
||||||
|
--quiet
|
||||||
|
|
||||||
|
ExecStop=/home/theflow/projects/mongodb/mongodb-server/bin/mongod \
|
||||||
|
--port 27017 \
|
||||||
|
--dbpath /home/theflow/projects/tractatus/data/mongodb \
|
||||||
|
--shutdown
|
||||||
|
|
||||||
|
# Restart policy
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
# Security settings
|
||||||
|
PrivateTmp=true
|
||||||
|
NoNewPrivileges=true
|
||||||
|
LimitNOFILE=64000
|
||||||
|
|
||||||
|
# Working directory
|
||||||
|
WorkingDirectory=/home/theflow/projects/tractatus
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
Loading…
Add table
Reference in a new issue