### Quick start: copy .env and start Docker Compose Source: https://docs.externa.qiick.io/docs/installation Use these commands to set up and launch the full stack with Docker Compose. Copy the example environment file to .env, then build and start containers. The app will be available at http://localhost:8000. ```bash cd /path/to/externa-core cp .env.docker.example .env docker compose up --build ``` -------------------------------- ### Install and run the Next.js starter Source: https://docs.externa.qiick.io/docs/headless-starter Installs dependencies and starts the development server for the Next.js starter. The app will be available at http://localhost:3002. ```bash npm install npm run dev ``` -------------------------------- ### Contributor clone and setup Source: https://docs.externa.qiick.io/docs/packagist Clone the repository and run composer setup or the guided installer. Use this when opening PRs, running tests against develop, or customizing before upstreaming. ```bash git clone https://github.com/qiick-io/externa-core.git cd externa-core composer setup # or: php artisan externa:install for a guided first run ``` -------------------------------- ### Copy the example environment file Source: https://docs.externa.qiick.io/docs/quick-start Copies the .env.example file to .env as the starting point for environment configuration. ```bash cp .env.example .env ``` -------------------------------- ### Deploy with managed DB/Redis using Compose overlay Source: https://docs.externa.qiick.io/docs/deployment Copy the managed environment example, set required variables (APP_KEY, DB_HOST, REDIS_HOST, secrets, TRUSTED_PROXIES, REVERB_*), then start only app, horizon, reverb, scheduler, and pulse. Bundled pgsql/redis services are behind profiles and do not start. ```bash cp .env.docker.prod.managed.example .env # Set APP_KEY, DB_HOST, REDIS_HOST, secrets, TRUSTED_PROXIES, browser-facing REVERB_* docker compose -f compose.prod.yaml -f compose.prod.managed.yaml up --build -d ``` -------------------------------- ### Run Composer setup script Source: https://docs.externa.qiick.io/docs/installation Runs the non-interactive setup script defined in composer.json. This is used for CI or scripted environments. It runs composer install, copies .env.example to .env if missing, generates an app key, runs migrations, installs npm dependencies, and builds assets. ```bash composer setup ``` -------------------------------- ### Build from source for production Source: https://docs.externa.qiick.io/docs/deploy-with-docker Setup commands to copy environment file and start production containers with build. Requires setting APP_KEY, secrets, APP_URL, TRUSTED_PROXIES, and browser-facing REVERB_* variables. ```bash cp .env.docker.prod.example .env # APP_KEY, secrets, APP_URL, TRUSTED_PROXIES, browser-facing REVERB_* docker compose -f compose.prod.yaml up --build -d ``` -------------------------------- ### Review environment defaults Source: https://docs.externa.qiick.io/docs/installation Example .env configuration with SQLite database, database session driver, database queue, and database cache. This is the recommended default setup. ```env APP_URL=http://localhost DB_CONNECTION=sqlite SESSION_DRIVER=database QUEUE_CONNECTION=database CACHE_STORE=database ``` -------------------------------- ### Bring up production stack with docker compose Source: https://docs.externa.qiick.io/docs/deployment Copies the production environment example and starts the stack. Requires setting APP_KEY, strong DB_PASSWORD/REVERB_*, real mail, and TRUSTED_PROXIES. Recommended FILES_DISK=s3 with AWS_* variables. ```bash cp .env.docker.prod.example .env # Set APP_KEY, strong DB_PASSWORD / REVERB_*, real mail, TRUSTED_PROXIES # Recommended: FILES_DISK=s3 + AWS_* docker compose -f compose.prod.yaml up --build -d ``` -------------------------------- ### Install externa-core with Composer (Operators) Source: https://docs.externa.qiick.io/docs/quick-start Preferred method for operators. Creates a new project, enters the directory, switches to Node 24, and runs the installer. The installer does not migrate or assume SQLite; the next step is always the installer. ```bash composer create-project qiick/externa-core externa-core cd externa-core nvm use # Node 24 php artisan externa:install ``` -------------------------------- ### Create project with Composer Source: https://docs.externa.qiick.io/docs/installation Creates a new Externa project using Composer, changes into the project directory, sets the Node version, and runs the interactive installer. This is the recommended way to get the code. ```bash composer create-project qiick/externa-core my-externa cd my-externa nvm use php artisan externa:install ``` -------------------------------- ### Run Passkeys Migration Source: https://docs.externa.qiick.io/docs/passkeys Run the database migration to create the passkeys table. This is required for existing environments after pulling the passkeys work; fresh installs that run composer setup or full migrate get it automatically. ```bash php artisan migrate ``` -------------------------------- ### Happy path: composer create-project qiick/externa-core Source: https://docs.externa.qiick.io/docs/packagist Run these commands to install externa-core. The first command installs dependencies and runs post-install scripts; the second changes into the project directory; the third uses nvm to select Node 24 as pinned in .nvmrc; the fourth runs the interactive installer. ```bash composer create-project qiick/externa-core my-externa cd my-externa nvm use # Node 24 pinned in .nvmrc php artisan externa:install ``` -------------------------------- ### Start MinIO profile Source: https://docs.externa.qiick.io/docs/installation Starts the MinIO (S3) profile with Docker Compose. After starting, set FILES_DISK=s3, AWS_ENDPOINT=http://minio:9000, AWS_USE_PATH_STYLE_ENDPOINT=true, and matching keys. The minio-init service creates the bucket. ```bash docker compose --profile minio up --build ``` -------------------------------- ### Start MariaDB profile Source: https://docs.externa.qiick.io/docs/installation Starts the MariaDB profile, which exposes the host on port 3307 like Herd. Use this command to run MariaDB instead of Postgres. ```bash docker compose --profile mariadb -f compose.yaml -f compose.mariadb.yaml up --build ``` -------------------------------- ### Run interactive installer Source: https://docs.externa.qiick.io/docs/installation Runs the interactive installer for Externa. This is preferred after create-project or on a fresh clone. It prompts for configuration and runs key generation, migrations, storage linking, and npm build. ```bash php artisan externa:install ``` -------------------------------- ### Start Reverb standalone with php84 artisan reverb:start Source: https://docs.externa.qiick.io/docs/reverb-and-echo Run Reverb without the Herd service. Use your own REVERB_APP_* values on both the app and the Reverb process. composer run dev:full starts reverb:start for that path. ```bash php84 artisan reverb:start ``` -------------------------------- ### Meilisearch environment variables example Source: https://docs.externa.qiick.io/docs/environment-variables Example .env block for optional Meilisearch site search. Set MEILISEARCH_ENABLED=true to enable, and provide MEILISEARCH_HOST and MEILISEARCH_API_KEY for indexing. ```env MEILISEARCH_ENABLED=false MEILISEARCH_HOST= MEILISEARCH_API_KEY= MEILISEARCH_INDEX=externa MEILISEARCH_INDEXABLE_STATUSES=published ``` -------------------------------- ### Docker quick deploy: pull and start with pinned image Source: https://docs.externa.qiick.io/docs/upgrade Pulls and starts the externa-core image from GHCR using a pinned version tag. Replace the tag with the release you want. Requires named volumes to be kept. ```bash EXTERNA_IMAGE=ghcr.io/qiick-io/externa-core:1.0.0 \ docker compose -f compose.quick.yaml pull EXTERNA_IMAGE=ghcr.io/qiick-io/externa-core:1.0.0 \ docker compose -f compose.quick.yaml up -d ``` -------------------------------- ### Install, migrate, seed commands Source: https://docs.externa.qiick.io/docs/quick-start Run these commands to install dependencies, generate the app key, run migrations and seeders, link storage, and generate Wayfinder routes. The npm commands are for frontend dependencies and building assets. ```bash composer install php artisan key:generate php artisan migrate --seed php artisan storage:link php artisan wayfinder:generate --with-form --no-interaction npm ci # or: npm install npm run build # or skip and use `npm run dev` / Vite HMR below ``` -------------------------------- ### Maintainer smoke test Source: https://docs.externa.qiick.io/docs/packagist Clears the composer cache, creates a project from the ^1.0 tag, and runs the installer. Expect the output 'Next step: php artisan externa:install' with no migrate hard-fail. ```bash composer clear-cache composer create-project qiick/externa-core:^1.0 /tmp/externa-smoke --no-interaction cd /tmp/externa-smoke # Must print Next step: php artisan externa:install — no migrate hard-fail php artisan externa:install ``` -------------------------------- ### Start Meilisearch with Docker Compose Source: https://docs.externa.qiick.io/docs/meilisearch Starts the Meilisearch service using the meilisearch profile. The service listens on host :7700. Inside the Compose network, set MEILISEARCH_HOST to http://meilisearch:7700 and MEILISEARCH_API_KEY to masterKey. ```bash docker compose --profile meilisearch up --build ``` -------------------------------- ### Browser vs Bruno / API key fetch examples Source: https://docs.externa.qiick.io/docs/public-cms-api-types Two fetch examples showing browser requests (Origin sent automatically) and server/Bruno/curl requests (no Origin, so API key required when allowlist is on). The second example uses the EXTERNA_API_KEY environment variable. ```ts // Browser (Origin sent automatically by the browser) const res = await fetch(`${baseUrl}/api/v1/collections`, { credentials: 'omit', }) ``` ```ts // Server / Bruno / curl — no Origin → send API key when allowlist is on const res = await fetch(`${baseUrl}/api/v1/collections`, { headers: { Authorization: `Bearer ${process.env.EXTERNA_API_KEY}` }, }) ``` -------------------------------- ### Quick deploy: pull GHCR image and start with docker compose Source: https://docs.externa.qiick.io/docs/deploy-with-docker Copy the .env sample, generate a strong APP_KEY, and start the stack with docker compose. Required environment variables: APP_KEY, DB_PASSWORD, APP_URL. First boot seeds roles and super admin if RUN_SEED is true. The app is available at http://localhost:8080 (host APP_PORT, default 8080→80). ```bash # From an externa-core checkout (Compose + env sample live in the repo) cp .env.docker.quick.example .env # Required: APP_KEY, strong DB_PASSWORD, APP_URL php -r "copy('.env', '.env.bak'); file_put_contents('.env', preg_replace('/^APP_KEY=.*/m', 'APP_KEY=base64:'.base64_encode(random_bytes(32)), file_get_contents('.env')));" # First boot only — create roles + super admin (then set RUN_SEED=false) # RUN_SEED=true # INITIAL_SUPER_ADMIN_EMAIL=you@example.com # INITIAL_SUPER_ADMIN_PASSWORD='…strong…' docker compose -f compose.quick.yaml up -d ``` -------------------------------- ### Start the development stack Source: https://docs.externa.qiick.io/docs/installation Runs composer run dev which uses concurrently to start the server, queue listener, logs, and Vite. Open the URL shown by artisan serve; unauthenticated visits to / redirect to login, authenticated users go to the dashboard. ```bash composer run dev ``` -------------------------------- ### Start MySQL 8 profile Source: https://docs.externa.qiick.io/docs/installation Starts the MySQL 8 profile, which stops the default Postgres via overlay and puts pgsql behind a non-default profile. Use this command to run MySQL 8 instead of Postgres. ```bash docker compose --profile mysql -f compose.yaml -f compose.mysql.yaml up --build ``` -------------------------------- ### Start Horizon with PHP 8.4 (php84 artisan horizon) Source: https://docs.externa.qiick.io/docs/horizon Starts Laravel Horizon. Prefer PHP 8.4 (Herd). With Herd Redis and Herd Reverb already up, pair with pulse:work. For standalone all-in-one, use composer run dev:full. ```bash # Prefer PHP 8.4 (Herd) php84 artisan horizon ``` -------------------------------- ### Build and migrate for deployment Source: https://docs.externa.qiick.io/docs/deployment Standard Laravel + Vite build steps: install dependencies, build assets, and run migrations. ```bash composer install --no-dev --optimize-autoloader npm ci npm run build php artisan migrate --force ``` -------------------------------- ### Git export environment variables example Source: https://docs.externa.qiick.io/docs/environment-variables Example .env configuration for Git export, showing all variables with their default values. Set GIT_EXPORT_ENABLED to true to enable the feature. ```env GIT_EXPORT_ENABLED=false GIT_EXPORT_REMOTE_URL= GIT_EXPORT_BRANCH=main GIT_EXPORT_SSH_KEY_PATH= GIT_EXPORT_FORMAT=json GIT_EXPORT_DRY_RUN=false GIT_EXPORT_COLLECTION_SLUGS=* ``` -------------------------------- ### Start queue worker with php artisan queue:listen Source: https://docs.externa.qiick.io/docs/installation Run this command to start a queue worker when QUEUE_CONNECTION=database. Required for background jobs like PrepareFilesZipJob, DuplicateFilesJob, and ImportCollectionJob. The composer run dev command already includes queue:listen. ```bash php artisan queue:listen --tries=1 --timeout=0 ``` -------------------------------- ### GET /api/v1/collections/{slug}/items?include=files,author,categories Source: https://docs.externa.qiick.io/docs/public-cms-api Example of using the `include` parameter on a list endpoint to expand files, author, and categories. The response is lean by default; without `include=files`, file fields remain as stored IDs. ```http GET /api/v1/collections/{slug}/items?include=files,author,categories GET /api/v1/collections/{slug}/items/{id}?include=files ``` -------------------------------- ### Run full stack with Horizon, Pulse, and Vite Source: https://docs.externa.qiick.io/docs/quick-start Starts Horizon, Pulse worker, and Vite. Matches the .env with Redis and Herd Reverb. Do not run php artisan reverb:start if Herd Pro already binds :8080. ```bash php artisan horizon php artisan pulse:work npm run dev ``` -------------------------------- ### Upgrade via Git tag (cloned externa-core) Source: https://docs.externa.qiick.io/docs/upgrade Fetch tags and checkout the target release tag, then install dependencies. ```bash cd /path/to/externa-core git fetch --tags origin git checkout v1.0.0 # example — use the target release tag composer install --no-dev --optimize-autoloader ``` -------------------------------- ### Allowed origins list example Source: https://docs.externa.qiick.io/docs/public-cms-api-types Example of allowed origins entered in the Public API → Allowed origins field. Each origin must be http/https with host and optional non-default port; no path, query, fragment, or credentials. ```text https://www.example.com https://app.example.com http://localhost:3000 ``` -------------------------------- ### Clone and set up the Next.js starter Source: https://docs.externa.qiick.io/docs/headless-starter Clones the externa-next-starter repo, enters the directory, and copies the .env.example to .env.local. Run these commands in a terminal. ```bash git clone https://github.com/qiick-io/externa-next-starter.git cd externa-next-starter cp .env.example .env.local ``` -------------------------------- ### Mail environment variables example (.env) Source: https://docs.externa.qiick.io/docs/environment-variables Example .env configuration for mail settings. The default mailer is 'log', meaning messages go to the log instead of SMTP. The MAIL_FROM_NAME default uses the APP_NAME variable. ```env MAIL_MAILER=log MAIL_SCHEME=null MAIL_HOST=127.0.0.1 MAIL_PORT=2525 MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_FROM_ADDRESS="hello@example.com" MAIL_FROM_NAME="${APP_NAME}" ``` -------------------------------- ### Query Meilisearch from a headless site (server-only) Source: https://docs.externa.qiick.io/docs/meilisearch Server-only example in TypeScript to search Meilisearch directly. Use a search-only API key (MEILISEARCH_SEARCH_KEY) and do not expose the master key in the browser. The example searches for 'hello' filtered by collection_slug = posts. ```ts // server-only example const res = await fetch( `${process.env.MEILISEARCH_HOST}/indexes/externa/search`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.MEILISEARCH_SEARCH_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ q: 'hello', filter: 'collection_slug = posts', }), }, ) ``` -------------------------------- ### Start Horizon and Pulse for full Herd stack Source: https://docs.externa.qiick.io/docs/minimal-vs-full-stack Run these commands to start Horizon and Pulse workers for the full local stack with Herd. Horizon is required for Redis queues and Health Horizon cards; pulse:work is required for Pulse aggregation. ```bash php84 artisan horizon php84 artisan pulse:work ``` -------------------------------- ### GET /up Source: https://docs.externa.qiick.io/docs/operations Laravel framework liveness probe. Returns a simple response indicating the application is up. ```APIDOC ## GET /up ### Description Laravel framework liveness probe. ### Method GET ### Endpoint /up ### Response #### Success Response (200) No specific response body documented. ``` -------------------------------- ### GET /settings/project Source: https://docs.externa.qiick.io/docs/admin-api Retrieves the current project settings. Requires the 'can-manage-project-settings' permission. ```APIDOC ## GET /settings/project ### Description Retrieves the current project settings. ### Method GET ### Endpoint /settings/project ### Response #### Success Response (200) Returns the project settings. ``` -------------------------------- ### Get item response JSON Source: https://docs.externa.qiick.io/docs/public-cms-api Example JSON response for a get item request. Contains the item object with id, collection_id, data, and timestamps. ```json { "data": { "id": 1, "collection_id": 3, "data": { "title": "Hello", "status": "published" }, "created_at": "2026-07-20T12:00:00+00:00", "updated_at": "2026-07-20T12:00:00+00:00" } } ``` -------------------------------- ### Clone and set up the Nuxt starter Source: https://docs.externa.qiick.io/docs/headless-starter Clones the externa-nuxt-starter repo, enters the directory, and copies the .env.example to .env. Run these commands in a terminal. ```bash git clone https://github.com/qiick-io/externa-nuxt-starter.git cd externa-nuxt-starter cp .env.example .env ``` -------------------------------- ### Get collection response Source: https://docs.externa.qiick.io/docs/public-cms-api Example JSON response for a single collection, including field schema summary. ```json { "data": { "id": 1, "name": "Posts", "slug": "posts", "is_singleton": false, "fields": [ { "id": 10, "name": "title", "type": "text", "settings": {} }, { "id": 11, "name": "status", "type": "select", "settings": {} } ] } } ``` -------------------------------- ### GET /settings/appearance Source: https://docs.externa.qiick.io/docs/admin-api Retrieves the current appearance settings. Requires the 'can-manage-project-settings' permission. ```APIDOC ## GET /settings/appearance ### Description Retrieves the current appearance settings. ### Method GET ### Endpoint /settings/appearance ### Response #### Success Response (200) Returns the appearance settings. ``` -------------------------------- ### GET /ai/import-jobs/{jobId} Source: https://docs.externa.qiick.io/docs/ai-api Polls the status of an async collection import job started from AI tools. Requires the 'can-create-collections' permission. The jobId must be a UUID. ```APIDOC ## GET /ai/import-jobs/{jobId} ### Description Used to poll async collection import jobs started from AI tools. ### Method GET ### Endpoint /ai/import-jobs/{jobId} ### Parameters #### Path Parameters - **jobId** (string) - Required - Must be a UUID. ### Response #### Success Response (200) Import job status. ``` -------------------------------- ### Upgrade via upstream merge (create-project with own remote) Source: https://docs.externa.qiick.io/docs/upgrade Add Externa as upstream, fetch tags, merge the release tag, and install dependencies. ```bash cd /path/to/my-externa git remote add upstream https://github.com/qiick-io/externa-core.git # once git fetch --tags upstream git merge v1.0.0 # example — resolve conflicts if you customized app code composer install --no-dev --optimize-autoloader ``` -------------------------------- ### Compose app healthcheck Source: https://docs.externa.qiick.io/docs/installation Healthcheck configuration for the app service in Docker Compose. It checks the /health/ready endpoint, with a long start period to accommodate cold vendor installs. ```yaml healthcheck: test: ['CMD-SHELL', 'curl -fsS http://127.0.0.1/health/ready || exit 1'] interval: 10s timeout: 5s retries: 12 start_period: 300s # cold vendor install can be long ``` -------------------------------- ### GET /files/{folder?} Source: https://docs.externa.qiick.io/docs/file-manager Browse files in a folder. Returns an Inertia page for the file manager UI. ```APIDOC ## GET /files/{folder?} ### Description Browse files in a folder. Returns an Inertia page for the file manager UI. ### Method GET ### Endpoint /files/{folder?} ### Parameters #### Path Parameters - **folder** (string) - Optional - The folder path to browse. ### Response #### Success Response (200) - **Inertia page** - The file manager UI page. ``` -------------------------------- ### GET /health/live Source: https://docs.externa.qiick.io/docs/operations Process up probe. Returns JSON with status 'ok' when the process is running. ```APIDOC ## GET /health/live ### Description Process up probe. Returns JSON with status 'ok' when the process is running. ### Method GET ### Endpoint /health/live ### Response #### Success Response (200) - **status** (string) - Always "ok" when the process is up. #### Response Example { "status": "ok" } ``` -------------------------------- ### Sample .env configuration Source: https://docs.externa.qiick.io/docs/configuration Example environment variables for the application, showing defaults for APP_NAME, APP_ENV, APP_DEBUG, APP_URL, and locale settings. APP_DEBUG is true in .env.example but should be disabled in production. ```env APP_NAME=Laravel APP_ENV=local APP_DEBUG=true APP_URL=http://localhost APP_LOCALE=en APP_FALLBACK_LOCALE=en APP_FAKER_LOCALE=en_US ``` -------------------------------- ### GET /settings/roles/create Source: https://docs.externa.qiick.io/docs/admin-api Returns the form page for creating a new role. Requires the 'can-create-roles' permission. ```APIDOC ## GET /settings/roles/create ### Description Returns the form page for creating a new role. ### Method GET ### Endpoint /settings/roles/create ### Parameters #### Query Parameters - None documented. ### Request Example None documented. ### Response #### Success Response (200) - No response schema documented. #### Response Example None documented. ``` -------------------------------- ### OpenAPI import examples Source: https://docs.externa.qiick.io/docs/public-cms-api-types Use these curl commands to download the OpenAPI specification for code generation. The first fetches from your Externa Core instance (preferred), the second from the docs site. ```bash # From your Externa Core instance (preferred for codegen against that install) curl -fsSL https://YOUR_EXTERNA_ORIGIN/api/v1/openapi.json -o externa-public-cms.openapi.json ``` ```bash # From this docs site (YAML) curl -fsSL https://YOUR_DOCS_HOST/client-types/openapi.yaml -o externa-public-cms.openapi.yaml ``` -------------------------------- ### GET /files/uploads/status Source: https://docs.externa.qiick.io/docs/file-manager Get the status of a chunked upload session. ```APIDOC ## GET /files/uploads/status ### Description Get the status of a chunked upload session. ### Method GET ### Endpoint /files/uploads/status ### Query Parameters - **upload_id** (string) - Required - The upload session ID. ### Response #### Success Response (200) - **status** (string) - The status of the upload (e.g., pending, uploading, completed). ``` -------------------------------- ### GET /ai Source: https://docs.externa.qiick.io/docs/ai-api Returns the Inertia AI page shell. This is the main entry point for the AI interface. ```APIDOC ## GET /ai ### Description Returns the Inertia AI page shell. ### Method GET ### Endpoint /ai ### Response #### Success Response (200) Inertia page response. ``` -------------------------------- ### GET /files/{file}/where-used Source: https://docs.externa.qiick.io/docs/file-manager Get collection item references that use this file. ```APIDOC ## GET /files/{file}/where-used ### Description Get collection item references that use this file. ### Method GET ### Endpoint /files/{file}/where-used ### Parameters #### Path Parameters - **file** (integer) - Required - The ID of the file. ### Response #### Success Response (200) - **references** (array) - List of references, each containing item editor link and field name. ``` -------------------------------- ### Preview assisted sync with --dry-run Source: https://docs.externa.qiick.io/docs/upgrade Shows the command to preview the sync without merging or migrating. Use this to see what files would change before applying. ```bash php artisan externa:upgrade --sync-upstream=v1.0.0 --dry-run ``` -------------------------------- ### GET /ai/status Source: https://docs.externa.qiick.io/docs/ai-api Returns provider and readiness information as JSON. Useful for checking if the AI service is available. ```APIDOC ## GET /ai/status ### Description Returns provider / readiness JSON. ### Method GET ### Endpoint /ai/status ### Response #### Success Response (200) JSON object with provider and readiness information. ``` -------------------------------- ### Pin a release with EXTERNA_IMAGE Source: https://docs.externa.qiick.io/docs/deploy-with-docker Override the image tag to a specific release version (e.g., 1.0.0) and start the stack. Useful for reproducible deployments. ```bash EXTERNA_IMAGE=ghcr.io/qiick-io/externa-core:1.0.0 \ docker compose -f compose.quick.yaml up -d ``` -------------------------------- ### Get collection response type Source: https://docs.externa.qiick.io/docs/public-cms-api-types TypeScript type for the response envelope of getting a single collection. ```ts type CollectionShowResponse = { data: CollectionResource } ``` -------------------------------- ### List files response JSON Source: https://docs.externa.qiick.io/docs/public-cms-api Example JSON response for the list files endpoint. Shows the structure of a file resource and pagination metadata. ```json { "data": [ { "id": 12, "parent_id": null, "type": "file", "access": "public", "filename": "hero.jpg", "title": "Hero", "description": null, "mime_type": "image/jpeg", "extension": "jpg", "filesize": 204800, "width": 1920, "height": 1080, "focal_point_x": 0.5, "focal_point_y": 0.5, "url": "http://externa-core.test/api/v1/files/12/content", "transforms": { "thumb": "http://externa-core.test/api/v1/files/12/transforms/thumb" }, "created_at": "2026-07-20T12:00:00+00:00", "updated_at": "2026-07-20T12:00:00+00:00" } ], "meta": { "current_page": 1, "last_page": 1, "per_page": 15, "total": 1 } } ``` -------------------------------- ### Advanced list filter query example Source: https://docs.externa.qiick.io/docs/public-cms-api Example of using the filter query parameter with the _eq operator to filter items by status. ```text ?filter[status][_eq]=published ``` -------------------------------- ### Next.js starter .env.local configuration Source: https://docs.externa.qiick.io/docs/headless-starter Environment variables for the Next.js starter. EXTERNA_API_URL is required; EXTERNA_API_KEY is optional (omit to use the public role); EXTERNA_COLLECTION is optional and auto-picks if empty. EXTERNA_API_KEY is read only in Server Components / server fetch, do not prefix with NEXT_PUBLIC_. ```env EXTERNA_API_URL=http://externa-core.test # optional — omit to use the public role EXTERNA_API_KEY= EXTERNA_COLLECTION=posts ``` -------------------------------- ### Get file content and transform with curl Source: https://docs.externa.qiick.io/docs/public-cms-api Streams the original file bytes or a transform. Requires 'read' permission. Same auth rules as Get file. ```bash curl -sS -OJ http://externa-core.test/api/v1/files/12/content \ -H "Authorization: Bearer ek_YOUR_SECRET" curl -sS -OJ http://externa-core.test/api/v1/files/12/transforms/thumb \ -H "Authorization: Bearer ek_YOUR_SECRET" ``` -------------------------------- ### Create item response JSON Source: https://docs.externa.qiick.io/docs/public-cms-api Example JSON response for a create item request. Returns 201 and the created item object. ```json { "data": { "id": 42, "collection_id": 3, "data": { "title": "New post", "status": "draft" }, "created_at": "2026-07-20T12:00:00+00:00", "updated_at": "2026-07-20T12:00:00+00:00" } } ``` -------------------------------- ### Environment variables for database, session, cache, and queue Source: https://docs.externa.qiick.io/docs/environment-variables Sample .env configuration showing SQLite database, database sessions, and Redis for queue and cache. Includes commented alternatives for minimal setup without Redis. ```env DB_CONNECTION=sqlite # DB_HOST=127.0.0.1 # DB_PORT=3306 # DB_DATABASE=laravel # DB_USERNAME=root # DB_PASSWORD= SESSION_DRIVER=database SESSION_LIFETIME=120 SESSION_ENCRYPT=false SESSION_PATH=/ SESSION_DOMAIN=null # Full stack defaults in .env.example — switch to database/log for minimal: BROADCAST_CONNECTION=reverb FILESYSTEM_DISK=local QUEUE_CONNECTION=redis CACHE_STORE=redis # CACHE_STORE=database # ok for light local without Redis cache ``` -------------------------------- ### Collection form layout JSON example Source: https://docs.externa.qiick.io/docs/field-types Example of form layout metadata on collections.form_layout, defining tabs and collapsible sections. Unplaced fields render in an 'Other' group. ```json { "version": 1, "tabs": [{ "id": "main", "label": { "en": "Main" } }], "sections": [ { "id": "details", "tab_id": "main", "label": { "en": "Details" }, "collapsible": true, "collapsed": false, "field_ids": [1, 2] } ] } ``` -------------------------------- ### Apply assisted sync with confirmation prompt Source: https://docs.externa.qiick.io/docs/upgrade Runs the sync with a confirmation prompt, then migrates, syncs permissions, and clears cache. ```bash php artisan externa:upgrade --sync-upstream=v1.0.0 ``` -------------------------------- ### Run minimal setup with composer run dev Source: https://docs.externa.qiick.io/docs/quick-start Runs the development server, queue listener, pail, and Vite. Requires QUEUE_CONNECTION=database and BROADCAST_CONNECTION=log in .env. Herd serves HTTP at APP_URL, so artisan serve is not needed. ```bash composer run dev # serve + queue:listen + pail + vite ``` -------------------------------- ### Field conditions JSON example Source: https://docs.externa.qiick.io/docs/field-types Example of a field conditions object with OR logic and two rules. When rules match, hidden, readonly, or required override base settings for that request. ```json { "logic": "or", "rules": [ { "field": "kind", "operator": "equals", "value": "custom" }, { "field": "status", "operator": "in", "value": "draft, review" } ], "hidden": false, "readonly": false, "required": true } ``` -------------------------------- ### Backup storage and .env files Source: https://docs.externa.qiick.io/docs/backup-restore Creates a tarball of storage/app and storage/logs, and copies .env to a dated backup. The .env copy should be kept offline or encrypted. ```bash # from project root tar -czf "backups/storage-$(date +%F).tar.gz" storage/app storage/logs cp .env "backups/env-$(date +%F).env" # keep offline / encrypted ``` -------------------------------- ### Local smoke: build image and run with quick Compose Source: https://docs.externa.qiick.io/docs/deploy-with-docker Build the production image locally and run the quick Compose stack without pulling from GHCR. Useful for local testing or offline environments. ```bash docker build --target production -t externa:prod . EXTERNA_IMAGE=externa:prod docker compose -f compose.quick.yaml up -d ``` -------------------------------- ### Sample JSON response for item with expanded relations Source: https://docs.externa.qiick.io/docs/public-cms-api Example response from the API showing an item with a cover file, author relation, and user_created/user_updated mini-users. Demonstrates the structure of expanded relations. ```json { "data": { "id": 1, "collection_id": 3, "data": { "title": "Hello", "cover": { "id": 12, "filename": "hero.jpg", "title": "Hero", "mime_type": "image/jpeg", "width": 1920, "height": 1080, "filesize": 204800, "url": "http://externa-core.test/api/v1/files/12/content", "transforms": { "thumb": "http://externa-core.test/api/v1/files/12/transforms/thumb" } }, "author": { "id": 7, "collection_id": 2, "data": { "name": "Ada" }, "created_at": "2026-07-20T12:00:00+00:00", "updated_at": "2026-07-20T12:00:00+00:00", "user_created_id": null, "user_updated_id": null, "user_created": null, "user_updated": null } }, "created_at": "2026-07-20T12:00:00+00:00", "updated_at": "2026-07-20T12:00:00+00:00", "user_created_id": 1, "user_updated_id": 1, "user_created": { "id": 1, "name": "Admin", "email": "admin@example.com" }, "user_updated": { "id": 1, "name": "Admin", "email": "admin@example.com" } } } ``` -------------------------------- ### collection_permissions.rules JSON example Source: https://docs.externa.qiick.io/docs/public-cms-api Example of the collection_permissions.rules JSON structure for field-level permissions and item filters. Fields map controls read/create/update access per field; item_filter uses AND logic with operators like equals and not_empty. ```json { "fields": { "title": { "read": true, "create": true, "update": true }, "status": { "read": true, "create": false, "update": false } }, "item_filter": { "logic": "and", "rules": [{ "field": "status", "operator": "equals", "value": "published" }] } } ``` -------------------------------- ### Caddy reverse proxy configuration Source: https://docs.externa.qiick.io/docs/reverse-proxy Caddyfile for externa.example.com with gzip encoding, WebSocket upgrade handling, and reverse proxy to app and reverb services. Adjust the /app/* path to match your Echo setup. ```caddyfile externa.example.com { encode gzip @websockets { header Connection *Upgrade* header Upgrade websocket } # Reverb WebSockets (path depends on your Echo setup — default Laravel Reverb) handle /app/* { reverse_proxy reverb:8080 } handle { reverse_proxy app:80 } } ``` -------------------------------- ### Nested blocks example Source: https://docs.externa.qiick.io/docs/field-types Complete example of a blocks field with nested blocks, including a section block that contains its own blocks field with rich_text and media types, plus related_modules (m2a) and related_articles (many_to_many) block types. ```json { "max_blocks_depth": 3, "block_types": [ { "key": "rich_text", "label": "Rich text", "fields": [ { "name": "title", "type": "string", "translatable": true, "settings": {} }, { "name": "body", "type": "wysiwyg", "translatable": true, "settings": {} } ] }, { "key": "section", "label": "Section", "fields": [ { "name": "heading", "type": "string", "translatable": true, "settings": {} }, { "name": "blocks", "type": "blocks", "translatable": false, "settings": { "block_types": [ { "key": "rich_text", "label": "Rich text", "fields": [ { "name": "body", "type": "wysiwyg", "translatable": true, "settings": {} } ] }, { "key": "media", "label": "Media", "fields": [{ "name": "image", "type": "image", "settings": {} }] } ] } } ] }, { "key": "related_modules", "label": "Related modules", "fields": [ { "name": "modules", "type": "m2a", "settings": { "allowed_collection_ids": [2] } } ] }, { "key": "related_articles", "label": "Related articles", "fields": [ { "name": "articles", "type": "many_to_many", "settings": { "related_collection_id": 1, "display_field": "title" } } ] } ] } ``` -------------------------------- ### Compose healthcheck for /health/ready Source: https://docs.externa.qiick.io/docs/deployment Example healthcheck configuration for local cold boot with a long start_period of 300s. Production Compose uses a shorter start_period (typically 60s). ```yaml healthcheck: test: ['CMD-SHELL', 'curl -fsS http://127.0.0.1/health/ready || exit 1'] interval: 10s timeout: 5s retries: 12 start_period: 300s ``` -------------------------------- ### Configure local provider settings via environment variables Source: https://docs.externa.qiick.io/docs/ai-configuration Configures the local provider (providers.local) with URL, API key, and default model. The URL defaults to http://127.0.0.1:1234/v1, API key is empty by default, and the model is set to openai/gpt-oss-20b in .env.example. ```env LOCAL_AI_URL=http://127.0.0.1:1234/v1 LOCAL_AI_API_KEY= LOCAL_AI_MODEL=openai/gpt-oss-20b ``` -------------------------------- ### GET /chat/options/items Source: https://docs.externa.qiick.io/docs/chat Returns items in a specified collection. ```APIDOC ## GET /chat/options/items ### Description Returns items in a specified collection. ### Method GET ### Endpoint /chat/options/items ### Parameters #### Query Parameters - **collection_id** (string) - Required - The UUID of the collection. ### Response #### Success Response (200) - Returns a list of items. #### Response Example [ { "id": "uuid", "name": "string" } ] ``` -------------------------------- ### Template prompt for AI-assisted upgrade Source: https://docs.externa.qiick.io/docs/upgrade Copy and fill vOLD/vNEW (example: v1.0.0 → v1.1.0). Paste context into your coding agent to resolve conflicts while preserving customizations. Keep .env and secrets out of commits; do not ask the agent to force-push or blind-commit without review. ```text I am upgrading Externa (Laravel app from qiick-io/externa-core) from vOLD to vNEW. Context to use (paste one or more): 1) GitHub compare: https://github.com/qiick-io/externa-core/compare/vOLD...vNEW 2) And/or CHANGELOG + release notes for vNEW 3) My conflicted / customized files (paste `git status` and the conflict hunks) Goals: - Resolve conflicts preserving my intentional customizations - Keep .env, storage/, and local secrets untouched — never commit them - Prefer upstream for framework/app defaults I did not customize - After a clean tree: composer install, npm ci && npm run build, then `php artisan externa:upgrade` (or migrate + permissions:sync + optimize:clear) Constraints: - Do not blind-commit; show the plan and diffs first - Do not rewrite git history or force-push - Call out breaking changes from the compare/CHANGELOG ``` -------------------------------- ### Externa environment variables copy-paste block Source: https://docs.externa.qiick.io/docs/environment-variables Use this block as a starting point for your .env file. It includes commented sections for files, AI (LM Studio/OpenAI-compatible local gateway), seeding, activity log, and public CMS API. Adjust values as needed; defaults apply if optional overrides are omitted. ```env # Files FILES_DUPLICATE_SYNC_MAX_BYTES=52428800 FILES_ZIP_TTL_MINUTES=60 FILES_ZIP_MAX_BYTES=104857600 # FILE_PUBLIC_URL_BASE= # AI (LM Studio / OpenAI-compatible local gateway) AI_DEFAULT_PROVIDER=local LOCAL_AI_URL=http://127.0.0.1:1234/v1 LOCAL_AI_API_KEY= LOCAL_AI_MODEL=openai/gpt-oss-20b AI_REMOTE_IMPORT_HOSTS= AI_WEBHOOK_TOKEN= AI_DAILY_PROMPT_LIMIT=0 AI_EMBEDDINGS_ENABLED=false AI_MCP_ENABLED=false # Seeding (optional overrides — config defaults apply if omitted) INITIAL_SUPER_ADMIN_EMAIL=superadmin@example.com INITIAL_SUPER_ADMIN_PASSWORD=password # Activity log ACTIVITYLOG_ENABLED=true ACTIVITYLOG_BUFFER_ENABLED=false # Public CMS API API_KEY_RATE_LIMIT=60 CORS_ALLOWED_ORIGINS=* ``` -------------------------------- ### Run optional backup script Source: https://docs.externa.qiick.io/docs/backup-restore Executes the repository helper script that dumps the database (when CLI tools exist) and tars storage/app into ./backups/ (gitignored). Review before cron. ```bash ./scripts/backup.sh ``` -------------------------------- ### Quick start: public read access with curl Source: https://docs.externa.qiick.io/docs/public-cms-api Two curl commands to fetch collections and items without authentication, demonstrating public read access after configuring the public role. ```bash curl -sS http://externa-core.test/api/v1/collections \ -H 'Accept: application/json' curl -sS http://externa-core.test/api/v1/collections/posts/items \ -H 'Accept: application/json' ``` -------------------------------- ### Build multi-arch production images with docker buildx bake Source: https://docs.externa.qiick.io/docs/deployment Builds production images for linux/amd64 and linux/arm64 using Buildx. The helper script creates the builder 'externa-multiarch' if needed. Optional push to a registry requires setting TAG and PUSH=1. ```bash # Bake both platforms (Buildx). Fails if either arch fails. docker buildx bake -f docker-bake.hcl production # Helper wrapper (creates builder `externa-multiarch` if needed): ./scripts/docker-buildx.sh production # Optional push to a registry (set TAG first): # TAG=ghcr.io/qiick-io/externa-core:1.0.0 PUSH=1 ./scripts/docker-buildx.sh production ``` -------------------------------- ### POST /chat/threads Source: https://docs.externa.qiick.io/docs/chat Starts a new item or direct thread. ```APIDOC ## POST /chat/threads ### Description Starts a new item or direct thread. ### Method POST ### Endpoint /chat/threads ### Parameters #### Request Body - **type** (string) - Required - The type of thread: `item` or `direct`. - **item_id** (string) - Optional - The UUID of the item (required for item threads). - **participant_ids** (array) - Optional - List of user UUIDs for direct threads. ### Request Example { "type": "direct", "participant_ids": ["uuid1", "uuid2"] } ### Response #### Success Response (201) - Returns the created thread object. #### Response Example { "id": "uuid", "type": "direct", "participants": ["uuid1", "uuid2"] } ``` -------------------------------- ### Shared post-deploy steps: migrate, permissions, build, cache clear Source: https://docs.externa.qiick.io/docs/upgrade Runs after new code is deployed. Includes migrations, permissions sync, npm install/build, cache clearing, and bringing the app back up. Commented lines show optional prune and production cache commands. ```bash php artisan migrate --force php artisan permissions:sync # Only if PermissionEnum removed names and you intend cleanup: # php artisan permissions:sync --prune npm ci npm run build php artisan optimize:clear # production hosts that cache config/routes: # php artisan config:cache && php artisan route:cache && php artisan view:cache php artisan up ``` -------------------------------- ### GET /chat/unread-count Source: https://docs.externa.qiick.io/docs/chat Returns the total unread count for the user. ```APIDOC ## GET /chat/unread-count ### Description Returns the total unread count for the user. ### Method GET ### Endpoint /chat/unread-count ### Response #### Success Response (200) - Returns the unread count. #### Response Example { "unread_count": 5 } ```