# BukidBountyApp — project instructions

## Dictionary-first workflow (MANDATORY)

This repo maintains a project dictionary at `ai-docs/dictionary.md` that maps domain terms, file locations, and concepts. It exists to save tokens on repeated lookups.

**At the start of every task in this repo:**
1. Read `ai-docs/dictionary.md` before exploring the codebase. Use it to resolve terms, file paths, and concepts instead of grepping/globbing first.
2. Only fall back to direct codebase exploration when the dictionary doesn't cover the term.

**During and after the task:**
3. When you discover anything worth caching for next time — a new term, a moved/renamed file, a corrected definition, a non-obvious mapping (term → file/function/route), a domain concept — update `ai-docs/dictionary.md` in place.
4. Keep entries concise: term, one-line definition, and the canonical file path(s).
5. Remove or correct entries you find to be stale or wrong.

The `dictionary` skill encapsulates this behavior — invoke it (or follow its rules manually) on every non-trivial task.

---

## Definition of Done — New Page or Feature (MANDATORY)

Every new page or API endpoint is **not complete** until all of the following are verified. Check each before closing any task that adds a page, route, or feature:

### Backend
- [ ] `UserActions::NewActionName` added to `app/Enums/UserActions.php`
- [ ] `UserPermissions::roles()` updated — which roles get the action, and which don't
- [ ] Route added to `routes/web.php` with the correct middleware (`auth`, `module:*`, etc.)
- [ ] Any raw `DB::table()->insert()` or `->update()` includes `created_by`/`updated_by` (Auth::id()) and `created_at`/`updated_at` (now()) — Eloquent listeners don't fire on raw queries

### Frontend / SPA
- [ ] Route registered in `app/Http/Controllers/Support/VueRouteMap.php` with `allowedUserTypes` — **must happen in the same commit as the new `.vue` file**, not as a follow-up fix
- [ ] Direct URL access tested (reload the page at its URL, not just navigate to it in-app)

### Theming
- [ ] No `bg-white`, `bg-light`, or `text-dark` hardcoded in the template — use CSS variables (`var(--bg-card)`, `var(--text-primary)`) or rely on the global Bootstrap overrides in `app.js`
- [ ] No scoped-CSS dark mode fix needed — the global `.dark-mode .bg-white` / `.bg-light` / `.text-dark` overrides in `app.js` handle Bootstrap classes automatically

### Layout
- [ ] If the page uses `sticky-top` on a header, set `top: 66px; z-index: 1020;` — the app has a fixed `TopHeader` at 66px and a sticky child will hide behind it without this offset

### Canonical Table Names
- [ ] Any raw SQL or `unique:`/`exists:` validation rule uses the **abbreviated table name** from the dictionary (`str` not `stores`, `prd_items` not `products`, `cst` not `customers`, `prd_str` not `product_store`) — wrong names cause silent 400/500 errors
