Skip to content

Development Guide

This guide covers local setup, testing, and coding standards.

Contributing

Contributions welcome — features, fixes, tests, and docs.

  1. Setup: Follow Quick Start below
  2. Branch: Create a feature branch from dev
  3. Code: Make small, focused commits
  4. Test: Run backend and frontend tests (see Testing)
  5. PR: Open a pull request to dev

For detailed git workflow, branching strategy, and conflict resolution, see Git Workflow.

Fast Evaluator Path

If you are opening this repo to assess it quickly rather than contribute to it, use this shorter path:

  1. Run the seeded app

    bash
    ./utils/deploy.sh --seed
  2. Open the main surfaces

  3. Use the seeded accounts

    • Admin: admin@catarchy.space / password
    • User: user1@catarchy.space / password
  4. Run the quick review command

    bash
    bun run review:quick

Quick Start

If your shell does not recognize vp, the repo is still usable with bun run ... from frontend/ because those scripts already delegate into Vite+. You can either use that fallback or add your local Vite+ install directory to PATH.

New to the repo? Follow these steps to get running:

  1. Run the app

    bash
    ./utils/deploy.sh

    Note: The backend automatically creates .env from .env.example when you run any php artisan command if it doesn't exist. You'll see a helpful message to run php artisan key:generate.

    Tip: Use ./utils/deploy.sh --skip-build for faster deployments when you've already built the Docker images and just need to restart containers or run database migrations.

  2. Access the app

    Admin port settings (ADMIN_HOST_BIND, ADMIN_HOST_PORT, VITE_ADMIN_URL) belong in the repo-root .env. ADMIN_URL belongs in backend/.env.

    If port 8001 still shows the main app after an upgrade, unregister the stale service worker for localhost:8001 in browser DevTools → Application → Service Workers.

  3. Optional: Enable HTTPS for local dev (single compose)

    bash
    # Set in backend/.env
    APP_ENV=development
    ENABLE_HTTPS=true
    
    # Generate self-signed certificates (one-time setup)
    # Note: script will NOT overwrite existing certs; use --force to regenerate
    ./utils/generate-dev-certs.sh
    
    # Deploy using the single entry point
    ./utils/deploy.sh
    
    # Access via HTTPS
    # https://localhost (browser will show security warning - click "Advanced" → "Proceed")
    # https://localhost:8001
    # https://localhost/docs

    Why HTTPS in dev?

    • Test features requiring secure context (Service Workers, Web Crypto API, etc.)
    • Match production behavior more closely
    • Test HTTPS-specific security headers

    Production note: Production deployments use docker-compose.yml only (no dev override). HTTPS is handled by reverse proxy (nginx/caddy/traefik) with proper certificates.

  4. Generate API Client

    If you change the backend API (@OA annotations), you must regenerate the frontend types and hooks:

    bash
    # Run from root to sync both backend and frontend
    vp run api:generate

    If vp is not available in your shell yet, use:

    bash
    bun run api:generate

    Alternatively, run separately:

    bash
    cd backend && php artisan l5-swagger:generate
    cd ../frontend && vp run api:generate

    CI/Commit Guardrail To ensure your generated code matches the current backend attributes, run:

    bash
    vp run api:check

    Shell fallback:

    bash
    bun run api:check

    (Exits with code 1 if there are uncommitted changes to generated files).

    Deployment: The ./utils/deploy.sh script automatically regenerates both the OpenAPI spec and the frontend client during the pre-build stage to ensure the production image is always consistent.

    Usage: Refer to frontend/src/api/generated/ for the output. Prefer using the generated hooks (useGetPets, usePostPets, etc.) over manual Axios calls for full type safety.

    See API Conventions for more details on full-stack typesafety.

Test Users (Seeded Data)

  • Super Admin: admin@catarchy.space / password
  • Admin: user1@catarchy.space / password
  • Regular Users: 3 users with factory-generated names/emails / password

