tractatus/scripts/deploy-blogs-to-production.js
TheFlow 2298d36bed fix(submissions): restructure Economist package and fix article display
- 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>
2025-10-24 08:47:42 +13:00

103 lines
3.1 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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 };