# Phoenix Setup

This guide shows the intended Phoenix integration path: supervise `Sftpd`,
authenticate through your app, and use the auth session map to scope backend
storage.

It covers:

- supervised startup and shutdown
- runtime configuration for deploy-specific values
- local static auth for development
- password and public-key auth backed by your app
- tenant-scoped S3 storage using session context
- deployment notes for host keys and port exposure

## Supervision

Add `Sftpd` to your application supervisor:

```elixir
children = [
  {Sftpd,
   port: Application.fetch_env!(:my_app, :sftp_port),
   system_dir: Application.fetch_env!(:my_app, :sftp_system_dir),
   auth: {MyApp.SftpAuth, []},
   backend: Sftpd.Backends.S3,
   backend_opts: [
     bucket: Application.fetch_env!(:my_app, :sftp_bucket),
     prefix: {:session, :sftp_prefix}
   ]}
]
```

`Sftpd.child_spec/1` owns the SSH daemon lifecycle and stops it when your
supervisor stops.

## Runtime Config

Use runtime config for deploy-specific values:

```elixir
# config/runtime.exs
config :my_app,
  sftp_port: String.to_integer(System.get_env("SFTP_PORT", "2222")),
  sftp_system_dir: System.fetch_env!("SFTP_SYSTEM_DIR"),
  sftp_bucket: System.fetch_env!("SFTP_BUCKET")
```

`system_dir` must point at persistent SSH host keys. Do not generate new host
keys on every deploy unless clients are prepared for host-key rotation.

## Local Static Auth

For local development without app auth:

```elixir
{Sftpd,
 port: 2222,
 system_dir: "priv/sftp_host_keys",
 auth: {:passwords, [{"dev", "dev"}]},
 backend: Sftpd.Backends.Memory,
 backend_opts: []}
```

## Password Auth

Implement `Sftpd.Auth` in your app. The returned session map is opaque to
`Sftpd` except where built-in backends document specific keys.

```elixir
defmodule MyApp.SftpAuth do
  @behaviour Sftpd.Auth

  alias MyApp.Accounts

  @impl true
  def authenticate_password(username, password, _peer, _opts) do
    with {:ok, user} <- Accounts.authenticate_sftp_user(username, password) do
      {:ok,
       %{
         user_id: user.id,
         tenant_id: user.tenant_id,
         sftp_prefix: "tenants/#{user.tenant_id}/"
       }}
    else
      _ -> :error
    end
  end

  @impl true
  def authorize_public_key(username, public_key, _opts) do
    fingerprint = Sftpd.Auth.fingerprint(public_key)

    with {:ok, user} <- Accounts.get_sftp_user_by_key(username, fingerprint) do
      {:ok,
       %{
         user_id: user.id,
         tenant_id: user.tenant_id,
         sftp_prefix: "tenants/#{user.tenant_id}/"
       }}
    else
      _ -> :error
    end
  end
end
```

## Public Keys

Store public-key fingerprints in your database:

```elixir
{:ok, public_key} = Sftpd.Auth.decode_authorized_key(authorized_key_line)
fingerprint = Sftpd.Auth.fingerprint(public_key)
```

The fingerprint is suitable for lookup during `authorize_public_key/3`.

## Tenant-Scoped S3

Use `prefix: {:session, :sftp_prefix}` to scope every S3 object key by the
authenticated session:

```elixir
backend_opts: [
  bucket: "uploads",
  prefix: {:session, :sftp_prefix}
]
```

If auth returns `%{sftp_prefix: "tenants/123/"}`, an upload to `/invoice.pdf`
is stored as `tenants/123/invoice.pdf`.

## Deployment Notes

Expose the configured TCP port through your load balancer or host firewall.
Persist the SSH host key directory across deploys. Keep application passwords,
public-key fingerprints, S3 bucket names, and endpoint credentials in your
normal runtime secret/config path.

## Next Steps

- Choose production storage in [Backends](BACKENDS.md).
- Add metrics and logging with [Telemetry](TELEMETRY.md).
- Implement non-S3 storage with [Custom Backends](CUSTOM_BACKENDS.md).
