ghostguild-org/scripts/add-coop-values-series.js

364 lines
11 KiB
JavaScript

import mongoose from 'mongoose';
import Series from '../server/models/series.js';
import Event from '../server/models/event.js';
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/ghostguild';
async function addCoopValuesSeries() {
try {
// Connect to MongoDB
await mongoose.connect(MONGODB_URI);
console.log('Connected to MongoDB');
// Create the series
const seriesData = {
id: 'coop-values-into-practice-2025',
title: 'Cooperative Values into Practice',
description: 'A practical, region-agnostic foundation in cooperative values and governance for game studio founders interested in worker-centric, anti-capitalist models. Structured as a peer-driven workshop emphasizing reciprocal learning and sharing.',
type: 'workshop_series',
isVisible: true,
isActive: true,
targetCircles: ['founder', 'practitioner'],
totalEvents: 6,
createdBy: 'admin@ghostguild.org',
tickets: {
enabled: true,
requiresSeriesTicket: false,
allowIndividualEventTickets: true,
currency: 'CAD',
member: {
available: true,
isFree: true,
price: 0,
name: 'Member Series Pass',
description: 'Free access to all sessions in the Cooperative Values into Practice series for Ghost Guild members.'
},
public: {
available: true,
name: 'Series Pass',
description: 'Access to all 6 sessions in the Cooperative Values into Practice series',
price: 150,
quantity: 20
},
capacity: {
total: 30
},
waitlist: {
enabled: true,
maxSize: 15
}
}
};
// Check if series already exists
let series = await Series.findOne({ id: seriesData.id });
if (series) {
console.log('Series already exists, updating...');
series = await Series.findOneAndUpdate(
{ id: seriesData.id },
seriesData,
{ new: true, runValidators: true }
);
} else {
console.log('Creating new series...');
series = new Series(seriesData);
await series.save();
}
console.log('Series created/updated:', series.title);
// Base date for scheduling (adjust as needed)
const baseDate = new Date('2025-11-01T18:00:00.000Z'); // Starting November 1, 2025, 6 PM UTC
// Create the events
const eventsData = [
{
title: 'Module 0: Orientation',
tagline: 'Welcome to Cooperative Values into Practice',
description: 'Introduce the goals and format of the program, quick power & identity reflections, Baby Ghosts values, and create group agreements.',
content: `## Welcome!
This orientation session kicks off our 6-month journey exploring cooperative values and governance for game studios.
## What We'll Cover
- Program goals and format
- Power & identity reflections
- Baby Ghosts values introduction
- Creating our group agreements together
## Homework
Power Flower exercise to complete before Module 1
## Who Should Attend
This series is designed for:
- Game studio founders interested in worker-centric models
- Practitioners exploring cooperative structures
- Anyone committed to anti-capitalist, democratic workplaces`,
position: 0,
weeks: 0
},
{
title: 'Module 1: Principles',
tagline: 'Understanding cooperative foundations',
description: 'Explore the difference between coops and traditional studios, foundational cooperative principles, historical and cultural context, and how they challenge industry norms.',
content: `## Cooperative Principles
Understanding what makes cooperatives different from traditional game studios.
## Topics
- Coops vs. traditional studios - key differences
- Foundational cooperative principles
- How cooperative values challenge industry norms
- Historical and cultural context
- Introduction to Coops for Creatives
## Activities
- Values Reflection exercise
- Value Mapping workshop
## Between Sessions
Reflect on how cooperative principles align with your studio vision.`,
position: 1,
weeks: 3
},
{
title: 'Module 2: Purpose',
tagline: 'Alignment, agreement, and shared vision',
description: 'Learn the difference between alignment, agreement, and false consensus. Reflect on cooperative origin stories, discuss financial needs and capacity, and map collective visions.',
content: `## Finding Your Cooperative Purpose
Moving beyond false consensus to genuine alignment.
## Topics
- The difference between alignment, agreement, and false consensus
- Reflecting on cooperative origin stories and values
- Discussing financial needs, availability, and capacity
- Mapping collective visions for scale and pace
- Clarifying roles, expectations, and contribution levels
## Activities
- Origin Stories sharing
- Solidarity Press exercise
- "The Talk" - discussing money and capacity
- Scale & Pace Alignment worksheets
## Between Sessions
Continue conversations about purpose and alignment with your team.`,
position: 2,
weeks: 4
},
{
title: 'Module 3: Practices Part 1 - Meetings & Decision-Making',
tagline: 'Democratic processes in action',
description: 'Move from boss-decides or majority-rules to cooperative approaches. Learn to redesign hierarchical meetings and facilitate inclusive, productive discussions.',
content: `## Democratic Practices: Meetings
Redesigning how we make decisions together.
## Topics
- Moving from boss-decides or majority-rules to cooperative approaches
- Redesigning hierarchical meetings
- Tips for facilitating inclusive, productive meetings
- Consensus-building techniques
- Managing power dynamics in meetings
## Activities
- Meeting redesign workshop
- Facilitation practice
- Decision-making simulations
## Between Sessions
Try implementing new meeting practices with your team.`,
position: 3,
weeks: 4
},
{
title: 'Module 4: Practices Part 2 - Finances & Governance',
tagline: 'Transparent systems for cooperative work',
description: 'Design transparent financial practices and systems, reframe disagreement as valuable information, and establish clear governance structures.',
content: `## Democratic Practices: Money & Structure
Building transparent financial and governance systems.
## Topics
- Designing transparent financial practices and systems
- Open book management for cooperatives
- Reframing disagreement from failure to valuable information
- Establishing clear governance systems
- Creating accountability without hierarchy
## Activities
- Financial transparency workshop
- Governance structure design
- Conflict as data reframing
## Between Sessions
Draft governance documents or financial transparency practices for your studio.`,
position: 4,
weeks: 4
},
{
title: 'Module 5: Pathways Forward',
tagline: 'Your cooperative journey continues',
description: 'Integrate learnings, share next steps, create accountability partnerships, and celebrate the work done together.',
content: `## Moving Forward Together
Bringing it all together and planning your next steps.
## Topics
- Integrating everything we've learned
- Individual and collective action plans
- Creating accountability partnerships
- Resources for ongoing learning
- Building a community of practice
## Activities
- Action planning workshop
- Accountability partner matching
- Celebration and reflection
## What's Next
Continue your cooperative journey with Ghost Guild support and your cohort connections.`,
position: 5,
weeks: 4
}
];
let currentDate = new Date(baseDate);
const createdEvents = [];
for (const eventData of eventsData) {
// Calculate dates
const startDate = new Date(currentDate);
const endDate = new Date(startDate);
endDate.setHours(endDate.getHours() + 2); // 2-hour sessions
const eventPayload = {
title: eventData.title,
tagline: eventData.tagline,
description: eventData.description,
content: eventData.content,
startDate,
endDate,
eventType: 'workshop',
location: '#ghost-guild-workshops', // Slack channel
isOnline: true,
isVisible: true,
membersOnly: false,
series: {
id: series.id,
title: series.title,
description: series.description,
type: series.type,
position: eventData.position + 1, // 1-indexed for display
totalEvents: 6,
isSeriesEvent: true
},
tickets: {
enabled: true,
requiresSeriesTicket: false,
seriesTicketReference: series._id,
currency: 'CAD',
member: {
available: true,
isFree: true,
price: 0,
name: 'Member Ticket',
description: 'Free for Ghost Guild members'
},
public: {
available: true,
name: 'Single Session Ticket',
description: 'Attend this individual session',
price: 30,
quantity: 10
},
capacity: {
total: 30
},
waitlist: {
enabled: true,
maxSize: 10
}
},
targetCircles: ['founder', 'practitioner'],
registrationRequired: true,
createdBy: 'admin@ghostguild.org'
};
// Check if event already exists (by title and series)
const existingEvent = await Event.findOne({
title: eventPayload.title,
'series.id': series.id
});
let event;
if (existingEvent) {
console.log(`Updating existing event: ${eventPayload.title}`);
event = await Event.findByIdAndUpdate(
existingEvent._id,
eventPayload,
{ new: true, runValidators: true }
);
} else {
console.log(`Creating event: ${eventPayload.title}`);
event = new Event(eventPayload);
await event.save();
}
createdEvents.push(event);
// Move to next session date (add weeks)
if (eventData.weeks > 0) {
currentDate.setDate(currentDate.getDate() + (eventData.weeks * 7));
}
}
// Update series with date range from events
const firstEvent = createdEvents[0];
const lastEvent = createdEvents[createdEvents.length - 1];
series.startDate = firstEvent.startDate;
series.endDate = lastEvent.endDate;
series.totalEvents = createdEvents.length;
await series.save();
console.log('\n✅ Successfully created/updated series and all events!');
console.log(`\nSeries: ${series.title}`);
console.log(`Events created: ${createdEvents.length}`);
console.log(`Date range: ${series.startDate.toLocaleDateString()} - ${series.endDate.toLocaleDateString()}`);
console.log('\nEvents:');
createdEvents.forEach((event, index) => {
console.log(` ${index + 1}. ${event.title} - ${event.startDate.toLocaleDateString()}`);
});
} catch (error) {
console.error('Error:', error);
} finally {
await mongoose.connection.close();
console.log('\nDatabase connection closed');
}
}
// Run the script
addCoopValuesSeries();