- Clone the repository
- Copy the .env.example file to .env
- In the .env file add your database credentials and set
BRAND_ORG_NAME. Seeconfig/branding.phpfor the full list of branding options including colours, logo, and images. - Create the local MySQL database if needed (e.g.
mysql -u root -e "CREATE DATABASE resources_site_template;") - Run
composer installto install PHP dependencies - Run
npm installto install JavaScript dependencies - Run
php artisan key:generateto set the application key - Run
php artisan migrate --seedto set up the database with tables and seed - Run
npm run devto set Vite running, which reloads assets on changes - If you're using Laravel Valet or Herd, go to
http://resources-site-template.testin your browser. Otherwise, runphp artisan serveand go to the provided URL.
If you've run the seeders, you can log in with test@example.com and password 'password'.
To seed example troves, collections, and tags for local development, run the example data seeder separately after the main seed:
php artisan db:seed --class="Database\Seeders\Example\ExampleDataSeeder"
The app uses AWS S3 for file storage. Set up an S3 bucket and add your credentials to .env — see .env.example for the required AWS_* variables. It's recommended to use S3 locally too so your setup matches production.
If you don't have S3 set up, you can use the local public disk for development by setting FILESYSTEM_DISK=local and MEDIA_DISK=public in your .env, then running php artisan storage:link. Note that files won't persist in the same way as S3.
Search is powered by Meilisearch. The SCOUT_DRIVER config defaults to null (search disabled, no external service required), so search only works once you explicitly set SCOUT_DRIVER=meilisearch in your .env and have Meilisearch running. To keep search disabled locally, either leave SCOUT_DRIVER unset or set it to null.
To run Meilisearch locally:
- Install Meilisearch - instructions here.
- Run
meilisearch --master-key="aSampleMasterKey"- keep this running in a separate terminal window. - In your
.env, uncomment/setSCOUT_DRIVER=meilisearchand checkMEILISEARCH_HOST/MEILISEARCH_KEYmatch the instance above (MEILISEARCH_KEYmust match the--master-keyyou started Meilisearch with). SCOUT_QUEUE=trueby default, so index updates are queued - make sure a queue worker is running (php artisan queue:workorphp artisan queue:listen), sinceQUEUE_CONNECTION=database.- Push the index settings (filterable/sortable/searchable attributes, defined per-model in
config/scout.php) to Meilisearch, then import existing records:
php artisan scout:sync-index-settings
php artisan scout:import "App\Models\Trove"
php artisan scout:import "App\Models\Collection"
Re-run both sync-index-settings and the import commands whenever you change a model's toSearchableArray() or the index-settings block in config/scout.php.
In production: Meilisearch is required for the full ranked/faceted browse experience — without it (SCOUT_DRIVER unset/null, or the engine unreachable) BrowseAll degrades to an unranked, date-ordered database listing with a "search unavailable" notice; filters still work, but there's no relevance ranking, typo tolerance or facet counts. On first deploy, and again after any schema/index change, run scout:sync-index-settings then scout:import for both App\Models\Trove and App\Models\Collection. Set SCOUT_QUEUE=true (queues index updates instead of running them synchronously in the request) and keep a queue worker running (php artisan queue:work). The Laravel scheduler must also be running (cron calling php artisan schedule:run every minute, or schedule:work under Supervisor) — it drives a nightly scout:import reconciliation for both models (app/Console/Kernel.php) that repairs any index drift left by a request where the engine was briefly unreachable.