Multi-instance digital asset repository
Elevator can store content in any format, such as images, audio, video, 3D objects, Sharable Content Object Reference Model (SCORM) bundles, and Portable Document Files (PDF) files. Elevator also provides a suite of standard tools for previewing and playing even exotic assets, like 3D walkthroughs and rotatable 3D objects.
- Flexible metadata schema. Create the schemas that are appropriate for your content, mix and match schemas, or make changes at any time.
- Any digital asset. Traditional media files, a Microsoft Office document, a SCORM bundle, or a proprietary filetype — Elevator can catalog it, archive it, and in most cases offer rich display.
- Cloud storage. Designed to run on Amazon Web Services.
- Email: elevator@umn.edu
- Docker Desktop
gh— GitHub CLI, authenticated withgh auth login. Required to fetch the Elasticsearch setup script from the private ansible repo.mkcert(optional but recommended) — generates locally-trusted SSL certs. Without it, bootstrap falls back to a self-signed cert that will show browser warnings.
bash scripts/bootstrapThe script handles everything: copying .env, generating SSL certs, starting Docker, installing PHP and Node dependencies, running the Doctrine schema, seeding the database, syncing the admin password, and setting up the Elasticsearch index with the correct mapping. It's safe to re-run — steps that are already complete are skipped.
The Elasticsearch step fetches the canonical index setup script from ansible-elevator-v2 via gh, so you'll need the gh CLI installed and authenticated (gh auth login) with access to that repo.
After the script finishes:
- App:
https://localhost/defaultinstance - Admin: username
admin, password isDEFAULT_ADMIN_PASSWORDfrom your.env(default:admin). To change it, updateDEFAULT_ADMIN_PASSWORDin.envand re-run./scripts/bootstrap.
Each worktree needs its own .env with unique port values so their Docker stacks don't collide:
HTTP_PORT=8080
HTTPS_PORT=8443
POSTGRES_PORT=5433
REDIS_PORT=6380
ELASTICSEARCH_PORT=9201
ELASTICSEARCH_TRANSPORT_PORT=9301
BEANSTALKD_PORT=11301See .env.example for the full list and defaults.
Upload a file through the UI, then grab the fileObjectId (press Cmd+Ctrl+H when viewing the asset):
./docker/runJob.sh <fileObjectId>Update DEFAULT_ADMIN_PASSWORD in .env and re-run ./scripts/bootstrap.
npm testRequires DEFAULT_ADMIN_PASSWORD to be set in .env. CI_ENV=local (the default) is sufficient to enable the database-reset endpoint the tests use.
Elevator uses Doctrine for schema management. The entity PHP files are generated from XML descriptors in application/doctrine/.
- Edit the XML descriptor (e.g.
application/doctrine/Entity.Foo.dcm.xml) - Regenerate the PHP entity:
docker compose exec php-fpm php doctrine.php orm:generate-entities application/models - Preview the SQL:
docker compose exec php-fpm php doctrine.php orm:schema-tool:update --dump-sql - Apply it:
docker compose exec php-fpm php doctrine.php orm:schema-tool:update --force - Clear the Doctrine cache (models are cached in Redis):
docker compose exec redis redis-cli flushdb
Elevator requires S3 for file storage — there is no local storage fallback. File uploads and processing will fail until an S3 bucket is configured.
S3 credentials are set per instance in the admin UI (Instance settings → Amazon S3 Key / Secret / Bucket), not in .env.
Preferred: ask the team for dev server S3 credentials and use those. This skips bucket setup and lets you process real files immediately.
Optional — set up your own bucket:
- Create an S3 bucket (e.g.
elevator-local-yourname) - In IAM, create a new user with a policy granting
s3:*on that bucket - Generate an access key for the user — save the key and secret (shown once)
- Apply the following bucket policy (replace the bucket name):
{
"Version": "2008-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "AWS": "*" },
"Action": "s3:GetObject",
"Resource": [
"arn:aws:s3:::YOUR-BUCKET/derivative/*streaming/*",
"arn:aws:s3:::YOUR-BUCKET/thumbnail/*",
"arn:aws:s3:::YOUR-BUCKET/vtt/*"
]
},
{
"Effect": "Deny",
"Principal": { "AWS": "*" },
"Action": ["s3:DeleteObject", "s3:DeleteObjectVersion"],
"Resource": "arn:aws:s3:::YOUR-BUCKET/original/*",
"Condition": { "Null": { "aws:MultiFactorAuthAge": true } }
},
{
"Effect": "Deny",
"Principal": { "AWS": "*" },
"Action": "s3:PutLifecycleConfiguration",
"Resource": "arn:aws:s3:::YOUR-BUCKET",
"Condition": { "Null": { "aws:MultiFactorAuthAge": true } }
}
]
}- Enter the key, secret, bucket name, and region in the admin UI under Instance settings
The AWS_QUEUEING_* vars in .env are separate — they're for the AWS Batch job queue used for background file processing, and are only needed if you're not using the local Beanstalkd queue.
docker system prune -a --volumes -f
docker builder prune -a -fThis typically frees 20–40 GB and clears the error.
Make sure your .env has ELASTIC_HOST=elasticsearch:9200 (the :9200 port suffix is required).
If the index exists but search returns nothing, the index mapping is likely missing or stale. Do a full reset:
# Re-fetch the setup script and rebuild the index from scratch
bash scripts/bootstrapOr manually, if you want to avoid re-running the full bootstrap:
_idx="elevator" # match ELASTIC_INDEX in .env
curl -XDELETE "http://localhost:9200/${_idx}_1"
curl -XDELETE "http://localhost:9200/${_idx}"
bash scripts/elastic_setup.sh localhost "${_idx}_1" "${_idx}"
docker compose exec php-fpm php index.php admin reindexAssets are automatically re-indexed on save, so a full reindex is only needed after a mapping change or bulk data import.
Docs use VuePress and live in ./docs.
# develop docs locally
npm run docs:dev
# deploy docs
npm run docs:deploy