# CLAUDE.md — ZoShop (zoshop-admin-web)

ZoShop is a location-based shop/service discovery platform (India). This one Laravel app is the whole backend and has four surfaces, separated by subdomain: a Filament **admin panel** (`admin.*/admin`), a **REST API for the separate Flutter customer app** (`admin.*/api`), a session-based **Partner PWA** built with Livewire where shop owners onboard, manage their shop and pay for subscriptions via Razorpay (`business.*`), and a public **marketing homepage** (root domain). Customers and partners log in with phone OTP (MSG91); admins use Filament email/password.

<!-- Context files: imported automatically at the start of every session. -->
@.claude/PROJECT_CONTEXT.md
@.claude/DECISIONS.md
@.claude/UI_CONTEXT.md

## Stack

<!-- The only part of this file that changes: update it whenever composer.json / composer.lock / package.json change (version bump, package added or removed). Everything under "Hard rules" stays fixed. -->

- PHP ^8.2 · Laravel 12.69.2 (locked) — Laravel 11+ skeleton: routing/middleware in `bootstrap/app.php`, no Kernel/RouteServiceProvider, models in `app/Models`, extra route files under `routes/{admin,customers,partners,marketing}/`
- Database: sqlite in `.env.example` (production driver unknown, see PROJECT_CONTEXT §12) · Queue: database (no jobs exist) · Cache: database · Mail: log · Files: local, plus custom disk `public_web` (root = `public/`) for uploads
- Frontend: Filament admin (Amber theme, Vite theme CSS); Partner PWA = Blade + Livewire 4 (bundles Alpine) + Tailwind 4 (neutral palette, class-based dark mode); marketing page = Blade + custom `resources/css/marketing.css`; Vite 7 build (`public/build` is git-ignored)
- Packages (non-dev, locked): filament/filament `v5.8.4` — admin panel; laravel/sanctum `v4.3.3` — customer API tokens; laravel/tinker `v2.11.1`; livewire/livewire `v4.4.6` — Partner PWA; razorpay/razorpay `2.9.3` — subscription payments
- Dev packages: fakerphp/faker `v1.24.1`, laravel/breeze `v2.4.2` (no Breeze scaffolding in `app/`), laravel/pail `v1.2.7`, laravel/pint `v1.30.4`, laravel/sail `v1.67.0`, mockery/mockery `1.6.15`, nunomaduro/collision `v8.9.5`, phpunit/phpunit `11.5.56`
- npm: tailwindcss ^4, @tailwindcss/vite ^4, vite ^7, laravel-vite-plugin ^2, alpinejs ^3.17, axios ^1.11, concurrently ^9
- Run locally: Laragon wildcard vhost `*.zoshop-admin-web.test` (+ hosts entries for `admin.`/`business.`); `composer setup` (runs `migrate --force` — not on a live DB), `composer dev` (serve + queue + pail + vite), `composer test`; `npm run dev` / `npm run build`
- Stack last updated: 2026-11-12

## Hard rules

These apply to every session and every task. They change only when the user explicitly asks.

### 1. Load the context before planning
The context files above are imported automatically; if they did not load, read everything in `.claude/` before doing anything else. Use them as the map: read the sections relevant to the task, then open the actual code you will touch. The files tell you where to look; the code tells you what is true.

### 2. Plan first for medium or large changes
A change is medium/large when it does any of these:
- adds or changes a migration (any schema change)
- adds a module, panel, route group, guard, role, or API version
- touches authentication, roles/permissions, payments, or money/tax calculations
- changes how an existing flow behaves (rather than fixing a bug in it)
- refactors or moves code, or will touch more than about 4 files
- adds, removes, or upgrades a package

For these: enter plan mode (if you cannot switch modes yourself, write the plan in chat and treat it the same way). Read the relevant code first, then ask the clarifying questions you need — multiple-choice where possible — and wait for the user's approval before editing any file. Small changes (a bug fix in one place, a text change, one validation rule) can go ahead directly.

### 3. Keep the context files current — after every change
This is the most important rule. Stale context is worse than none, because the next session will trust it.
- `PROJECT_CONTEXT.md` describes the project as it is **now**. When something changes, edit the affected section in place — no "Update:" notes, no leaving the old version beside the new one — and bump its "Last updated" line.
- `DECISIONS.md` is append-only history. Add an entry for every decision that has a why: a design choice, a trade-off, a rejected alternative, a business rule the user explained, a convention adopted. Never edit or delete old entries; to reverse one, add a new entry and mark the old one `Superseded by <date — title>`.
- `UI_CONTEXT.md` changes when a UI pattern is added or changed (layout, component, colour, form/table/alert pattern). Record the why in `DECISIONS.md`.
- The Stack section of this file changes when composer/npm dependencies change.

