berrypod/lib/berrypod/setup.ex
jamey 5b41f3fedf extract site_name and site_description from theme settings into standalone settings
site_name and site_description are shop identity, not theme concerns.
They now live in the Settings table as first-class settings with their
own assigns (@site_name, @site_description) piped through hooks and
plugs. The setup wizard writes site_name on account creation, and the
theme editor reads/writes via Settings.put_setting. Removed the
"configure your shop" checklist item since currency/country aren't
built yet. Also adds shop name field to setup wizard step 1.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 14:52:31 +00:00

105 lines
3.5 KiB
Elixir

defmodule Berrypod.Setup do
@moduledoc """
Aggregates setup status checks for the setup flow and launch checklist.
"""
alias Berrypod.{Accounts, Mailer, Orders, Products, Settings, Shipping}
@setup_secret_key :berrypod_setup_secret
@doc """
Returns the setup secret for first-run admin creation.
In prod, gates access to the setup form so only someone with server access
(log output or SETUP_SECRET env var) can create the admin account.
Reads from SETUP_SECRET env var first, otherwise auto-generates a random
token and stores it in :persistent_term for the lifetime of the node.
"""
def setup_secret do
case System.get_env("SETUP_SECRET") do
nil ->
case :persistent_term.get(@setup_secret_key, nil) do
nil ->
secret =
:crypto.strong_rand_bytes(16)
|> Base.url_encode64(padding: false)
:persistent_term.put(@setup_secret_key, secret)
secret
secret ->
secret
end
secret ->
secret
end
end
@doc """
Returns whether the setup secret gate should be shown.
True in prod when no admin exists. False in dev/test.
"""
def require_setup_secret? do
Application.get_env(:berrypod, :env, :dev) == :prod and not Accounts.has_admin?()
end
@doc """
Returns a map describing the current setup status.
Used by the setup page, dashboard launch checklist, and ThemeHook gate.
## Setup phase (connections)
* `admin_created` — at least one user exists
* `provider_connected` — a provider connection with an API key exists
* `provider_type` — the connected provider's type (e.g. "printify"), or nil
* `stripe_connected` — Stripe API key is stored
* `setup_complete` — all three connections made
## Launch checklist phase
* `products_synced` / `product_count` — products imported
* `has_shipping` — at least one shipping rate exists
* `theme_customised` — theme settings have been saved at least once
* `has_orders` — at least one paid order exists
* `email_configured` — email adapter configured and verified
* `site_live` — shop is open to the public
* `can_go_live` — minimum requirements met to go live (includes shipping)
* `checklist_dismissed` — admin has dismissed the launch checklist
"""
def setup_status do
conn = Products.get_first_provider_connection()
product_count = Products.count_products()
provider_connected = conn != nil
products_synced = product_count > 0
stripe_connected = Settings.has_secret?("stripe_api_key")
admin_created = Accounts.has_admin?()
site_live = Settings.site_live?()
has_shipping = Shipping.has_shipping_rates?()
%{
# Setup phase
admin_created: admin_created,
provider_connected: provider_connected,
provider_type: conn && conn.provider_type,
stripe_connected: stripe_connected,
setup_complete: admin_created and provider_connected and stripe_connected,
# Launch checklist
products_synced: products_synced,
product_count: product_count,
has_shipping: has_shipping,
theme_customised: Settings.get_setting("theme_customised", false) == true,
has_orders: Orders.has_paid_orders?(),
email_configured: Mailer.email_configured?(),
site_live: site_live,
can_go_live: provider_connected and products_synced and stripe_connected and has_shipping,
checklist_dismissed: Settings.get_setting("checklist_dismissed", false) == true
}
end
end