This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Laravel 12 application with Livewire 3, using the official Laravel Livewire Starter Kit. Full-stack PHP application with Tailwind CSS v4, Flux UI components, and Vite build system.
# Start full development stack (recommended)
composer dev
# Individual services
php artisan serve # Laravel dev server
npm run dev # Vite with hot reload
php artisan queue:listen # Queue worker
php artisan pail # Log viewer# Run all tests
composer test
# or
php artisan test
# or
./vendor/bin/pest
# Run specific test suites
./vendor/bin/pest tests/Feature
./vendor/bin/pest tests/Unit
# Run specific test file
./vendor/bin/pest tests/Feature/Auth/LoginTest.php# Fix PHP code style
./vendor/bin/pint
# Check without fixing
./vendor/bin/pint --testphp artisan migrate # Run migrations
php artisan migrate:fresh --seed # Reset and seed database
php artisan db:seed # Run seeders only# Production build
npm run build
# Clear caches
php artisan config:clear
php artisan cache:clear
php artisan view:clearAll Livewire components follow this structure:
- PHP Class:
app/Livewire/{Feature}/{ComponentName}.php - Blade View:
resources/views/livewire/{feature}/{component-name}.blade.php - Components use Volt for single-file components in
resources/views/livewire/
Key component patterns:
- Use typed properties for data binding
- Implement validation rules via
#[Validate]attributes orrules()method - Mount method for initialization
- Computed properties for derived state
Complete authentication system with:
- Login/Register/Logout in
app/Livewire/Auth/ - Email verification support
- Password reset functionality
- Two-factor authentication ready
- CSS: Tailwind CSS v4 configured in
resources/css/app.css - Flux UI: Component library imported, use
<flux:button>,<flux:input>, etc. - JavaScript: Minimal JS in
resources/js/app.js, primarily for Livewire - Build: Vite handles all asset compilation with hot reloading
- Migrations use anonymous classes
- Factories defined for all models in
database/factories/ - MySQL database in development and production
- Soft deletes implemented where appropriate
- Feature Tests: User flows and integration tests in
tests/Feature/ - Unit Tests: Model and service tests in
tests/Unit/ - Tests use RefreshDatabase trait
- Factory-based test data generation
- Livewire testing helpers for component assertions
- Routes:
routes/web.phpfor web routes - Config:
config/directory, especiallyapp.php,database.php,livewire.php - Environment:
.envfor local configuration (never commit) - Models:
app/Models/following Eloquent conventions - Middleware:
app/Http/Middleware/for request filtering
This is a task management application with cleaning/maintenance scheduling features:
- Core Models: Task, TaskSchedule, TaskTemplate, TimeLog, Station, InventoryItem
- Key Service:
RecurrenceCalculatorhandles complex recurring task logic - Features: Task scheduling with recurrence patterns, inventory tracking, time logging, station management
The application uses a two-phase task management system:
-
Task (Master Template): Defines the recurrence rules
- Fields:
interval_type(daily/weekly/monthly/yearly/custom),interval_value,recurrence_pattern(JSON) - Located in
app/Models/Task.php recurrence_patternstores complex rules like weekdays-only, even/odd weeks, specific days
- Fields:
-
TaskSchedule (Instance): Individual occurrences generated from Task
- Generated by
tasks:generatecommand viaRecurrenceCalculatorservice - Status flow:
pending→in_progress→completedORpending→overdue - Located in
app/Models/TaskSchedule.php
- Generated by
RecurrenceCalculator Service (app/Services/RecurrenceCalculator.php):
- Core logic:
shouldGenerateTask(Task $task, Carbon $date): bool - Handles complex patterns:
- Daily: weekdays-only mode, every N days
- Weekly: specific days, even/odd week filtering
- Monthly: day-of-month (handles month-end edge cases), Nth weekday (e.g., "second Tuesday")
- Yearly: same month/day annually
- Method
getNextOccurrences()for preview (used in UI)
Two critical artisan commands run via cron:
-
tasks:generate(app/Console/Commands/GenerateTaskSchedules.php)- Generates TaskSchedule instances from Task templates
- Options:
--days=7(lookahead window),--date=(start date) - Prevents duplicates with
whereDate()check - Default due times vary by interval_type (daily: 18:00, weekly: 17:00, etc.)
-
tasks:rollover-overdue(app/Console/Commands/RolloverOverdueTasks.php)- Marks overdue tasks (past scheduled_date/due_time)
- Moves non-daily overdue tasks to today if
settings('task_rollover_enabled')is true - Adds note: "Flyttad från {date} (försenad)"
- Excludes daily tasks from rollover (they regenerate naturally)
Schedule these in cron (production):
* * * * * cd /path && php artisan schedule:runGlobal helper function (app/helpers.php):
settings('key', 'default_value') // Get setting
settings()->set('key', 'value') // Set settingSettingsService (app/Services/SettingsService.php):
- Cached in Laravel cache (24hr TTL)
- Stored in
settingstable with groups (general/tasks/notifications) - Admin configurable via
Admin\SystemSettingsLivewire component - Key settings:
task_rollover_enabled,require_clock_in_for_completion
Gate definition (app/Providers/AppServiceProvider.php):
Gate::define('admin', fn($user) => $user->isAdmin());Route middleware (routes/web.php):
- Employee routes:
middleware(['auth']) - Admin routes:
middleware('can:admin')
IMPORTANT: Livewire components do NOT have automatic authorization checks. When creating admin components, manually verify:
public function mount() {
abort_unless(Gate::allows('admin'), 403);
}Components follow feature-based organization:
app/Livewire/Admin/*- Admin-only features (stations, tasks, templates, inventory, users, settings)app/Livewire/Employee/*- Employee features (dashboard, station details, tasks, time reports)app/Livewire/Auth/*- Authentication flow (login, register, password reset, email verification)app/Livewire/Settings/*- User settings (profile, password, appearance)
Naming Convention:
- Class:
app/Livewire/Feature/ComponentName.php - View:
resources/views/livewire/feature/component-name.blade.php
- Clock In: Creates
TimeLogwithclock_intimestamp,station_id - Clock Out: Updates same
TimeLogwithclock_out, calculates duration - Task Completion: Can create separate TimeLog entries per TaskSchedule completion
- Reports:
Employee\TimeReportscomponent, exports viaTimeReportsExportController
Station
├── hasMany Tasks
├── hasMany TaskSchedules (through Tasks)
├── hasMany TimeLogs
├── hasMany StationInventory
└── belongsToMany Users (station_user pivot)
Task
├── belongsTo Station
├── hasMany TaskSchedules
└── no direct user relationship (assigned via station)
TaskSchedule
├── belongsTo Task
└── belongsTo Station (through Task)
TimeLog
├── belongsTo User
├── belongsTo Station
└── belongsTo TaskSchedule (nullable - can be general clock in/out)
- Local Server: Uses
composer devwhich starts all services (including php artisan serve) - Database: MySQL configured in
.env(changed from SQLite) - Locale: Swedish (
Carbon::setLocale('sv')in AppServiceProvider)
- Create Livewire components:
php artisan make:livewire ComponentName - Run tests after changes:
./vendor/bin/pest - Format code before commits:
./vendor/bin/pint - Use
composer devfor full-stack development - Database changes require migrations:
php artisan make:migration
- NEVER use seeders in production - they contain test users with
passwordas password - Create admin users via Tinker in production (see
docs/installation.md) - Test user emails:
admin@example.com,employee@example.com(development only) .envis gitignored - no hardcoded secrets in codebase- All sensitive configs use
env()helper