Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"

# Generate realistic, reproducible local seed data
gem "faker"

# Audits gems for known security defects (use config/bundler-audit.yml to ignore issues)
gem "bundler-audit", require: false

Expand Down
4 changes: 4 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ GEM
factory_bot_rails (6.5.1)
factory_bot (~> 6.5)
railties (>= 6.1.0)
faker (3.8.0)
i18n (>= 1.8.11, < 2)
faraday (2.14.1)
faraday-net_http (>= 2.0, < 3.5)
json
Expand Down Expand Up @@ -537,6 +539,7 @@ DEPENDENCIES
debug
diffy
factory_bot_rails
faker
image_processing (~> 1.2)
importmap-rails
jbuilder
Expand Down Expand Up @@ -612,6 +615,7 @@ CHECKSUMS
event_stream_parser (1.0.0) sha256=a2683bab70126286f8184dc88f7968ffc4028f813161fb073ec90d171f7de3c8
factory_bot (6.5.6) sha256=12beb373214dccc086a7a63763d6718c49769d5606f0501e0a4442676917e077
factory_bot_rails (6.5.1) sha256=d3cc4851eae4dea8a665ec4a4516895045e710554d2b5ac9e68b94d351bc6d68
faker (3.8.0) sha256=c147b308df73a90f27a4fc84f18d4c22ef0ad9c2a64b2b61c86fd0ca71753efc
faraday (2.14.1) sha256=a43cceedc1e39d188f4d2cdd360a8aaa6a11da0c407052e426ba8d3fb42ef61c
faraday-mashify (1.0.2) sha256=ebdc93b3f807af9a4b18c3d967fc7bcda01e297aed9cc2015ffe8db6e7add2e9
faraday-multipart (1.2.0) sha256=7d89a949693714176f612323ca13746a2ded204031a6ba528adee788694ef757
Expand Down
145 changes: 5 additions & 140 deletions db/seeds.rb
Original file line number Diff line number Diff line change
@@ -1,141 +1,6 @@
puts "Seeding users..."
hampton = CoPlan::User.find_or_create_by!(email: "hampton@squareup.com") do |u|
u.external_id = "hampton@squareup.com"
u.name = "Hampton Lintorn-Catlin"
u.username = "hampton"
u.admin = true
u.avatar_url = "https://avatars.githubusercontent.com/u/111?s=80"
u.title = "Staff Engineer"
u.team = "Developer Tools"
if Rails.env.local?
require_relative "seeds/development"
CoPlan::DevelopmentSeed.call
else
warn "Development seed data is only available in development and test environments."
end
hampton.update!(avatar_url: "https://avatars.githubusercontent.com/u/111?s=80") if hampton.avatar_url.blank?

puts "Seeding plans..."
if CoPlan::Plan.count == 0
plan = CoPlan::Plans::Create.call(
title: "Q3 Product Roadmap",
content: "# Q3 Product Roadmap\n\n## Goals\n\n- Launch new dashboard\n- Improve API performance\n- Add team collaboration features\n\n## Timeline\n\n### Month 1\n- Design reviews\n- Technical planning\n\n### Month 2\n- Core implementation\n- Testing\n\n### Month 3\n- Beta launch\n- Feedback collection\n",
user: hampton
)
plan.update!(status: "considering")
end

puts "Seeding comments..."
if CoPlan::CommentThread.count == 0
plan = CoPlan::Plan.first
if plan&.current_plan_version
reviewer = CoPlan::User.find_or_create_by!(email: "reviewer@squareup.com") do |u|
u.external_id = "reviewer@squareup.com"
u.name = "Plan Reviewer"
u.title = "Senior Engineer"
u.team = "Platform"
end

thread = CoPlan::CommentThread.create!(
plan: plan,
plan_version: plan.current_plan_version,
start_line: 5,
end_line: 8,
created_by_user: reviewer
)
thread.comments.create!(
author_type: "human",
author_id: reviewer.id,
body_markdown: "I think the timeline for Month 1 is too aggressive. Can we break this into smaller milestones?"
)

general_thread = CoPlan::CommentThread.create!(
plan: plan,
plan_version: plan.current_plan_version,
created_by_user: hampton
)
general_thread.comments.create!(
author_type: "human",
author_id: hampton.id,
body_markdown: "Overall this is looking good. Let's move forward with the **beta launch** plan."
)
end
end

