Administrator configuration

Configure external services, e-mail, translation and application locales.

OpenDataBio works without optional external services, but administrators must make explicit decisions about e-mail delivery, taxonomic services, assisted translation and the locales available to users. Keep credentials in the installation environment file; never commit them to the source repository.

The shipped environment templates leave USER_TRANSLATION_PROVIDER and all service credentials empty. Apache, nginx and Docker installation therefore do not silently enable translation or make an external request. During the interactive direct-server installer, answering the optional Google question with its default no keeps the feature disabled. Configure services only after deciding who will manage credentials, quotas and operating costs.

After changing .env or .env.production, refresh the application configuration:

php artisan optimize:clear
php artisan config:cache

For Docker production, run Artisan inside the application container and use paths as seen inside that container.

Media imports and upload limits

Use this reference set in the installation’s .env (.env.production for production Docker). Existing installations must add the variables: updating a template does not change the active environment file.

MEDIA_MAX_FILE_SIZE=209715200
MEDIA_IMPORT_MAX_ARCHIVE_KB=1048576
MEDIA_IMPORT_MAX_ENTRY_BYTES=209715200
MEDIA_IMPORT_MAX_UNCOMPRESSED_BYTES=2147483648
MEDIA_IMPORT_MAX_ENTRIES=5000
MEDIA_IMPORT_MAX_COMPRESSION_RATIO=100
MEDIA_IMPORT_CHUNK_SIZE=50
MEDIA_IMPORT_CHUNK_SECONDS=30
MEDIA_IMPORT_WORKER_TIMEOUT=300
MEDIA_IMPORT_CONCURRENT_CHUNKS=1
MEDIA_IMPORT_RETENTION_DAYS=7
MEDIA_IMPORT_DELIVERY_RETRY_SECONDS=600
MEDIA_IMPORT_LOCK_STORE=redis
QUEUE_CONNECTION=redis
REDIS_DB=0
REDIS_CACHE_DB=1

MEDIA_MAX_FILE_SIZE limits each media file to 200 MiB and also contributes to file limits for other imports. ZIPs allow 1 GiB, each extracted entry 200 MiB, and total extracted content 2 GiB. Sizes are bytes except MEDIA_IMPORT_MAX_ARCHIVE_KB, which is KiB. The 5000-entry ceiling includes metadata and directories; the compression ratio ceiling applies per entry.

Each execution processes up to 50 rows or a 30-second budget checked between files. One file can exceed that budget; the 300-second timeout covers the whole execution, including ZIP preparation. Workers need pcntl to enforce it. One concurrent media execution is the starting point for controlling CPU, memory and disk usage in multiuser installations. Larger upload limits do not require more concurrency.

Redis carries jobs and shared locks; the database stores progress. Keep the queue Redis database (0) separate from cache/locks (1). The scheduler recovers interrupted or lost deliveries; 600 seconds is the reference recovery interval, not the normal delay between chunks. Temporary files for inactive failed or cancelled imports expire after 7 days; an expired import requires a new upload.

Align application, PHP and web server limits

The lowest limit anywhere in the upload path wins. Livewire follows the configured ZIP/media limits, but .env does not configure PHP, Apache, Nginx or external proxies. For this reference set, configure the PHP serving the website:

upload_max_filesize = 1024M
post_max_size = 1100M
max_input_time = 1800

Use client_max_body_size 1100M; in Nginx and LimitRequestBody 1153433600 in Apache. The margin above 1 GiB accommodates the rest of the request. Apply compatible limits to external proxies too. These uploads do not require increasing MySQL’s max_allowed_packet: ZIPs and media are stored on disk.

max_input_time is an initial allowance for slow uploads; buffering and server/proxy timeouts also affect the result. Do not increase every timeout to match the total batch duration: processing runs in the queue. Size memory for decoded images and concurrency, not ZIP size. A 200 MiB file ceiling does not guarantee every image fits in available memory. Allow disk space for temporary uploads, extraction and final media across users; the extracted-content limit is per ZIP, not a global storage quota.

