Skip to main content

Development Setup & Workflow

Complete development environment setup and workflow guide for Lancaster Archery Academy.

Prerequisites

Required Software

  • PHP: 8.2 or higher
  • Composer: 2.x (latest stable)
  • Node.js: 20.x (check .nvmrc for exact version)
  • npm: 10.x (comes with Node.js)
  • Database: MySQL 8.0+ or MariaDB 10.3+
  • Git: For version control
  • Redis: Optional, for caching and queues in production
  • Laravel Herd: Modern Laravel development environment (macOS/Windows)
  • TablePlus or Sequel Pro: Database management
  • VS Code: With extensions:
    • PHP Intelephense
    • Laravel Extra Intellisense
    • Volar (Vue 3)
    • Tailwind CSS IntelliSense
  • Postman or Insomnia: API testing

Initial Setup

1. Clone Repository

cd Z:\Repos
git clone [email protected]:rhino-group/lancasterarcheryacademy.com.git
cd lancasterarcheryacademy.com

2. Install Dependencies

# Install PHP dependencies
composer install

# Install Node dependencies
npm install

3. Environment Configuration

# Copy environment file
cp .env.example .env

# Generate application key
php artisan key:generate

4. Configure Environment Variables

Edit .env:

APP_NAME="Lancaster Archery Academy"
APP_ENV=local
APP_DEBUG=true
APP_URL=http://lancasterarcheryacademy.test

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=lancasterarchery
DB_USERNAME=root
DB_PASSWORD=

# Authorize.Net (Sandbox)
AUTHNET_LOGIN_ID=your_sandbox_login
AUTHNET_TRANSACTION_KEY=your_sandbox_key
AUTHNET_CLIENT_KEY=your_public_client_key
AUTHNET_MODE=sandbox

# Smartwaiver (Test)
SMARTWAIVER_API_KEY=your_test_api_key
SMARTWAIVER_TEMPLATE_ID=your_test_template_id
SMARTWAIVER_WEBHOOK_SECRET=your_webhook_secret

# Mail (Development)
MAIL_MAILER=log
[email protected]
MAIL_FROM_NAME="${APP_NAME}"

# Session & Cache
SESSION_DRIVER=file
CACHE_DRIVER=file
QUEUE_CONNECTION=sync

5. Database Setup

Create Database:

# MySQL
mysql -u root -p
CREATE DATABASE lancasterarchery CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
exit;

Run Migrations:

php artisan migrate

Seed Database (optional, for test data):

php artisan db:seed

6. Build Frontend Assets

# Development build
npm run dev

# Or watch mode (rebuilds on file changes)
npm run watch
php artisan storage:link

Creates symlink from public/storage to storage/app/public

8. Configure Nova

License: Add Nova license key to .env

NOVA_LICENSE_KEY=your_license_key

Nova User:

php artisan nova:user

# Follow prompts to create admin user
# Email: [email protected]
# Password: password (change in production!)

9. Start Development Server

Option A: Laravel Herd (Recommended)

# Herd automatically serves the application
# Access at: http://lancasterarcheryacademy.test

Option B: Artisan Serve

php artisan serve
# Access at: http://localhost:8000

Option C: Valet (macOS)

valet link lancasterarchery
valet secure lancasterarchery # HTTPS
# Access at: https://lancasterarchery.test

10. Access Application

Public Site: http://lancasterarcheryacademy.test
Nova Admin: http://lancasterarcheryacademy.test/nova

Default Admin Credentials:

Email: [email protected]
Password: password

⚠️ Change immediately after first login!

Development Workflow

Running Development Services

Terminal 1 - Laravel:

php artisan serve

Terminal 2 - Vite/Mix (watch mode):

npm run watch
# Or for hot module replacement:
npm run hot

Terminal 3 - Queue Worker (if using queues):

php artisan queue:work

Terminal 4 - Log Viewer:

tail -f storage/logs/laravel.log

Database Management

Fresh Migration (drops all tables and recreates):

php artisan migrate:fresh

Fresh with Seeding:

php artisan migrate:fresh --seed

Rollback Last Migration:

php artisan migrate:rollback

Check Migration Status:

php artisan migrate:status

Run Specific Seeder:

php artisan db:seed --class=EventSeeder

Asset Compilation

Development Build (unminified, with source maps):

npm run dev

Watch Mode (rebuild on file changes):

npm run watch

Hot Module Replacement (instant updates):

npm run hot

Production Build (minified, optimized):

npm run production

Nova Development

Clear Nova Cache:

php artisan nova:clear

Publish Nova Assets:

php artisan nova:publish

Build Nova Components (after modifying custom components):