Record: schema changes, new or changed routes/modules, models and relationships, business rules and flows, integrations, jobs and schedules, config/env keys (names only), packages, UI patterns. Skip: bug fixes that do not change behaviour, copy edits, formatting.

Do the updates in the same task as the change, before saying you are done. End every task with one line:
`Context updated: <file> (<what>), …` — or `Context updated: none needed (<reason>)`.

### 4. Protect existing data
This project has history and probably live data. Never run any of these without the user's explicit OK in the current conversation: `migrate:fresh`, `migrate:refresh`, `migrate:reset`, `migrate:rollback`, `db:wipe`, `db:seed` or `--seed`, raw `DROP` / `TRUNCATE`, `DELETE` or `UPDATE` without a `WHERE`. If a planned schema change can lose data (dropping or renaming a column or table, narrowing a type), say so explicitly in the plan.

### 5. Migrations
Never edit a migration that may already have run — write a new one, named for what it does. Use `php artisan migrate:status` (read-only) when unsure. Keep `down()` working. The migrations may not describe the whole database — check `PROJECT_CONTEXT.md` §4.4 before assuming they do.

### 6. Follow the existing patterns
Match how this project already does things — structure, naming, validation style, response format, UI components (see `PROJECT_CONTEXT.md` §9 and `UI_CONTEXT.md`) — even where a newer approach exists. Propose modernisation as a separate decision; never slip it into an unrelated task.

### 7. Dependencies and versions
Do not install, remove or upgrade composer/npm packages, or change the PHP/Laravel version, without asking. If a task seems to need a package, name it, say why, and wait.

### 8. Secrets
Never write values from `.env`, or any other credential, into the context files, code, comments, commits or chat. Refer to keys by name (`MAIL_PASSWORD`). Do not print `.env`. If you find a hard-coded credential, report its location, not its value.

### 9. Code beats context
If a context file disagrees with the code, the code is right: fix the file in the same task and tell the user what was wrong. Anything marked *(inferred)* was guessed during the initial scan — confirm it before relying on it for anything risky.

### 10. Verify before saying done
Run the project's tests if real ones exist. Otherwise at least lint changed PHP files (`php -l`), and run `php artisan route:list` after route changes. Say what you checked and what you could not check.

### 11. Changing this file
Do not edit the Hard rules unless the user explicitly asks. If `DECISIONS.md` grows past about 400 lines, ask before moving old superseded entries to `.claude/DECISIONS_ARCHIVE.md`.

### Project-specific rules (carried over)

Carried over from `.agents.md` (the project's earlier agent index, kept in place; it points to `.agent/PROJECT_CONTEXT.md`, `.agent/DECISSIONS.md`, `.agent/UI_CONTEXT.md`). Facts from those files have been verified and moved into `.claude/`; the `.agent/` files are older and partly stale (e.g. they still describe an approval workflow and omit several admin resources).

- **Keep the layering `Controller → Service → Repository`.** No substantial business logic in controllers, Livewire components or Filament classes. Services are standalone classes (no interfaces); repository contracts live in `app/Contracts/Repositories`, implementations in `app/Repositories/Eloquent`, bound in `RepositoryServiceProvider`. (Reality check in PROJECT_CONTEXT §9: there is no Admin service layer yet; do not spread that further without asking.)
- **Keep the four surfaces separate** — Admin (Filament), Partner PWA, Flutter customer API, marketing — in code, routes and guards. Don't make the Partner PWA consume `routes/customers/api.php`, and don't put Partner logic under a `Customers` namespace.
- **Don't invent anything listed as open/undecided** in `.agent/DECISSIONS.md` ("Open / not decided yet": subscription plan tiers/pricing, admin-side partner/product management UI). Ask first.
- **Public visibility is enforced server-side** via `Business::scopePubliclyVisible` — never trust the Flutter app to filter, and reuse the scope.
- **Status-like columns stay plain strings** — no PHP enums or DB ENUMs.
- **Context location (decided 2026-11-12):** `.claude/` is the only canonical context set. `.agents.md` and `.agent/*.md` are legacy: do not read them as truth and do not update them (its rules 1–2, "read/update `.agent/*.md`", are superseded by Hard rules 1 and 3). The user may delete them later.