Apply and verify configuration changes

  1. Edit the environment file actually used by the installation.
  2. Run php artisan config:cache and php artisan queue:restart, keeping Supervisor active to relaunch workers.
  3. Check the website’s php.ini: php --ini only describes CLI PHP. Apache mod_php and PHP-FPM use their own configuration; pool/VirtualHost overrides can also change effective values.
  4. Validate and reload Apache/Nginx; restart or reload PHP-FPM when applicable.
  5. For Docker, follow the installation page’s rebuild/recreation instructions.
  6. Test a representative ZIP and follow its UserJob to completion, including failure recovery. Check the scheduler, storage access and worker logs.

Google Cloud Translation

OpenDataBio uses Cloud Translation Advanced (v3) only to translate user-maintained content in edit forms. Interface strings under lang/ are not sent to Google. Generated text fills missing fields and must be reviewed before the record is saved. Import jobs never invoke Google automatically.

Google requires billing even when usage remains within an applicable free credit. Review current pricing, set a budget alert, and restrict quotas before enabling the service.

  1. Sign in to the Google Cloud console.
  2. Create or select a project and record its project ID.
  3. Link a billing account.
  4. Under APIs & Services, enable Cloud Translation API.
  5. Under IAM & Admin → Service Accounts, create a dedicated service account for OpenDataBio.
  6. Grant that service account Cloud Translation API User (roles/cloudtranslate.user). Do not grant Owner, Editor, Admin, or the Cloud Translation service-agent role.
  7. Create a JSON key for the service account and download it once. Store it outside the repository, readable by the web-server user and not by other system users.
  8. Configure:
USER_TRANSLATION_PROVIDER=google
GOOGLE_CLOUD_PROJECT=your-google-project-id
GOOGLE_TRANSLATION_LOCATION=global
GOOGLE_APPLICATION_CREDENTIALS=/absolute/server/path/google-translation.json
USER_TRANSLATION_MAX_CHARACTERS_PER_REQUEST=10000
USER_TRANSLATION_TIMEOUT=30

For Apache or nginx, the credential file and all parent directories must be accessible to the PHP/web-server user. A typical permission arrangement is:

sudo chgrp www-data /secure/path/google-translation.json
sudo chmod 750 /secure/path
sudo chmod 640 /secure/path/google-translation.json

For Docker production, place the file under the untracked docker-secrets/ directory, mount it read-only, and set the environment value to its container path, for example:

GOOGLE_APPLICATION_CREDENTIALS=/run/secrets/google-translation.json

Verify configuration first without an external request, then with a short live translation:

php artisan translations:check --source=en --target=es
php artisan translations:check --source=en --target=es --live

Disable assisted translation at any time by leaving USER_TRANSLATION_PROVIDER empty.

Tropicos

Tropicos Web Services requires a personal API key in every request.

Configuring it improves taxonomic curation by allowing editors to search and validate published botanical names against Tropicos instead of relying only on the local library or other external sources.

  1. Open the Tropicos API-key request page.
  2. Submit the requested contact and intended-use information.
  3. Store the issued key in the installation environment:
MOBOT_API_KEY=your-tropicos-api-key

If no key is configured, OpenDataBio remains functional and other configured taxonomic services, primarily GBIF, can still be used. Do not expose the key in client-side code or commit it.

Pl@ntNet image identification

OpenDataBio can send one to five images of the same plant to Pl@ntNet and show species, genus and family candidates for human review. Results are cached, an identification is never changed automatically, and applying a candidate still requires the normal OpenDataBio permissions.

Create a free developer account on the Pl@ntNet sign-up page, then generate or manage the key under API-key settings. See the official getting-started guide and API reference for current quotas, terms and request details.

OpenDataBio supports two credential sources:

  • Server key: configured by an administrator and shared by users who do not have a personal key. Its quota is shared by the installation.
  • Personal key: stored by a registered user in Edit profile. It is encrypted at rest, takes precedence over the server key, and uses that Pl@ntNet account’s independent quota.

For an installation that provides a shared server key, configure:

PLANTNET_API_KEY=your-server-plantnet-key
PLANTNET_ALLOW_USER_KEYS=true
PLANTNET_SERVER_FALLBACK=true
PLANTNET_DAILY_REQUEST_LIMIT=500
PLANTNET_DAILY_USER_LIMIT=20