cd nova-components/EventTools
npm run dev # or npm run prod

Testing

Running Tests

Lancaster Archery uses PHPUnit for testing.

Run All Tests:

php artisan test

Run Specific Test File:

php artisan test tests/Feature/ReservationTest.php

Run Specific Test Method:

php artisan test --filter testUserCanCreateReservation

Run with Coverage (requires Xdebug):

php artisan test --coverage

Writing Tests

Feature Test Example (tests/Feature/ReservationTest.php):

<?php

namespace Tests\Feature;

use App\Models\User;
use App\Models\Account;
use App\Models\Event;
use App\Models\Session;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class ReservationTest extends TestCase
{
use RefreshDatabase;

/** @test */
public function user_can_create_reservation_for_available_session()
{
$user = User::factory()->create();
$account = Account::factory()->create(['user_id' => $user->id]);
$session = Session::factory()->create(['seat_quantity' => 10]);

$this->actingAs($user);

$response = $this->post(route('reservations.store'), [
'account_id' => $account->id,
'session_id' => $session->id,
'seats' => 1,
]);

$response->assertRedirect(route('cart.index'));
$this->assertDatabaseHas('reservations', [
'account_id' => $account->id,
'session_id' => $session->id,
'seats' => 1,
]);
}

/** @test */
public function user_cannot_book_full_session()
{
$user = User::factory()->create();
$account = Account::factory()->create(['user_id' => $user->id]);
$session = Session::factory()->create(['seat_quantity' => 1]);

// Book the only seat
Reservation::factory()->create([
'session_id' => $session->id,
'seats' => 1,
'status' => 1,
]);

$this->actingAs($user);

$response = $this->post(route('reservations.store'), [
'account_id' => $account->id,
'session_id' => $session->id,
'seats' => 1,
]);

$response->assertSessionHasErrors('session_id');
}
}

Unit Test Example (tests/Unit/SubscriptionTest.php):

<?php

namespace Tests\Unit;

use App\Models\Subscription;
use App\Models\SubscriptionInvoice;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class SubscriptionTest extends TestCase
{
use RefreshDatabase;

/** @test */
public function subscription_calculates_monthly_price_with_volume_discount()
{
$subscription = Subscription::factory()->create([
'created_at' => now()->subMonths(6),
]);

// Event with volume pricing: 10% off at 6 months
$subscription->event->update([
'price' => 100,
'volume_pricing' => [
['months' => 6, 'discount_type' => 'percent', 'amount' => 10]
]
]);

$monthlyPrice = $subscription->calculateMonthlyPrice();

$this->assertEquals(90, $monthlyPrice); // $100 - 10%
}
}

Test Database

Tests use in-memory SQLite for speed:

phpunit.xml:

<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>

Debugging

Laravel Debugbar

Enable in Development:

DEBUGBAR_ENABLED=true

Access debugbar at bottom of page to view:

  • Queries and execution time
  • Route information
  • View data
  • Session data
  • Memory usage
  • Request/response details

Logging

View Logs:

tail -f storage/logs/laravel.log

Log Channels:

  • single - All logs in one file
  • daily - Rotate logs daily
  • slack - Send critical errors to Slack
  • papertrail - Send to Papertrail service

Log Examples:

Log::info('User registered', ['user_id' => $user->id]);
Log::warning('Low seat availability', ['session_id' => $session->id]);
Log::error('Payment failed', ['error' => $exception->getMessage()]);

Xdebug Setup

Install Xdebug:

# macOS (via Homebrew)
pecl install xdebug

# Windows (included with Laravel Herd)

Configure php.ini:

[xdebug]
zend_extension=xdebug.so
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_port=9003
xdebug.client_host=127.0.0.1

VS Code launch.json:

{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/app": "${workspaceFolder}"
}
}
]
}

Set Breakpoints in VS Code, start debugging, trigger request

Telescope (Development Profiling)

Install (if not already):

composer require laravel/telescope --dev
php artisan telescope:install
php artisan migrate

Access: http://lancasterarcheryacademy.test/telescope

Features:

  • Request monitoring
  • Database query tracking
  • Job/queue inspection
  • Mail preview
  • Exception tracking
  • Cache operations
  • Redis commands

Code Quality

Laravel Pint (Code Formatting)

Run Formatting:

./vendor/bin/pint

Check Without Formatting:

./vendor/bin/pint --test

Configuration: pint.json

PHPStan (Static Analysis)

Run Analysis:

./vendor/bin/phpstan analyse

Configuration: phpstan.neon

ESLint (JavaScript Linting)

Run Linting:

npm run lint

Auto-fix:

npm run lint:fix

Configuration: .eslintrc.js