puts "Seeding API tokens..."
if CoPlan::ApiToken.count == 0
raw_token = "dev-api-token-#{SecureRandom.hex(8)}"
CoPlan::ApiToken.create!(
user: hampton,
name: "Development Agent",
token_digest: Digest::SHA256.hexdigest(raw_token),
token_prefix: raw_token[0, 8]
)
puts " Created API token: #{raw_token}"
puts " (Save this — it won't be shown again)"
end

puts "Seeding plan types..."
# Icons come from the built-in named set (CoPlan::PlansHelper::PLAN_TYPE_ICONS)
# so each install can brand its document types.
general = CoPlan::PlanType.find_or_create_by!(name: "General") do |pt|
pt.description = "General-purpose plan"
end
general.update!(icon: "file-text") if general.icon.blank?
CoPlan::PlanType.find_or_create_by!(name: "RFC") do |pt|
pt.description = "Request for Comments — propose a significant change for team review"
pt.default_tags = ["rfc"]
end.tap { |pt| pt.update!(icon: "scroll") if pt.icon.blank? }
CoPlan::PlanType.find_or_create_by!(name: "Design Doc") do |pt|
pt.description = "Technical design document for a new system or feature"
pt.default_tags = ["design"]
end.tap { |pt| pt.update!(icon: "compass") if pt.icon.blank? }
CoPlan::PlanType.find_or_create_by!(name: "ADR") do |pt|
pt.description = "Architecture Decision Record — document a key technical decision"
pt.default_tags = ["adr"]
end.tap { |pt| pt.update!(icon: "scale") if pt.icon.blank? }

# Backfill any plans without a plan type
CoPlan::Plan.where(plan_type_id: nil).update_all(plan_type_id: general.id)

puts "Seeding tags on plans..."
CoPlan::Plan.includes(:tags, :plan_type).find_each do |p|
if p.tags.empty? && p.plan_type&.default_tags&.any?
p.tag_names = p.plan_type.default_tags
end
end

# Add some demo plans with tags for local development
if CoPlan::Plan.count < 3
rfc_type = CoPlan::PlanType.find_by(name: "RFC")
design_type = CoPlan::PlanType.find_by(name: "Design Doc")

api_plan = CoPlan::Plans::Create.call(
title: "API Rate Limiting Strategy",
content: "# API Rate Limiting Strategy\n\n## Problem\n\nOur API endpoints have no rate limiting, leading to occasional abuse.\n\n## Proposal\n\nImplement token-bucket rate limiting at the gateway level.\n\n## Alternatives Considered\n\n- Per-IP limiting\n- API key quotas\n",
user: hampton,
plan_type_id: rfc_type&.id
)
api_plan.update!(status: "considering")
api_plan.tag_names = ["api", "infrastructure", "security"]

auth_plan = CoPlan::Plans::Create.call(
title: "Authentication System Redesign",
content: "# Authentication System Redesign\n\n## Goals\n\n- Migrate from session-based to token-based auth\n- Support SSO providers\n- Improve security posture\n\n## Architecture\n\nOIDC-based flow with JWT access tokens.\n",
user: hampton,
plan_type_id: design_type&.id
)
auth_plan.update!(status: "developing")
auth_plan.tag_names = ["security", "infrastructure", "design"]
end

# Tag the original Q3 roadmap if it has no tags
q3 = CoPlan::Plan.find_by(title: "Q3 Product Roadmap")
q3.tag_names = ["roadmap", "product"] if q3 && q3.tags.empty?

puts "Seeding folders..."
if CoPlan::Folder.count == 0
product = CoPlan::Folder.find_or_create_by_path!("Product/Q3", created_by_user: hampton)
infra = CoPlan::Folder.find_or_create_by_path!("Infrastructure", created_by_user: hampton)

q3&.update!(folder: product) if q3&.folder_id.nil?
api_seed = CoPlan::Plan.find_by(title: "API Rate Limiting Strategy")
api_seed&.update!(folder: infra) if api_seed&.folder_id.nil?
end

puts "Done! #{CoPlan::User.count} users, #{CoPlan::Plan.count} plans, #{CoPlan::Folder.count} folders, #{CoPlan::CommentThread.count} threads, #{CoPlan::Comment.count} comments, #{CoPlan::ApiToken.count} API tokens."
Loading
Loading