Admin Features

  • User Impersonation: Click 👤 icon in Users table to impersonate any user
  • Stop Impersonating: Use navbar indicator or admin panel to return
  • User Ban/Unban: Ban users to put them in read-only mode (view-only, no writes); unban to restore full access
  • User Storage Visibility: Open http://localhost:8001/users/:id to view storage used and storage limit for that user
  • Storage Limits Config: Open http://localhost:8001/system-settings to configure default vs premium storage ceilings

Testing

Backend (Pest/PHPUnit)

Always run backend tests inside the Docker container to ensure proper extensions and PHP version.

Tests run in parallel by default for faster execution.

bash
# Run all tests (parallel by default)
cd backend && php artisan test --parallel

# Run tests without parallel execution
cd backend && php artisan test --no-parallel

# Run specific test suites
cd backend && php artisan test --parallel --testsuite=Feature
cd backend && php artisan test --parallel --testsuite=Unit

Running tests locally (outside Docker):

If you need to run tests on your local machine:

bash
cd backend

# First time only - .env will be auto-created from .env.example
composer install
php artisan key:generate

# Configure your local database settings in .env, then run tests
php artisan test --parallel

Frontend (Vitest)

bash
cd frontend

# Run all tests
vp test

# Interactive UI
vp run test:ui

# Coverage report
vp run test:coverage

End-to-End (Playwright)

Playwright E2E tests live under frontend/e2e/.

For this project, the default E2E runner (frontend/scripts/e2e-test.sh) manages Docker services (db, backend, mailhog) and database seeding automatically before running Playwright.

Offline-mode E2E coverage lives in frontend/e2e/offline-mode.spec.ts (pet create/edit/delete, medical record create, and habit day check-in queue/replay). Integration coverage for the same journeys without a full browser is in frontend/src/offline/offline-mode.integration.test.tsx. See Offline Mode for the feature matrix and test-layer guidance.

The checked-in Playwright config now defaults to a single worker for stability with the seeded shared accounts. Override it with PLAYWRIGHT_WORKERS only when you intentionally want to trade some determinism for speed.

Quick start:

bash
# From frontend/
cd frontend
vp run e2e            # headless run
vp run e2e:ui         # interactive UI
vp run e2e:report     # open last HTML report

Important when debugging against http://localhost:8000: Playwright is exercising the Docker-served app, not a live Vite dev server. If you change frontend code that is bundled into the backend-served SPA, rebuild the frontend and then rebuild the backend container image so the running app actually serves the new assets:

bash
cd frontend
bun run build
cd ..
docker compose up -d --build backend

A plain docker compose restart backend is enough for backend-only PHP changes, but not for frontend asset changes that are baked into the image.

If Playwright browsers are missing on your machine, install them once:

bash
cd frontend
vp exec playwright install chromium

Static Analysis & Quality Gates

Code Quality (Formatting)

Run Laravel Pint to automatically format code according to PSR-12 and Laravel conventions.

bash
# From the backend directory
cd backend
./vendor/bin/pint

PHPStan (Backend Type Analysis)

PHPStan enforces type safety and catches bugs at write-time using static analysis. Currently configured at Level 5.

Run analysis:

bash
cd backend
composer phpstan

Deptrac (Architecture Layer Enforcement)

Deptrac prevents architectural violations by enforcing allowed dependencies between layers.

Run analysis:

bash
cd backend
composer deptrac

Asset Management

PWA Assets

PWA icons, screenshots, and manifests are maintained as explicit source assets in frontend/public and mirrored to backend/public when they need to be served from Laravel's public root. Do not regenerate the web manifests from an icon-only script: the manifests include install metadata such as id, screenshots, shortcuts, categories, theme colors, and the offline start URL.

Root-level icons such as favicon.ico, apple-touch-icon.png, and icon-32.png are served with a 1-day browser cache in the backend container NGINX config. After updating branding assets, expect clients to pick them up automatically within a day unless you also change the filenames.

The frontend ships separate light and dark web manifests. Theme switching between them is handled by the app-owned runtime in frontend/src/lib/theme-runtime.ts, while the backend SPA shell applies the initial resolved theme before hydration so the manifest, theme-color, and color-scheme metadata stay in sync from first paint onward. Those manifests intentionally do not lock orientation, so the installed PWA can rotate with the device.