- Create Economist SubmissionTracking package correctly: * mainArticle = full blog post content * coverLetter = 216-word SIR— letter * Links to blog post via blogPostId - Archive 'Letter to The Economist' from blog posts (it's the cover letter) - Fix date display on article cards (use published_at) - Target publication already displaying via blue badge Database changes: - Make blogPostId optional in SubmissionTracking model - Economist package ID: 68fa85ae49d4900e7f2ecd83 - Le Monde package ID: 68fa2abd2e6acd5691932150 Next: Enhanced modal with tabs, validation, export 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
103 lines
3.1 KiB
JavaScript
103 lines
3.1 KiB
JavaScript
/**
|
||
* Deploy Approved Blogs to Production
|
||
* Migrates 3 vetted blog posts from dev to prod database
|
||
*/
|
||
|
||
const { MongoClient } = require('mongodb');
|
||
|
||
const DEV_URI = 'mongodb://localhost:27017';
|
||
const DEV_DB = 'tractatus_dev';
|
||
|
||
// Approved slugs (passed moderation)
|
||
const APPROVED_SLUGS = [
|
||
'when-frameworks-fail-case-study',
|
||
'five-component-tractatus-architecture',
|
||
'tractatus-blog-system-launch'
|
||
];
|
||
|
||
// Blocked slug (HIGH severity violations)
|
||
const BLOCKED_SLUGS = [
|
||
'why-ai-safety-requires-architectural-boundaries-not-just-training'
|
||
];
|
||
|
||
async function deployBlogs() {
|
||
const devClient = new MongoClient(DEV_URI);
|
||
|
||
try {
|
||
console.log('📦 Deploying Approved Blogs to Production\n');
|
||
console.log('━'.repeat(50));
|
||
|
||
// Connect to dev
|
||
await devClient.connect();
|
||
const devDb = devClient.db(DEV_DB);
|
||
const devBlogCollection = devDb.collection('blog_posts');
|
||
|
||
// Fetch approved blogs
|
||
const approvedBlogs = await devBlogCollection.find({
|
||
slug: { $in: APPROVED_SLUGS }
|
||
}).toArray();
|
||
|
||
console.log(`\n✅ Found ${approvedBlogs.length} approved blogs in dev:\n`);
|
||
approvedBlogs.forEach((blog, i) => {
|
||
console.log(` ${i + 1}. ${blog.title}`);
|
||
console.log(` Slug: ${blog.slug}`);
|
||
console.log(` Author: ${blog.author.name} (${blog.author.type})`);
|
||
console.log(` Status: ${blog.status}\n`);
|
||
});
|
||
|
||
// Check for blocked blog
|
||
const blockedBlog = await devBlogCollection.findOne({
|
||
slug: { $in: BLOCKED_SLUGS }
|
||
});
|
||
|
||
if (blockedBlog) {
|
||
console.log('⛔ BLOCKED from production (HIGH violations):\n');
|
||
console.log(` - ${blockedBlog.title}`);
|
||
console.log(` Reason: Uses "guarantee" (inst_017 violation)`);
|
||
console.log(` Action Required: Must be revised before deployment\n`);
|
||
}
|
||
|
||
console.log('━'.repeat(50));
|
||
console.log('\n📋 Export blog data for manual production import:');
|
||
console.log('\nRun this on production server:');
|
||
console.log('\nmongosh tractatus_prod <<EOF');
|
||
|
||
approvedBlogs.forEach(blog => {
|
||
// Remove _id to allow MongoDB to generate new ones on insert
|
||
const { _id, ...blogWithoutId } = blog;
|
||
console.log(`db.blog_posts.updateOne(
|
||
{ slug: "${blog.slug}" },
|
||
{ $set: ${JSON.stringify(blogWithoutId, null, 2)} },
|
||
{ upsert: true }
|
||
);`);
|
||
});
|
||
|
||
console.log('EOF\n');
|
||
console.log('━'.repeat(50));
|
||
|
||
} catch (error) {
|
||
console.error('❌ Error:', error.message);
|
||
throw error;
|
||
} finally {
|
||
await devClient.close();
|
||
}
|
||
}
|
||
|
||
// Run if called directly
|
||
if (require.main === module) {
|
||
deployBlogs()
|
||
.then(() => {
|
||
console.log('\n✨ Blog deployment data generated');
|
||
console.log('\n⚠️ Manual step required:');
|
||
console.log(' 1. SSH to production server');
|
||
console.log(' 2. Run the mongosh commands shown above');
|
||
console.log(' 3. Verify blogs appear at https://agenticgovernance.digital/blog.html\n');
|
||
process.exit(0);
|
||
})
|
||
.catch(error => {
|
||
console.error('\n💥 Deployment failed:', error);
|
||
process.exit(1);
|
||
});
|
||
}
|
||
|
||
module.exports = { deployBlogs, APPROVED_SLUGS, BLOCKED_SLUGS };
|