Packages

Multi-tenancy library for Elixir/Phoenix with schema-based isolation (PostgreSQL Schemas or MySQL Databases). Lightweight, observable, with clean separation of concerns.

Current section

Files

Jump to
kirayedar lib mix tasks kirayedar.setup.ex
Raw

lib/mix/tasks/kirayedar.setup.ex

defmodule Mix.Tasks.Kirayedar.Setup do
alias Kirayedar.Utils
use Mix.Task
@shortdoc "Generates multi-tenancy infrastructure based on your preferred naming"
@moduledoc """
Generates the complete Kirayedar multi-tenancy setup for your application.
This task will:
- Generate the tenant model
- Create the tenant table migration
- Update your config.exs
- Optionally generate LiveView CRUD
## Usage
mix kirayedar.setup
You will be prompted for:
- Tenant resource name (e.g., "Tenant", "Organization")
- Whether to use binary_id (UUID)
- Admin host domain
- Whether to generate LiveViews
"""
def run(_args) do
Mix.shell().info("""
#{IO.ANSI.cyan()}
╔═══════════════════════════════════════╗
║ Kirayedar Multi-Tenancy Setup ║
╚═══════════════════════════════════════╝
#{IO.ANSI.reset()}
""")
# 1. Gather User Preferences
resource_raw_name =
Utils.prompt("What do you want to call your tenant/organization?", "Tenant")
use_binary_id = Mix.shell().yes?("Do you want to use binary_id (UUID)?")
admin_host = Utils.prompt("What is your Admin Host?", "localhost")
primary_domain = Utils.prompt("What is your primary domain?", "example.com")
need_liveviews = Mix.shell().yes?("Do you want to generate LiveViews for CRUD?")
app_name = Utils.app_name()
app_module = Utils.app_module()
naming = Utils.naming_conventions(resource_raw_name)
# 2. Setup Assigns for Templates
assigns = [
app_name: app_name,
app_module: app_module,
resource: naming.singular,
module: naming.module,
table: naming.plural,
use_binary_id: use_binary_id
]
# 3. Define paths
template_dir = Path.join([:code.priv_dir(:kirayedar), "templates", "kirayedar.setup"])
migration_folder = "priv/repo/#{assigns[:resource]}_migrations"
model_path = "lib/#{app_name}/#{assigns[:resource]}.ex"
File.mkdir_p!(migration_folder)
Mix.shell().info("Created #{migration_folder} directory...")
# 4. Generate Model File
Utils.generate_file_by_template(
template_dir,
"model.ex.eex",
model_path,
assigns
)
Mix.shell().info("✔ Generated Model at #{model_path}")
# 5. Generate Migration File
timestamp = Utils.now_timestamp()
migration_path = "priv/repo/migrations/#{timestamp}_create_#{assigns[:table]}.exs"
Utils.generate_file_by_template(
template_dir,
"migration.ex.eex",
migration_path,
assigns
)
Mix.shell().info("✔ Generated migration at #{migration_path}")
# 6. Update Config
update_config(
admin_host,
primary_domain,
assigns[:resource],
use_binary_id,
app_name,
app_module
)
# 7. Conditionally call the LiveView Generator
if need_liveviews do
Mix.shell().info("Triggering LiveView generation...")
Mix.Tasks.Kirayedar.Gen.Live.run([])
end
# 8. Print summary
print_summary(
naming,
admin_host,
primary_domain,
use_binary_id,
migration_path,
model_path,
need_liveviews
)
end
defp update_config(admin_host, primary_domain, resource, use_binary_id, app_name, app_module) do
config_path = "config/config.exs"
Application.put_env(:kirayedar, :admin_host, admin_host)
Application.put_env(:kirayedar, :primary_domain, primary_domain)
Application.put_env(:kirayedar, :tenant_resource, resource)
Application.put_env(:kirayedar, :binary_id, use_binary_id)
if File.exists?(config_path) do
original_content = File.read!(config_path)
new_config = """
# Kirayedar Multi-Tenancy Configuration
config :kirayedar,
repo: #{app_module}.Repo,
admin_host: "#{admin_host}",
primary_domain: "#{primary_domain}",
tenant_model: #{app_module}.#{Macro.camelize(resource)},
tenant_resource: :#{resource},
binary_id: #{use_binary_id}
"""
if String.contains?(original_content, "config :kirayedar") do
Mix.shell().info("Config for :kirayedar already exists. Skipping updates.")
else
pattern = ~r/import_config\s+"#\{config_env\(\)\}\.exs"/
updated_content =
if String.match?(original_content, pattern) do
String.replace(original_content, pattern, "#{new_config}\n\\0")
else
original_content <> "\n" <> new_config
end
File.write!(config_path, updated_content)
Mix.shell().info("✔ Updated config/config.exs")
end
else
Mix.shell().error("Could not find config/config.exs")
end
end
defp print_summary(
naming,
admin_host,
primary_domain,
use_binary_id,
migration_path,
model_path,
need_liveviews
) do
Mix.shell().info("""
#{IO.ANSI.green()}✔ Kirayedar Setup Complete!#{IO.ANSI.reset()}
#{IO.ANSI.yellow()}Summary:#{IO.ANSI.reset()}
• Resource: :#{naming.singular}
• Module: #{naming.module}
• Table: #{naming.plural}
• Admin Host: #{admin_host}
• Primary Domain: #{primary_domain}
• Binary ID: #{use_binary_id}
• Migration Path: #{migration_path}
• Model Path: #{model_path}
#{if need_liveviews, do: "• LiveViews: Generated", else: ""}
#{IO.ANSI.cyan()}Next Steps:#{IO.ANSI.reset()}
1. Run migrations:
mix ecto.migrate
2. Add the Kirayedar.Plug to your endpoint (lib/my_app_web/endpoint.ex):
plug Kirayedar.Plug
3. Update your Repo to use Kirayedar.Repo (lib/my_app/repo.ex):
use Kirayedar.Repo
4. Create your first tenant:
Kirayedar.create(MyApp.Repo, "acme_corp")
#{IO.ANSI.magenta()}Documentation:#{IO.ANSI.reset()}
• GitHub: https://github.com/yourusername/kirayedar
• Docs: https://hexdocs.pm/kirayedar
""")
end
def application do
[
extra_applications: [:logger]
]
end
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]
defp deps do
[
{:ecto_sql, "~> 3.12"},
{:plug, "~> 1.16"},
{:postgrex, "~> 0.19", optional: true},
{:myxql, "~> 0.7", optional: true},
{:phoenix_live_view, "~> 1.0", optional: true},
{:ex_doc, "~> 0.31", only: :dev, runtime: false},
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
{:dialyxir, "~> 1.4", only: [:dev], runtime: false}
]
end
defp description do
"""
Multi-tenancy library for Elixir/Phoenix with schema-based isolation
(PostgreSQL Schemas or MySQL Databases). Lightweight, observable,
with clean separation of concerns.
"""
end
defp package do
[
licenses: ["MIT"],
links: %{
"GitHub" => @source_url
},
maintainers: ["Your Name"]
]
end
defp docs do
[
main: "Kirayedar",
extras: ["README.md", "CHANGELOG.md"],
source_ref: "v#{@version}",
source_url: @source_url
]
end
end