add setup foundations: site gate, registration lockdown, coming soon page

- Settings.site_live?/0 and set_site_live/1 for shop visibility control
- Accounts.has_admin?/0 to detect single-tenant admin existence
- Registration lockdown: /users/register redirects when admin exists
- Setup.setup_status/0 aggregates provider, product, and stripe checks
- Coming soon page at /coming-soon with themed styling
- ThemeHook :require_site_live gate on all public shop routes
  - Site live → everyone through
  - Authenticated → admin preview through
  - No admin → fresh install demo through
  - Otherwise → redirect to coming soon
- Go live / take offline toggle on /admin/settings
- 648 tests, 0 failures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-02-11 22:58:58 +00:00
parent 093bdcc7a6
commit e64bf40a71
16 changed files with 471 additions and 74 deletions

View File

@@ -60,6 +60,15 @@ defmodule SimpleshopTheme.Accounts do
"""
def get_user!(id), do: Repo.get!(User, id)
@doc """
Returns whether an admin user exists.
SimpleShop is single-tenant — any user in the database is the admin.
"""
def has_admin? do
Repo.exists?(User)
end
## User registration
@doc """

View File

@@ -116,6 +116,22 @@ defmodule SimpleshopTheme.Settings do
end
end
@doc """
Returns whether the shop is live (visible to the public).
Defaults to `false` for fresh installs.
"""
def site_live? do
get_setting("site_live", false) == true
end
@doc """
Sets whether the shop is live (visible to the public).
"""
def set_site_live(live?) when is_boolean(live?) do
put_setting("site_live", live?, "boolean")
end
@doc """
Deletes a setting by key.
"""

View File

@@ -0,0 +1,33 @@
defmodule SimpleshopTheme.Setup do
@moduledoc """
Aggregates setup status checks for the admin setup flow.
"""
alias SimpleshopTheme.{Accounts, Products, Settings}
@doc """
Returns a map describing the current setup status.
Used by the admin setup checklist and ThemeHook gate to determine
what's been completed and whether the shop can go live.
"""
def setup_status do
conn = Products.get_provider_connection_by_type("printify")
product_count = Products.count_products_for_connection(conn && conn.id)
printify_connected = conn != nil and conn.api_key_encrypted != nil
products_synced = product_count > 0
stripe_connected = Settings.has_secret?("stripe_api_key")
site_live = Settings.site_live?()
%{
admin_created: Accounts.has_admin?(),
printify_connected: printify_connected,
products_synced: products_synced,
product_count: product_count,
stripe_connected: stripe_connected,
site_live: site_live,
can_go_live: printify_connected and products_synced and stripe_connected
}
end
end