feat: add seed-tags and migrate-community-connections scripts

Idempotent seed for 16 craft + 20 cooperative tags by slug. Migration
maps existing offering/lookingFor tags to communityConnections.topics
and copies peerSupport fields without deleting originals.
This commit is contained in:
Jennie Robinson Faber 2026-04-05 16:11:52 +01:00
parent 4b6ff19d5f
commit 1cb029a881
2 changed files with 324 additions and 0 deletions

111
scripts/seed-tags.js Normal file
View file

@ -0,0 +1,111 @@
/**
* Seed Script: Tags
*
* Upserts craft and cooperative tags by slug (idempotent).
* Safe to run multiple times.
*/
import 'dotenv/config'
import mongoose from 'mongoose'
import Tag from '../server/models/tag.js'
import { connectDB } from '../server/utils/mongoose.js'
// Convert a slug like "qa-and-testing" to "QA and Testing"
// Special-cases common abbreviations.
const ABBREVIATIONS = new Set(['qa', 'ux', 'ui', 'devops'])
function slugToLabel(slug) {
return slug
.split('-')
.map((word) => {
if (ABBREVIATIONS.has(word)) return word.toUpperCase()
return word.charAt(0).toUpperCase() + word.slice(1)
})
.join(' ')
}
const CRAFT_SLUGS = [
'game-design',
'programming',
'narrative-design',
'art-and-animation',
'audio-and-music',
'production-management',
'qa-and-testing',
'community-management',
'marketing-and-comms',
'ux-and-ui-design',
'business-development',
'devops-and-tools',
'localization',
'accessibility',
'analytics-and-data',
'education-and-mentoring',
]
const COOPERATIVE_SLUGS = [
'governance',
'finance-and-budgeting',
'legal-structures',
'conflict-resolution',
'consensus-decision-making',
'revenue-sharing',
'cooperative-bylaws',
'member-onboarding',
'democratic-management',
'worker-ownership',
'platform-cooperativism',
'cooperative-marketing',
'shared-resources',
'cooperative-funding',
'community-building',
'equity-and-inclusion',
'cooperative-tech',
'sustainability',
'collective-bargaining',
'inter-coop-collaboration',
]
async function seedTags() {
await connectDB()
const tagDefs = [
...CRAFT_SLUGS.map((slug) => ({ slug, pool: 'craft', label: slugToLabel(slug) })),
...COOPERATIVE_SLUGS.map((slug) => ({ slug, pool: 'cooperative', label: slugToLabel(slug) })),
]
let upserted = 0
let unchanged = 0
for (const { slug, pool, label } of tagDefs) {
const result = await Tag.updateOne(
{ slug },
{ $setOnInsert: { slug, pool, label, active: true, createdAt: new Date() } },
{ upsert: true }
)
if (result.upsertedCount > 0) {
console.log(` + Created [${pool}] ${label} (${slug})`)
upserted++
} else {
unchanged++
}
}
console.log('\n=== Seed Complete ===')
console.log(` Total tags defined: ${tagDefs.length}`)
console.log(` Newly created: ${upserted}`)
console.log(` Already existed: ${unchanged}`)
}
seedTags()
.then(() => {
console.log('\nTag seed completed successfully')
process.exit(0)
})
.catch((err) => {
console.error('\nTag seed failed:', err)
process.exit(1)
})
.finally(() => {
mongoose.connection.close()
})