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
.nvmrcfor 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
Recommended Tools
- 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
7. Link Storage
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 filedaily- Rotate logs dailyslack- Send critical errors to Slackpapertrail- 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 codedevelop- Integration branchfeature/feature-name- Feature developmentfix/bug-name- Bug fixeshotfix/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
- Laravel Documentation: https://laravel.com/docs/8.x
- Laravel Nova Documentation: https://nova.laravel.com/docs/4.0
- Inertia.js Documentation: https://inertiajs.com
- Vue 3 Documentation: https://v3.vuejs.org
- Tailwind CSS Documentation: https://tailwindcss.com/docs
- Authorize.Net CIM Guide: https://developer.authorize.net/api/reference/features/customer_profiles.html
- Smartwaiver API: https://api.smartwaiver.com/docs/