@@ -54,5 +54,159 @@ namespace :pwb do
5454 rescue Pwb ::TenantShardMigrator ::MigrationError => e
5555 puts "Migration aborted: #{ e . message } "
5656 end
57+
58+ desc "Create and provision a new website on a specific shard"
59+ task :provision_new , [ :subdomain , :shard_name ] => :environment do |_ , args |
60+ subdomain = args [ :subdomain ] &.strip &.downcase
61+ shard_name = args [ :shard_name ] &.strip
62+
63+ unless subdomain && shard_name
64+ puts "Usage: rake 'pwb:sharding:provision_new[subdomain,shard_name]'"
65+ puts ""
66+ puts "Examples:"
67+ puts " rake 'pwb:sharding:provision_new[brisbane,demo]'"
68+ puts " rake 'pwb:sharding:provision_new[my-agency,shard_1]'"
69+ puts ""
70+ puts "Options (via ENV):"
71+ puts " SITE_TYPE=residential|commercial|vacation_rental (default: residential)"
72+ puts " SEED_PACK=base|residential|commercial (default: base)"
73+ puts " OWNER_EMAIL=user@example.com (optional - creates owner user)"
74+ puts " SKIP_PROPERTIES=true (skip seeding sample properties)"
75+ puts ""
76+ puts "Available shards:"
77+ Pwb ::ShardRegistry . logical_shards . each do |logical |
78+ status = Pwb ::ShardRegistry . configured? ( logical ) ? "configured" : "not configured"
79+ puts " #{ logical } (#{ status } )"
80+ end
81+ next
82+ end
83+
84+ target_shard = shard_name . to_sym
85+
86+ # Validate shard
87+ unless Pwb ::ShardRegistry . configured? ( target_shard )
88+ puts "ERROR: Shard '#{ target_shard } ' is not configured in database.yml"
89+ puts ""
90+ puts "Available configured shards:"
91+ Pwb ::ShardRegistry . logical_shards . each do |logical |
92+ puts " #{ logical } " if Pwb ::ShardRegistry . configured? ( logical )
93+ end
94+ next
95+ end
96+
97+ # Check if website already exists
98+ existing = Pwb ::Website . find_by ( subdomain : subdomain )
99+ if existing
100+ puts "ERROR: Website with subdomain '#{ subdomain } ' already exists (id: #{ existing . id } , shard: #{ existing . shard_name } )"
101+ next
102+ end
103+
104+ # Configuration from ENV
105+ site_type = ENV . fetch ( 'SITE_TYPE' , 'residential' )
106+ seed_pack = ENV . fetch ( 'SEED_PACK' , 'base' )
107+ owner_email = ENV [ 'OWNER_EMAIL' ]
108+ skip_properties = ENV [ 'SKIP_PROPERTIES' ] == 'true'
109+
110+ puts "\n === Provisioning New Website ==="
111+ puts "Subdomain: #{ subdomain } "
112+ puts "Shard: #{ target_shard } "
113+ puts "Site type: #{ site_type } "
114+ puts "Seed pack: #{ seed_pack } "
115+ puts "Owner email: #{ owner_email || '(none)' } "
116+ puts "Skip properties: #{ skip_properties } "
117+ puts "=" * 40
118+
119+ ActiveRecord ::Base . transaction do
120+ # Create owner user if email provided
121+ user = nil
122+ if owner_email . present?
123+ user = Pwb ::User . find_or_create_by! ( email : owner_email . downcase ) do |u |
124+ u . password = SecureRandom . hex ( 16 )
125+ u . onboarding_state = 'active'
126+ end
127+ puts "\n Owner user: #{ user . email } (id: #{ user . id } )"
128+ end
129+
130+ # Create the website
131+ website = Pwb ::Website . new (
132+ subdomain : subdomain ,
133+ site_type : site_type ,
134+ shard_name : target_shard . to_s ,
135+ seed_pack_name : seed_pack ,
136+ provisioning_state : 'pending' ,
137+ owner_email : owner_email
138+ )
139+
140+ unless website . save
141+ puts "ERROR: Failed to create website: #{ website . errors . full_messages . join ( ', ' ) } "
142+ raise ActiveRecord ::Rollback
143+ end
144+
145+ puts "Website created: id=#{ website . id } "
146+
147+ # Create owner membership if user exists
148+ if user
149+ Pwb ::UserMembership . create! (
150+ user : user ,
151+ website : website ,
152+ role : 'owner' ,
153+ active : true
154+ )
155+ user . update! ( website : website )
156+ puts "Owner membership created"
157+ end
158+
159+ # Provision the website
160+ puts "\n Provisioning website..."
161+ service = Pwb ::ProvisioningService . new
162+ result = service . provision_website ( website : website , skip_properties : skip_properties ) do |progress |
163+ puts " #{ progress [ :percentage ] } % - #{ progress [ :message ] } "
164+ end
165+
166+ unless result [ :success ]
167+ puts "\n ERROR: Provisioning failed: #{ result [ :errors ] . join ( ', ' ) } "
168+ raise ActiveRecord ::Rollback
169+ end
170+
171+ website . reload
172+ puts "\n === Provisioning Complete ==="
173+ puts "Website ID: #{ website . id } "
174+ puts "Subdomain: #{ website . subdomain } "
175+ puts "Shard: #{ website . shard_name } "
176+ puts "State: #{ website . provisioning_state } "
177+
178+ base_domain = ENV . fetch ( 'BASE_DOMAIN' , 'propertywebbuilder.com' )
179+ puts "URL: https://#{ website . subdomain } .#{ base_domain } "
180+
181+ if website . locked_pending_email_verification?
182+ puts "\n Note: Website is locked pending email verification."
183+ puts "To go live immediately, run:"
184+ puts " rake 'pwb:sharding:go_live[#{ website . id } ]'"
185+ end
186+ end
187+ rescue StandardError => e
188+ puts "\n ERROR: #{ e . message } "
189+ puts e . backtrace . first ( 5 ) . join ( "\n " ) if ENV [ 'DEBUG' ]
190+ end
191+
192+ desc "Force a website to go live (skip email verification)"
193+ task :go_live , [ :website_id ] => :environment do |_ , args |
194+ unless args [ :website_id ]
195+ puts "Usage: rake 'pwb:sharding:go_live[website_id]'"
196+ next
197+ end
198+
199+ website = Pwb ::Website . find ( args [ :website_id ] )
200+
201+ unless website . locked_pending_email_verification?
202+ puts "Website is not in locked state (current: #{ website . provisioning_state } )"
203+ next
204+ end
205+
206+ website . verify_and_go_live!
207+ puts "Website #{ website . subdomain } is now live!"
208+ rescue AASM ::InvalidTransition => e
209+ puts "ERROR: Cannot transition to live: #{ e . message } "
210+ end
57211 end
58212end
0 commit comments