With this configuration, personal keys are preferred. Users without one fall back to PLANTNET_API_KEY. PLANTNET_DAILY_REQUEST_LIMIT is a local safety ceiling per credential; PLANTNET_DAILY_USER_LIMIT limits a non-administrator’s use of the shared server key. Pl@ntNet’s reported remote balance is also respected. Administrators are exempt from the per-user shared-key limit, but not from the credential’s local or remote quota.

To require personal keys and avoid a shared installation quota:

PLANTNET_API_KEY=
PLANTNET_ALLOW_USER_KEYS=true
PLANTNET_SERVER_FALLBACK=false
PLANTNET_DAILY_REQUEST_LIMIT=500

In this mode, Pl@ntNet remains available to every user who stores a valid personal key. Users without one do not see the identification action. Leaving PLANTNET_API_KEY empty does not disable personal keys.

To disable personal credentials while retaining only the installation key, set PLANTNET_ALLOW_USER_KEYS=false. If neither an allowed personal key nor an enabled server fallback is available, Pl@ntNet identification is unavailable; the rest of OpenDataBio continues to work.

Requests are sent by the OpenDataBio server, not directly by the browser. Therefore, normal OpenDataBio use does not require enabling Expose my API key or adding the OpenDataBio URL under Pl@ntNet CORS authorized domains. If you deliberately expose the key in Pl@ntNet settings, follow Pl@ntNet’s current instructions and authorize the server IP for non-CORS requests.

After changing the environment, run the configuration refresh commands shown at the top of this page. Never commit either server or personal keys.

E-mail

E-mail is used for password recovery, optional address verification, dataset requests and job notifications. Production installations should use a dedicated SMTP account or transactional provider.

Without working e-mail, administrators must support account recovery manually, users can miss access-request decisions and long-running background work cannot reliably notify them when attention is required.

MAIL_MAILER=smtp
MAIL_HOST=smtp.example.org
MAIL_PORT=587
MAIL_USERNAME=opendatabio@example.org
MAIL_PASSWORD=replace-with-secret
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=opendatabio@example.org
MAIL_FROM_NAME="${APP_NAME}"
MAIL_VERIFY_PEER=true
MAIL_VERIFY_PEER_NAME=true
MAIL_ALLOW_SELF_SIGNED=false
EMAIL_VERIFICATION_ENABLED=false

Use port 465 with the encryption required by your provider when applicable. Keep certificate verification enabled in production. Enable EMAIL_VERIFICATION_ENABLED only after outbound delivery and password recovery have been tested. Queue workers must be running for queued notifications.

Locale responsibilities

OpenDataBio keeps three concepts separate:

  • APP_LOCALE is the permanent primary locale and is always required for translatable content.
  • Interface locales have complete application translation files under lang/<code>/.
  • Content locales are languages in which users may maintain UserTranslation values. They do not require an interface translation.

ODB_INTERFACE_LOCALES and ODB_CONTENT_LOCALES initialize a new installation. For an existing installation, use Admin → Application locales or:

php artisan locales:configure --interfaces=en,es,pt-br --content=en,es,pt-br
php artisan locales:audit

Add a content-only locale

  1. In Admin → Application locales, add a normalized code such as fr or es-mx and a human-readable name.
  2. Enable User content.
  3. Do not enable Interface unless lang/<code>/ is complete.
  4. Add a provider mapping in config/user-translation.php if the translation provider does not accept the application code directly.

Existing records are not automatically backfilled. Users may open their edit forms and explicitly generate missing translations. Bulk imports must supply their translations explicitly.

Add a new interface locale

  1. Copy the complete key structure from an existing lang/<code>/ directory into lang/<new-code>/.
  2. Translate every value in application context without changing keys, placeholders, HTML structure, or pluralization syntax.
  3. Add the locale name to config/languages.php.
  4. Run the locale audit and application tests.
  5. Deploy the code containing the translation files.
  6. Add/enable the locale through the admin page or locales:configure.
  7. Clear caches. Rebuild resources/api/odb_param_schema.json with its generator when releasing documentation/schema changes; never edit the generated JSON manually.

When upgrading OpenDataBio, compare the new .env.example with the deployed environment, run database migrations, run php artisan locales:audit, and update every installed lang/<code>/ directory with any newly introduced translation keys before enabling that interface.