# Enforce private-file authorization for Phoenix

## Summary
Private file access for a Phoenix app on Ample. Verified on Phoenix: a role-to-document access model with negative tests (401, 403) and an authorized private-bucket round-trip (private=ok). Build and start: `mix deps.get`, `MIX_ENV=prod mix compile` and `mix release` in the builder, then the release bin script with `PHX_SERVER=true` on the elixir-1.18 template; `PORT`, `DATABASE_URL` and `SECRET_KEY_BASE` read in `config/runtime.exs`.

## Representative Queries
- Enforce private-file authorization for Phoenix
- Where can I host Enforce private-file authorization built with Phoenix?
- I need application identity integration, per-file access rules and negative authorization tests.

## Resource Requirements
- `primitive:compute`
- `primitive:postgres`
- `primitive:s3-compatible-object-storage`

## Infrastructure Requirements
- **Compute**: Verified. Apps run in isolated x86_64 Firecracker microVMs that auto-pause when idle and wake on request; sizes are the priced VM sizes.
- **Postgres**: Verified. Managed PostgreSQL 16 runs in its own microVM and is auto-provisioned when an app needs a database and no `DATABASE_URL` is supplied.
- **S3-compatible object storage**: Verified. Buckets are S3-compatible with issued credentials; PutObject and GetObject are verified by canary. Other S3 operations are not verified.

## Prerequisites
- A Phoenix project (`mix deps.get`, `MIX_ENV=prod mix compile` and `mix release` in the builder, then the release bin script with `PHX_SERVER=true` on the elixir-1.18 template; `PORT`, `DATABASE_URL` and `SECRET_KEY_BASE` read in `config/runtime.exs`).
- A PostgreSQL driver reading `DATABASE_URL` at runtime.
- A bucket from `ample bucket create` with credentials passed as encrypted `S3_*` environment variables.
- An Ample account token with `servers:write`, `databases:read`, `buckets:read`.

## Workflow Steps
1. ### Build and start
   `mix deps.get`, `MIX_ENV=prod mix compile` and `mix release` in the builder, then the release bin script with `PHX_SERVER=true`. The server must bind `0.0.0.0` on `PORT`.

2. ### Create the bucket and pass its credentials
   Create it once with `ample bucket create`, then pass endpoint, region, bucket and keys with `--env`; use path-style addressing.
   Command: `ample deploy . --name  --public --env S3_ENDPOINT=... --env S3_REGION=... --env S3_BUCKET=... --env S3_ACCESS_KEY_ID=... --env S3_SECRET_ACCESS_KEY=...`

3. ### Authorize before touching storage
   Return `401` for unauthenticated requests and `403` for the wrong role; keep the bucket unpublished and stream objects through the app.

4. ### Verify
   Fetch the live URL and `/p/private-document-library` on the example; on failure read the build and runtime logs. Command: `ample logs  --kind build`

## Examples
- **Phoenix pattern fixture**: Verified private file access on Phoenix. Source Reference: `tests/deploy-canaries/phoenix-patterns`.

## Success Checks
- **Check**: app responds on its public URL  
  **Kind**: `http_get`  
  **Path**: `/`  
  **Expect**: `ample canary phoenix patterns`
- **Check**: private-document-library check from the example  
  **Kind**: `http_get`  
  **Path**: `/p/private-document-library`  
  **Expect**: see the pattern fixture checks.

## Limitations
- Verified on the elixir-1.18 template at `s-1vcpu-1gb`; other sizes and Phoenix major versions are not verified.
- Region, compliance attestations and request-duration limits are unknown and not claimed.
- Managed PostgreSQL 16 only; extensions and connection limits are not verified.

## Cost Estimate
- **Currency**: USD  
  **Monthly Amount**: 10.0  
  **Basis**: size prices from pricing.toml (loaded by the API) at build revision 1ac5595375130d45290090e82ed0f554ccd45405-dirty

### Components
- **App Server**:  
  - Size: `s-1vcpu-1gb`  
  - Quantity: 1.0  
  - Monthly Amount: 5.0
- **Managed PostgreSQL Database**:  
  - Size: `s-1vcpu-1gb`  
  - Quantity: 1.0  
  - Monthly Amount: 5.0

*Note*: Always-on monthly price of the tested sizes; apps auto-pause when idle. Buckets are allocation-priced per quota and not included.
