4.8 KiB
4.8 KiB
Ledgerrz Project Instructions & Conventions
Welcome to the Ledgerrz codebase! This file defines the persistent guidelines, architectural rules, and context directories loaded in every Gemini session.
1. Context Persistence Mandate
- Business Logic & Goals (
IDEA.md): You MUST read and follow the application concept, features, and user workflow goals outlined inIDEA.mdat the start of any new session. - Design & Architecture Decisions (
DECISIONS.md): You MUST strictly adhere to the established style architecture (BEM methodology with scoped styles and@apply), package deduplication rules, and controller structures documented inDECISIONS.md. Update this file with any new major design decisions made during your session.
2. Key Technology Stack & Conventions
- PHP/Laravel: PHP 8.4 & Laravel 13. Adhere to typed parameters and return values. Ensure controllers extend properly and use required authorization traits (e.g.,
AuthorizesRequests). - Frontend Styling (BEM): Replaced direct Tailwind inline utility-class markup with BEM (Block, Element, Modifier). All custom component styles must live inside
<style scoped>blocks with a relative@reference "../../css/app.css"directive to pull variables without duplications. - Real-time Broadcasting: Powered by
@laravel/echo-vuewith fallback configurations and Vite deduplication rules configured invite.config.ts. - Testing & Isolation: Powered by Pest PHP (v4). Every backend controller, event, or model change must be validated by running tests. To prevent local
.envvariables from polluting the CLI test execution (causing CSRF/session 419 errors), always run tests in an isolated environment using:env -i PATH="$PATH" php artisan test - Standardized Authorization (
canprop): Never write manual role checks (such aspivot.role === 'owner') or hardcoded boolean flags (such asisOwner) inside Vue pages or components. Instead, always leverage Laravel policies on the backend and pass permissions reactively to the frontend as structuredcanobjects (e.g.,can: { update: boolean, close: boolean }). - Vue-Defined Breadcrumbs Layout: All page-specific breadcrumbs should be declared locally inside the page's
.vuefile rather than returned from controllers. For dynamic, prop-dependent paths, always use the Inertia v3 layout callback function insidedefineOptions:defineOptions({ layout: (props: any) => ({ breadcrumbs: [ { title: 'Dynamics', href: route('dynamics.index') }, { title: props.dynamic.name, href: route('dynamics.show', props.dynamic.id) } ] }) });
3. Advanced Browser Testing & Architectural Guidelines (Laravel Dusk)
- Dusk Database Locks on SQLite: Never use the
DatabaseTransactionstrait in Laravel Dusk tests if the project is backed by a SQLite database file. Since Dusk runs in concurrent, separate processes (the CLI runner and the web server), an active uncommitted database transaction in the CLI will hold a SQLite write lock. This causes the web server to fail withSQLSTATE[HY000]: General error: 5 database is locked. Instead, dynamically create and clean up models during test execution or use sequential DB seeds. - Inertia/Vue SPA Testing: Browser tests targeting asynchronously rendered Single Page Applications must always use explicit
waitForText()orwaitFor()selectors before executing assertions. Direct assertions likeassertSee()are immediate and will fail if the JavaScript has not finished compiling and mounting the DOM. - Synchronous Queue for WebSockets: Running real-time WebSocket / Echo Dusk tests locally requires setting
QUEUE_CONNECTION=syncandBROADCAST_CONNECTION=reverbin your.envfile. This ensures broadcast jobs execute immediately on the web server rather than buffering in the database (which fails without a running background queue worker). - Automatic ID-to-UUID Serialization: All models carrying a
uuidcolumn (such asUser,Dynamic,Ledger,Mutation, andPredefinedMutation) must use theApp\Concerns\SerializesIdToUuidtrait. This guarantees that any raw model or relationship array/JSON conversion automatically replaces the integeridwith the secureuuidunder the'id'key. - UUID Controller Inputs: When the frontend submits relationship parameters (such as
predefined_mutation_idin requests), it only knows and passes the secure UUID. The receiving backend controller must explicitly resolve this UUID to its internal database integer ID before inserting the record (e.g.PredefinedMutation::where('uuid', $uuid)->value('id')), maintaining column type safety and foreign key constraints without exposing integer IDs to the client.