Git Workflow

Branching Strategy

  • main - Production-ready code
  • develop - Integration branch
  • feature/feature-name - Feature development
  • fix/bug-name - Bug fixes
  • hotfix/critical-fix - Production hotfixes

Commit Message Convention

Follow Conventional Commits:

feat: add subscription volume discount calculator
fix: resolve cart expiration race condition
docs: update payment processing guide
refactor: simplify reservation validation logic
test: add subscription billing tests
chore: update composer dependencies

Pull Request Checklist

  • Tests passing (php artisan test)
  • Code formatted (./vendor/bin/pint)
  • Static analysis passing (./vendor/bin/phpstan analyse)
  • Frontend linted (npm run lint)
  • Assets compiled for production (npm run production)
  • Database migrations tested
  • Documentation updated
  • Nova resources tested
  • Browser testing completed

Performance Optimization

Caching

Production Caching:

# Cache configuration
php artisan config:cache

# Cache routes
php artisan route:cache

# Cache views
php artisan view:cache

# Cache events
php artisan event:cache

Clear All Caches:

php artisan optimize:clear

Query Optimization

Enable Query Logging (development):

DB::enableQueryLog();
// ... perform queries
dd(DB::getQueryLog());

Use Debugbar to identify N+1 queries

Eager Loading:

// Bad (N+1)
$reservations = Reservation::all();
foreach ($reservations as $reservation) {
echo $reservation->session->event->name; // 2 additional queries per reservation
}

// Good (eager loading)
$reservations = Reservation::with('session.event')->get();
foreach ($reservations as $reservation) {
echo $reservation->session->event->name; // Only 3 queries total
}

Asset Optimization

Production Build (minified, optimized):

npm run production

Image Optimization:

  • Use WebP format where supported
  • Implement lazy loading
  • Optimize via Nova Media Library

Scheduled Tasks (Cron)

Configure Cron Job

On Server:

crontab -e

# Add:
* * * * * cd /path-to-project && php artisan schedule:run >> /dev/null 2>&1

List Scheduled Tasks

php artisan schedule:list

Run Schedule Manually

php artisan schedule:run

Key Scheduled Commands

In app/Console/Kernel.php:

protected function schedule(Schedule $schedule)
{
// Generate subscription invoices (1st of each month)
$schedule->command('subscriptions:generate-invoices')
->monthlyOn(1, '01:00');

// Charge active subscriptions (daily)
$schedule->command('subscriptions:charge')
->dailyAt('02:00');

// Generate subscription reservations (daily)
$schedule->command('subscriptions:generate-reservations')
->dailyAt('00:00');

// Expire old orders (every 5 minutes)
$schedule->command('orders:expire')
->everyFiveMinutes();

// Clean old audits (weekly)
$schedule->command('audits:clean')
->weekly()
->sundays()
->at('03:00');
}

Deployment

Pre-Deployment Checklist

  • Environment variables configured for production
  • Database backed up
  • Tests passing
  • Assets compiled (npm run production)
  • Dependencies updated (composer install --no-dev --optimize-autoloader)
  • Configuration cached
  • Maintenance mode plan

Deployment Steps

# 1. Enable maintenance mode
php artisan down --message="Upgrading system" --retry=60

# 2. Pull latest code
git pull origin main

# 3. Install/update dependencies
composer install --no-dev --optimize-autoloader --no-interaction

# 4. Run migrations
php artisan migrate --force

# 5. Clear and cache
php artisan optimize:clear
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache

# 6. Restart queue workers
php artisan queue:restart

# 7. Build frontend assets (if not built locally)
npm ci
npm run production

# 8. Disable maintenance mode
php artisan up

Environment Configuration (Production)

APP_ENV=production
APP_DEBUG=false
APP_URL=https://lancasterarcheryacademy.com

LOG_CHANNEL=daily
LOG_LEVEL=error

SESSION_DRIVER=redis
CACHE_DRIVER=redis
QUEUE_CONNECTION=redis

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=your_redis_password
REDIS_PORT=6379

AUTHNET_MODE=production

Zero-Downtime Deployment

Use Laravel Envoy or Deployer for automated zero-downtime deployments.

Troubleshooting

Common Issues

"Class not found" errors:

composer dump-autoload
php artisan optimize:clear

Assets not loading:

npm run production
php artisan storage:link
php artisan optimize:clear

Permission errors:

chmod -R 775 storage bootstrap/cache
chown -R www-data:www-data storage bootstrap/cache

Queue jobs not processing:

php artisan queue:restart
php artisan queue:work --verbose

Nova not loading:

php artisan nova:publish
php artisan view:clear

Additional Resources