Set up a new Laravel project
This guide shows you how to initialise a new Laravel project from scratch, adhering to our company standards for Git workflows, linting, formatting, and CI setup.
Step 1: Create the Laravel Project
Section titled “Step 1: Create the Laravel Project”Follow the official Laravel instructions for setting up a Laravel project with a starter kit. Ensure you’re on the latest version of the starter kit (remove and re-install if necessary).
Company preferences:
- React frontend
- Built-in auth
- No teams support (unless wanted)
- Pest for testing
- Laravel Boost (why not)
Step 2: Create the GitHub Repository
Section titled “Step 2: Create the GitHub Repository”- Go to GitHub and create a new repository under our organisation.
- Ensure the repo is Private and empty. No need to add a license.
- Push the starter kit code to the empty repo.
cd new-projectgit add -Agit commit -m 'initial commit'git remote add origin git@github.com:novatura/new-project.gitgit push -u origin mainStep 3: Set up Git workflow
Section titled “Step 3: Set up Git workflow”Repository Rulesets
Section titled “Repository Rulesets”Add the repository as a target for our GitHub org’s branch rulesets in order to apply standard branch protection rules and other security features such as requiring signed commits. Find them here.
Git Workflow
Section titled “Git Workflow”For a waterfall project (pre-production), create the following branches:
mainstagingdevbug-fixesd1
The worflow consists of, each deliverable gets a dX branch. Each new deliverable branch is created from it’s predecessor, so d2 would branch from d1.
For other projects (agile, takeover), only the following:
mainstagingdevbug-fixes
Once a project is in production, this is the workflow:
- Use feature branches (using a Linear issue as the branch name, i.e.
DEL-123-initialise-project) to build features. - Open feature branches PRs into
dev. Keep PRs short and targeted. This way, AI and human reviewers can actually review. - At the end of sprint cadence / deliverable, open a PR from
devintostaging. Use AI code review to catch any final bugs. Diffs may be too large to review manually at this point, so it’s important that feature branches were used properly. - Once testing has finished on staging, and all CI checks have passed, open a PR from
stagingintomain, which will require approval. - For bug fixes, use the
bug-fixesbranch and open PRs intomainfor AI and human code review. Keep this branch up to date withmain.
Step 4: Linting and formatting
Section titled “Step 4: Linting and formatting”Frontend (Biome)
Section titled “Frontend (Biome)”Configure Biome for the project.
bun add -D -E @biomejs/biomebunx --bun @biomejs/biome initBackend (Pint, PHPStan)
Section titled “Backend (Pint, PHPStan)”Pint and PHPStan should be installed from the Laravel starter kit.
composer types:check && types:check
Continuous Integration
Section titled “Continuous Integration”Add these workflows to .github/workflows that runs on dev, staging and main.
name: Frontend Code Quality
on: push: branches: - main - staging - dev
jobs: quality: runs-on: ubuntu-latest
permissions: contents: read steps: - name: Checkout uses: actions/checkout@v6 with: persist-credentials: false - name: Setup Biome uses: biomejs/setup-biome@v2 with: version: latest - name: Run Biome run: biome ci .name: Backend Code Quality
on: push: branches: - main - staging - dev
jobs: quality: runs-on: ubuntu-latest strategy: matrix: php-version: ['8.5']
permissions: contents: read steps: - name: Checkout uses: actions/checkout@v6 with: persist-credentials: false - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-version }} tools: composer:v2 coverage: xdebug version: latest - name: Install Composer Dependencies run: composer install --no-interaction --prefer-dist --optimize-autoloader - name: Run Pint run: pintTODO: Verify these work and maybe configure automated pushing of safe fixes?
Step 5: Testing
Section titled “Step 5: Testing”Ensure you have Pest set up and a version controlled .env.ci file exists. Do not keep real secrets or credentials in this file.
Add a testing workflow to .github/workflows that runs on staging and main. The below is just a guideline, as testing setup may vary project to project.
name: Run Tests
on: push: branches: - main pull_request: branches: - staging - main workflow_dispatch:
jobs: ci: runs-on: ubuntu-latest strategy: matrix: php-version: ['8.5']
services: mysql: image: mysql:8.0 ports: - 3306:3306 env: MYSQL_ROOT_PASSWORD: password # Match phpunit.xml DB_DATABASE so migrations run against this schema MYSQL_DATABASE: testing # Without this, only root exists; local/Sail uses sail and tests inherit that username MYSQL_USER: sail MYSQL_PASSWORD: password options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 redis: image: redis:alpine ports: - 6379:6379 options: >- --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
steps: - name: Checkout code uses: actions/checkout@v6
- name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-version }} tools: composer:v2 coverage: xdebug
- name: Setup Bun uses: oven-sh/setup-bun@v2
- name: Install Bun Dependencies run: bun install --frozen-lockfile
- name: Install Composer Dependencies run: composer install --no-interaction --prefer-dist --optimize-autoloader
- name: Copy Environment File run: cp .env.example .env
- name: Generate Application Key run: php artisan key:generate
- name: Build Assets run: bun run build
- name: Setup network hosts run: | echo "127.0.0.1 localhost" | sudo tee -a /etc/hosts echo "127.0.0.1 mysql" | sudo tee -a /etc/hosts echo "127.0.0.1 redis" | sudo tee -a /etc/hosts - name: Tests env: DB_CONNECTION: mysql DB_HOST: mysql DB_PORT: 3306 DB_DATABASE: testing DB_USERNAME: sail DB_PASSWORD: password REDIS_HOST: redis run: ./vendor/bin/pestDependabot
Section titled “Dependabot”GitHub Copilot Review
Section titled “GitHub Copilot Review”Add the following instructions for Copilot:
# React/Laravel Code Review Guidelines
Use the following guidelines for code review. The main goal is clean and maintainable code. For every PR you review, generate a short changelog using the following example template.
<format># TitleBrief summary of main features.
## Changelog:1. Feature: Added new integration for ___2. Refactor: Updated ___ page3. Fix: Broken layout on ___ page4. Fix: Bug where ___</format>
## Code StyleIgnore formatting issues and comments. These are handled by CI formatters.
## Query Optimisation- Ensure that batch queries are employed where sensible, rather than performing queries inside of loops.- If the number of database queries can be reduced, suggest an appropriate refactor.
## Architecture- Ensure that single responsibility principle is respected.- Ensure separation of concerns is considered.
## Testing- Advocate for integration/feature tests where appropriate, with a small and well curated set of end to end tests for core features is a good balance.- Where services classes and repositories are used, advise on testability by looking at whether their dependencies can be mocked through appropriate techniques such as dependency injection.- Ensure no tests are going to call third party APIs that might incur fees or take up lots of CI time.---applyTo: "**/*.php"---
# PHP / Laravel Code Review GuidelineThis file defines our PHP and Laravel conventions for code review.
## Architecture- Avoid tight coupling between systems. Use controllers to handle requests, repositories to handle data fetching.
## Tests- Ensure tests are deterministic.---applyTo: "**/*.tsx"---
# React Code Review GuidelineThis file defines our React conventions for code review.
## Components- Ensure useEffects are only used where necessary or sensible, to avoid unnecessary re-renders.- Make sure components are Instance-Proof- Make sure components are Concurrent-Proof- Make sure components are Portal-Proof- Avoid tight coupling between components, use React Context where appropriate to abstract logic away from UI to keep code clean.
## Robustness- Make sure all relevant feedback is accounted for, such as toast popups for when operations fail, loading UI or error messages in formsExtra Continuous Integration Steps
Section titled “Extra Continuous Integration Steps”Add this cron job that cleans up our artifact storage.
name: Cleanup Artifactson: workflow_dispatch: schedule: - cron: '0 0 * * *' # Daily
permissions: actions: write
jobs: cleanup: runs-on: ubuntu-latest steps: - name: Delete old artifacts uses: actions/github-script@v7 with: script: | const artifacts = await github.rest.actions.listArtifactsForRepo({ owner: context.repo.owner, repo: context.repo.repo, per_page: 100 });
for (const artifact of artifacts.data.artifacts) { console.log(`Deleting ${artifact.name} (${artifact.size_in_bytes} bytes)`); await github.rest.actions.deleteArtifact({ owner: context.repo.owner, repo: context.repo.repo, artifact_id: artifact.id }); }