//! Seed one project per creator (their [`ProjectSpec`]), spread across genres. //! //! Each project is public the moment it is inserted: `create_project` leaves //! `is_public` at its `true` default and never sets `is_sandbox`, so the pair //! (durable creator + project) clears the only two public-visibility gates. The //! project's pricing, items, and tiers land in [`super::items`]; this module //! returns enough context ([`SeededProject`]) for that step. use super::SeedError; use super::creators::{ProjectSpec, SeededCreator}; use crate::db::{self, DbProject, Slug, UserId}; /// A project after insertion, with the owner and spec its items still need. pub struct SeededProject { /// The owning creator's id (needed for ownership-checked item/pricing writes). pub user_id: UserId, /// The inserted project row. pub project: DbProject, /// The spec that produced it, carries the item, pricing, and tier data. pub spec: &'static ProjectSpec, } /// Create the one project each seeded creator owns. /// /// Called from [`super::run`] immediately after [`super::creators::seed_creators`], /// with the creators it returned. `create_project` auto-suffixes any slug /// collision and defaults the project to public, so no publish step is needed. pub async fn seed_projects( pool: &sqlx::PgPool, creators: &[SeededCreator], ) -> Result, SeedError> { let mut seeded = Vec::with_capacity(creators.len()); for creator in creators { let spec = creator.project; let slug = Slug::from_trusted(spec.slug.to_string()); let features: Vec = spec .features .iter() .map(std::string::ToString::to_string) .collect(); let project = db::projects::create_project( pool, creator.user.id, &slug, spec.title, Some(spec.description), &features, ) .await?; tracing::info!( slug = %project.slug, user_id = %creator.user.id, "example seed: created project" ); seeded.push(SeededProject { user_id: creator.user.id, project, spec, }); } Ok(seeded) }