# Host Product Catalog with Symfony: Authorized File Delivery

## Summary
Deploy a product catalog built with Symfony on Ample using the generated downloads pattern. Compute runs the app in an isolated microVM behind a public HTTPS URL, a managed PostgreSQL 16 database is auto-provisioned and injected as DATABASE_URL, a private S3-compatible bucket holds objects with credentials delivered as encrypted environment variables.  
Verified on Symfony: an export query rendered to a CSV artifact stored with metadata in a private bucket and returned only to an authorized caller (401 without token, export=ok rows=3). Not separately tested: your export formats, retention policy and entitlement model; treat the product catalog-specific behavior as your application code.

## Infrastructure Requirements
- **Compute**: Apps run in isolated x86_64 Firecracker microVMs that auto-pause when idle and wake on request; sizes are the priced VM sizes.
- **Postgres**: 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**: Buckets are S3-compatible with issued credentials; PutObject and GetObject are verified by canary. Other S3 operations are not verified.

## Prerequisites
1. A Symfony project that builds and starts with the documented commands: `composer install --no-dev` from `composer.lock` with Symfony Runtime's dotenv disabled.
2. A PostgreSQL driver reading DATABASE_URL at runtime.
3. A bucket created with `ample bucket create` with its credentials passed as encrypted S3_* environment variables.
4. An Ample account token with required permissions.

## Tested Configuration
- **Template**: php-8.5
- **Runtime**: php
- **Size**: s-1vcpu-1gb
- **Install Command**: `composer install --no-dev --prefer-dist --no-interaction --no-progress --optimize-autoloader`
- **Start Command**: `frankenphp php-server --listen :$PORT --root public`

## Workflow Steps
1. **Build and start**  
   `composer install --no-dev`. The server must bind 0.0.0.0 on PORT.
2. **Implement the pattern on PostgreSQL**  
   The fixture's module implements generated downloads. Keep migrations idempotent and run them with --release-command.
3. **Wire object storage**  
   Create the bucket(s), then pass endpoint, region, bucket, and keys as --env values.  
4. **Deploy**  
   Run the synchronous deploy once and read the result.
5. **Verify**  
   Fetch the live URL and run checks on failure.

## Examples
- Multi-pattern Symfony app whose generated downloads module was checked live.

## Limitations
- Verified on the php-8.5 template at s-1vcpu-1gb; other sizes, templates, and Symfony major versions not verified.
- The product catalog export formats and retention policy were not separately tested.

## Cost Estimate
- **Monthly Amount**: $10.00
   - **App Server**: $5.00 (s-1vcpu-1gb)
   - **Managed PostgreSQL Database**: $5.00 (s-1vcpu-1gb)
  
**Note**: Always-on monthly price of the tested sizes; buckets are allocation-priced per quota.

## Evidence Summary
1. **Canary Run**: Symfony pattern fixture deployed on Ample. Checks passed for generated downloads.
   - **Observed At**: 2026-09-20T22:23:52Z
   - **Expires At**: 2027-03-19T22:23:52Z
2. **Canary Run**: The same Symfony app deployed with a --release-command migration.
   - **Observed At**: 2026-09-20T22:23:52Z
   - **Expires At**: 2027-03-19T22:23:52Z

## Next Actions
- **Browse Catalog Index**: Method: GET, Path: "/v1/catalog"
- **Search Published Recipes by Intent**: Method: POST, Path: "/v1/catalog/search"
- **Prepare a Deployment Plan**: Method: POST, Path: "/v1/catalog/plan"
- **Read Existing Authentication Setup**: Method: GET, Path: "/mcp/setup"
- **Browse Product Catalog**: Method: GET, Path: "/v1/catalog/nodes/workload%3Aproduct-catalog"
