Instruction file imported from HandsomeStrife/vino-recall (
.cursor/rules/technical-outline.mdc). Copyright stays with the author.
KEY INFORMATION
The site is accessed via http://localhost:8282
NO emojis should be used - this is professional site.
-
No Creation of
app/Domain- All domain-based work must be placed in
/domain/and never in/app/Domainor/app/domain. - Never create or access an
app/Domainorapp/domainfolder.
- All domain-based work must be placed in
-
No
@phpDirectives in Blade- Blade templates must not contain
@phpdirectives.
- Blade templates must not contain
-
Models in Domain Namespace
- No models in the
appnamespace. All Eloquent models reside indomain/*/Models.
- No models in the
-
Fail Fast on Unknown References
- If the AI is about to reference or generate any file/class/method not found or explicitly defined, stop and seek clarification rather than guessing or inventing.
-
snake_case for variables, camelCase for functions/methods.
-
Action classes should be executed in the folgit lowing pattern
(new Action())->execute(...) -
Current user should always be retrieved with
(new UserRepository())->getLoggedInUser()and NEVER with Auth -
This project does NOT use Laravel Dusk for browser testing. It uses Pest Browser testing. Never create Dusk tests or reference Dusk classes. Always examine existing browser tests in tests/Browser/ to see the correct Pest Browser testing pattern before creating any browser tests.
Run tests with sail pest
-
ALWAYS check that components exist before making assumptions
-
Exceptions for broken statem and null for optional data - we should always throw exceptions and catch them, as opposed to returning null unless it's explictly optional.
-
All created markdown documents should be made in the "support-docs" folder
-
Use DTOs over arrays - we should always work towards knowing what data we are working with, and helping enable static analysis
-
When using the Browser to check your work, start with the route
/dev/auto-loginto log in. -
NEVER migrate:fresh or rollback migrations without EXPLICIT approval.
PSR-12 Coding Guidelines
(Full details below are also part of standard PSR-12. This is just a summary of key items to maintain clarity.)
-
General:
- PSR-12 extends PSR-1 and PSR-2.
- Use
UTF-8(no BOM).
-
PHP Tags & Declarations:
- Only
<?php(no short tags). declare(strict_types=1);on its own line immediately after<?php.
- Only
-
Namespaces & Imports:
- One
usestatement per line, grouped logically. - Namespace on its own line, directly below
declare(strict_types=1);.
- One
-
Classes, Traits, Interfaces:
- Opening brace on a new line.
- Blank line before class declaration.
extends/implementson same line as class name (multi-line splits if needed).- Always declare visibility (
public,protected,private) on properties/methods. - Constants in uppercase with underscores.
-
Methods & Functions:
- Opening brace on a new line.
- Arguments inline if short, multiline with optional trailing comma if long.
- Return types on the same line.
- Order:
public|protected|private, thenstatic, thenfunction.
-
Control Structures:
- Space after keywords (
if,while). - Braces on new lines.
- Use
elseif(notelse if). caseindented,breakaligned with case body.
- Space after keywords (
-
Indentation & Line Length:
- 4 spaces, no tabs.
- Soft limit ~120 chars.
- Unix line endings (
\n).
-
Blank Lines & Spacing:
- One blank line between methods or logical code groups.
- No trailing whitespace.
- One blank line before EOF.
-
Docblocks:
- Use standard PHPDoc (
/** ... */) for summaries,@param,@return, etc. - One line per tag.
- Use standard PHPDoc (
-
Misc:
- One statement per line, no closing
?>in pure PHP-only files. - Keep code minimal, tested, and no-lint errors.
Codebase Analysis: Architecture, Strategies, and Components
1. Architecture
- Laravel Foundation: Routing, ORM (Eloquent), service container, etc.
- DDD Approach:
- Core business logic in
domain/*. - Organized into Bounded Contexts (e.g.,
domain/User,domain/StreamLinks, etc.). - Each context typically has subfolders:
Models(Eloquent models)Data(DTOs w/Spatie\LaravelData)Actions(single-operation logic)Repositories(data retrieval, returns DTOs)- Possibly
Enums,Jobs,Exceptions,Mail...
- Core business logic in
- Application Layer (
app/):- Livewire components
- Http controllers, middleware, form requests
- Providers, Console, etc.
- Blade components for “application-level” concerns (but domain logic stays in
domain/).
- Frontend: Livewire for dynamic interfaces, Blade for templating, Alpine.js for simple interactions, Tailwind CSS for styling.
2. Development Strategies & Guidelines
- PSR-12: Strict adherence.
- Spatie Laravel Data:
- Define DTOs in
domain/*/Data. - Create via
::from(). - Livewire + Data objects must implement
Wireable+ useWireableData.
- Define DTOs in
- Action-Repository:
- Actions: single
execute()for business logic & data modifications. - Repositories: read-only data retrieval, returning DTOs (no direct model returns).
- Actions: single
- Models:
- Inside
domain/*/Modelswithprotected $guarded = [];.
- Inside
- Blade:
- No
@phpin templates. - Use standard Blade components for forms, buttons, badges, modals, tooltips, etc.
- No
- Testing:
- Tests are written with Pest4 in mind
- No mocks except external APIs.
- Factories for test data.
- Avoid skipped tests.
- Do NOT use any flags like -v or --versbose when running tests
- Dev Environment:
- Sail for Artisan commands.
- Keep a
development_log.md.
3. Component Usage
-
Blade Components (in
resources/views/components/):- Layouts:
<x-layout.default>/<x-layout.default.sidebar> - Forms:
<x-form>,<x-form.label>,<x-form.input>,<x-form.select> - Buttons:
<x-button>(+ variants) - Badges:
<x-badge>(+ variants) - Modals:
<x-modal.slideover>,<x-modal.popup> - Tooltips:
x-tooltipdata attributes
- Layouts:
-
Livewire Components (
app/Livewire/):- Named for their feature (e.g.,
StreamLinksLinkManager). - Interact with domain Actions & Repositories.
- Must handle state with Spatie DTOs if it’s complex and must remain consistent.
- Named for their feature (e.g.,
-
Data Objects (
domain/*/Data/):- Transfer data across layers, ensuring type safety.
- Created from arrays or models with
::from(). - Provide validation, transformation, and can be used seamlessly in Livewire or controllers.
AI Interaction Guidelines
-
Fail Fast on Uncertain References
- If the requested file/class/method/Blade component isn’t found in the codebase or isn’t explicitly described, ask for clarification before proceeding. Do not invent.
-
Agent Mode / Project Awareness
- In Cursor agent mode, always check for existing classes or files before creating new ones.
- If a file already exists, either (a) use/extend it, or (b) ask if it should be modified.
-
Professional & Predictable Output
- No “made-up” methods or “magic” classes.
- Strictly follow the domain structure, especially
domain/*for domain logic. - Validate all references (methods, classes, components) to ensure correctness.
-
Clean Architecture & Boundaries
- Respect the Action (commands) vs Repository (queries) vs Model lines.
- Keep controllers or Livewire components thin; delegate domain logic to Actions.
-
Naming & Organization
- Match existing patterns (e.g.,
UserData,PaymentRepository). - Keep domain logic within
domain/. - Use
App\Http\Controllersfor standard controllers andApp\Livewirefor Livewire components.
- Match existing patterns (e.g.,
Laravel Guidelines (Specific to the Project)
-
Use Spatie Data for DTOs
- Never override default Spatie methods like
fromArrayorfromModel; useDataClass::from(...)instead. - Repositories must return Data or DataCollections (not raw models).
- Never override default Spatie methods like
-
Actions vs. Repositories
- Repositories: data retrieval only, never modify data.
- Actions: performing logic/persistence in the domain. Single
execute()method is standard.
-
No Unnecessary Eloquent in Livewire
- If data is needed in a Livewire component, retrieve it via the appropriate Repository and store it in a DTO.
- Any creation or update logic must be handled via an Action.
-
Use Sail
- For Artisan, Livewire, Tinker commands:
vendor/bin/sail [command]. - Keep local dev environment consistent.
- For Artisan, Livewire, Tinker commands:
-
Logging in
development_log.md- Record major changes, issues, or discussion outcomes.
-
Dont use data collections
- Always use Laravel collections, not data collections. An example:
/** * @return Collection<UserData> */ public function getAll(): Collection { return User::all()->map(fn ($user) => UserData::from($user)); }
Livewire Practices
-
Creation
vendor/bin/sail livewireto scaffold new components if needed.- Confirm they do not already exist in
app/Livewire/.
-
AlpineJS
- Use for toggles or simple interactive elements.
- Keep heavier JS in standalone scripts if needed.
-
Livewire Data Objects
- Extend
Livewire\Wireable, useSpatie\LaravelData\Concerns\WireableData. - Represent complex state with Data objects rather than arrays.
- Extend
-
Fail Fast
- If the AI is about to reference a non-existent Blade view, partial, or sub-component, pause and confirm.
-
Forms for data saving
- Livewire components should use Livewire Forms for saving information (which in turn should use an action)
- Can be created with artisan livewire:form xyz
Blade Components
- Structure
- Use the existing form elements (
<x-form>,<x-form.label>, etc.), button components (<x-button>), badge components (<x-badge>), and modals (<x-modal.slideover>,<x-modal.popup>).
- Use the existing form elements (
- No
@php- Strictly use Blade expressions
{{ }}or directives like@if,@foreach.
- Strictly use Blade expressions
- Layout
- Use
<x-layout.default>or<x-layout.default.sidebar>, never<x-app-layout>.
- Use
- Tooltips
- Implement with
x-tooltipdata attributes.
- Implement with
Spatie Laravel Data Usage
-
Defining
class SongData extends Data { public function __construct( public string $title, public string $artist, ) {} } -
Creating
SongData::from([...])orSongData::from($model)
-
Validation
- Inferred from property types or custom attributes (
#[Max(20)]). - Can override
rules()if needed.
- Inferred from property types or custom attributes (
-
Features
- Route model binding, transforms, lazy props, TypeScript generation, etc.
Laravel Testing
- Factories
- For test data setup, stored in
database/factories/.
- For test data setup, stored in
- No Mocks
- Unless mocking external APIs, prefer real application code in tests.
- No Skipped Tests
- Must either test or remove.
Code Safety & Final Notes
-
No Speculative Code
- Always confirm existence of classes/methods before referencing.
- If uncertain, ask.
-
No Duplication
- If similar code exists, either reuse or refactor rather than duplicating.
-
Consistent & Predictable
- Respect naming conventions, domain boundaries, and coding style.
- Ensure code compiles & references are accurate (fail fast otherwise).
-
Professional Output
- Keep code neat, minimal, documented where necessary.
- Provide brief reasoning or clarifications when unsure, then ask user for final confirmation.
-
Project Awareness
- In Cursor’s agent mode, search the codebase for relevant references (models, data, actions, repositories) before creating new ones.
Modal Component Usage (<x-modal.slideover> and <x-modal.popup>)
This document outlines the correct way to use the standard modal components in this project. Adhering to these rules ensures consistency and leverages the component design.
Core Principles
- Title via Slot: The modal's title MUST be placed within
<x-slot name="title">. Do NOT use thetitle="..."attribute. - No Content Slot: The main body/content of the modal MUST be placed directly within the
<x-modal.*>tags. Do NOT use<x-slot name="content">. - Actions Slot: Action buttons (like Save, Cancel, Confirm, Delete) MUST be placed within
<x-slot name="actions">. Do NOT place them directly as children of the modal component outside this slot.
Correct Example (<x-modal.popup>)
<x-modal.popup
x-model="confirmingDeletion"
x-modelable="open"
max-width="lg"
>
<x-slot name="title">
Confirm Deletion
</x-slot>
{{-- Main content goes directly here --}}
<p class="text-sm text-gray-600">
Are you sure you want to delete this item? This action cannot be undone.
</p>
{{-- Action buttons MUST be in the actions slot --}}
<x-slot name="actions">
<div class="flex justify-end space-x-3">
<x-button.secondary type="button" @click="confirmingDeletion = false">
Cancel
</x-button.secondary>
<x-button.danger type="button" wire:click="deleteItem">
Delete
</x-button.danger>
</div>
</x-slot>
</x-modal.popup>
Correct Example (<x-modal.slideover>)
<x-modal.slideover
x-model="showForm"
x-modelable="open"
>
<x-slot name="title">
Add New Item
</x-slot>
{{-- Main content (e.g., a form) goes directly here --}}
{{-- Modal Action buttons MUST be in the actions slot --}}
<x-slot name="actions">
<div class="flex justify-end space-x-3">
<x-button.secondary type="button" @click="showForm = false">
Cancel
</x-button.secondary>
<x-button.primary type="submit" form="yourFormId"> {{-- Example: use form attribute if needed --}}
Save Item
</x-button.primary>
{{-- Alternatively, place submit button inside form and only Cancel here --}}
</div>
</x-slot>
</x-modal.slideover>
Incorrect Usage (Avoid This)
{{-- INCORRECT: Uses title attribute --}}
<x-modal.popup x-model="show" title="My Title">
{{-- INCORRECT: Uses content slot --}}
<x-slot name="content">
My modal content.
</x-slot>
{{-- INCORRECT: Places actions outside actions slot --}}
<div class="flex justify-end">
<x-button>OK</x-button>
</div>
</x-modal.popup>