PhpStorm Agent Prompt: Rebuild Hotel Discovery Search as a Reliable Public Search Contract

📄 General
← Back to Documentation
# PhpStorm Agent Prompt: Rebuild Hotel Discovery Search as a Reliable Public Search Contract Copy everything below into the IDE agent as one task. --- You are fixing the production-critical public hotel discovery route: `GET /locations?type=rentals&category=hotel` Read these project references before editing: - `HOTEL_DISCOVERY_SEARCH_AUDIT_2026-08-28.md` - `C:\Users\Svet PC\Downloads\zapazime_2026-08-28_22-55-21.sql` — schema reference only. Do **not** import, alter, expose, or commit this dump. - `app/Http/Controllers/WebController.php` - `app/Models/Venue.php`, `Location.php`, `Place.php`, `Category.php`, `VenueObject.php`, `RentalUnit.php`, `RatePlan.php`, `Stay.php`, and booking models relevant to date availability. - `resources/views/web/locations.blade.php` - `resources/views/web/partials/nav.blade.php` - `app/Providers/AppServiceProvider.php` ## Goal Make public hotel discovery dependable from category navigation through results, location/place/venue detail and booking handoff. This must be a coherent search system, not a collection of independent text filters. Use one validated request contract and one shared public-search scope for results, category counters, map, cards, detail eligibility and booking revalidation. ## Non-negotiable safety rules - Preserve unrelated working-tree changes. - Use PHP 8.3+ only; do not weaken Composer platform checks. - Do not use `withoutGlobalScopes()` for public discovery unless you replace the removed tenant constraints with an explicit, reviewed platform-publication scope. Never cross company/workspace boundaries accidentally. - Do not return inactive, unpublished, unverified, expired-certificate, suspended, rejected, private, deleted, or tenant-inaccessible inventory. - Do not fabricate price, rating, availability, count, amenities or review data. - Do not hide a failure with a broad catch, silent fallback or text matching that bypasses an inactive category/type. - Do not submit real bookings/payments or modify production data. Use factories, seeders and sandbox/non-chargeable test methods only. ## Confirmed defects to fix 1. `WebController::locations()` receives `category=hotel`, but `buildVenueSearchQuery()` only receives the booking type and never applies the selected category. 2. Deactivated categories/types are bypassable: a missing/inactive `Category` currently falls back to venue text matching, and if a booking type has no active categories, the booking-type filter is omitted altogether. 3. Search only checks venue `is_active`; it does not consistently use the model's public-display policy or require active parent place/location and bookable active room/unit inventory. 4. The Blade filter panel emits flat keys such as `ss`, `min_price`, `property_type`, `group_adults`, `amenities[]`, while the controller reads a different nested `q.*` schema. Most controls are ineffective. 5. Hotel date/guest/room controls do not query availability. 6. Amenity filtering queries columns on `venue_facilities`, but the actual facility details are reached through the `facility()` relationship. 7. Rating/review-count filters are unimplemented; sorting has duplicate IDs, no reliable change handler and incompatible values. 8. Navigation count, category-card count, location count and map/result count use different queries. The category card can display a fabricated fallback price or a conflicting availability number. 9. Category matching is hard-coded/keyword-based (`LIKE` on text) instead of a stable category identifier. The public category manager is missing a complete super-admin on/off control with auditability. ## Required design ### 1. Canonical query contract and validation Create a dedicated request/DTO/value object for public discovery. Choose one URL schema and make server, Blade and JavaScript use it consistently. Prefer readable top-level GET parameters, for example: `type`, `category`, `destination`, `checkin`, `checkout`, `adults`, `children`, `children_ages[]`, `rooms`, `min_price`, `max_price`, `currency`, `property_type`, `amenities[]`, `min_rating`, `min_reviews`, `sort`, `page`. For hotels, use **check-in/check-out** terminology; do not reuse vehicle pickup/drop-off semantics. Preserve compatible legacy parameters temporarily only through an explicit normalizer and redirect/canonical URL strategy. Validate and normalize: - exact allowed booking types and active canonical category; - category belongs to type; - dates are valid and checkout is after checkin; - sensible guest/room limits and non-negative prices; - known sort values and known facilities/property types; - pagination limits and deterministic default ordering. An unknown or disabled category/type must be a localized safe 404 or a clear empty state according to the established product convention—never a broadened result set. Document the choice and test it. ### 2. One public inventory scope Implement an explicit reusable query scope/service, e.g. `PublicDiscoveryQuery` or appropriately named Eloquent scopes. Every public-search consumer must use it: navigation/card counters, `/locations`, map/list/grid, location/place/venue detail eligibility and booking final revalidation. It must require, according to actual schema/model semantics: - venue is active and soft-delete-safe; - venue passes public visibility requirements (verified, certificate valid and not suspended/rejected/high-risk); reuse/fix `publiclyDisplayable()` rather than duplicating partial conditions; - active eligible parent place and location; - public company/workspace publication constraints, without data leakage; - for hotel availability/counts, at least one active, eligible, bookable room or rental unit. Honor room block, maintenance and housekeeping readiness where they are part of the booking model. Do not broaden `NULL booking_type` as a permanent compatibility rule. Migrate legacy records to a canonical type/category mapping, then make the public scope strict. Provide a reviewed, idempotent migration/command/seed repair plan. ### 3. Canonical categories and super-admin publication control Make `categories` the single source of truth for public category definition: stable slug, booking type, name/translation, sort order and `is_active`. - Add an authenticated, authorization-protected super-admin management surface (use the existing admin convention) to activate/deactivate categories and, if appropriate, booking types. - Add confirmation, audit-log entry, clear active/inactive state and cache invalidation. - Deactivation must immediately remove the category from navigation, APIs, direct URLs, counters, maps, results, details and booking handoff. - Replace keyword `LIKE` category matching with stable mapping/foreign-key or a clearly defined transitional mapping. Do not match category by venue name or description in the final public path. ### 4. Complete hotel criteria Implement the retained controls end-to-end: - destination across country/city/location/place, with safe autocomplete; - check-in/check-out availability using the existing stays/bookings/room assignments/room blocks and unit model; avoid N+1 overlap checks; - adults, children (including ages if schema/product supports it), rooms and occupancy at the room/unit level; - real rate-plan/unit pricing in the requested/display currency, including a clear tax/fee policy; do not use a venue `price_per_hour` proxy for hotels; - valid hotel property types and active facilities via `venueFacilities.facility`; - approved/public review aggregates only, with minimum-rating and review-count filters; - explicit, implemented sorts: recommended, total price ascending/descending, rating, newest and distance only when user coordinates are actually available. If a control cannot be made truthful now, remove it from the public UI rather than leaving a decorative filter. ### 5. Counters and presentation Define the metric on every UI count and use batched queries from the shared scope. Examples: “properties”, “room types” and “available rooms for selected dates” are different metrics and must never be interchanged. - Navigation category count and hotel category-card count must use the same documented metric as the current result set when no dates are supplied. - With dates/guests, display an explicitly date-available result total. - Use paginator `total()` where the UI says total results, not `count()` for the current page. - Remove hard-coded availability/price fallback copy. Hide unavailable metrics or show a truthful localized empty state. - Make map, grid and list read the identical filtered result IDs. ### 6. Front-end behavior and accessibility Refactor `resources/views/web/locations.blade.php` so there is one form and one source of filter state. Eliminate duplicate `id="sort-select"` values. Use a normal GET submission that works without JavaScript; JavaScript may enhance it but must emit the canonical server contract. Preserve search criteria through: category → locations → location → place → venue detail → booking review. Use localized labels, accessible input labels, validation errors, URL history, clear/reset behavior and meaningful empty/no-availability states. Keep mobile layout responsive and do not reintroduce horizontal overflow. ## Tests required Add focused feature/model/browser tests using deterministic factories/fixtures. At minimum cover: 1. published active verified hotel with eligible unit appears; 2. non-hotel rental never appears under `category=hotel`; 3. disabled/unknown category and disabled booking type cannot be reached by URL; 4. inactive, soft-deleted, unverified, expired-certificate, suspended venue; 5. inactive parent place/location; inactive/blocked/dirty/maintenance room; 6. destination, valid/invalid dates, guest/room capacity, price, amenity, property type, rating, review count and each sort option; 7. booking overlap, room block and concurrent availability revalidation; 8. counter equality across navigation, category card, paginator total and map; 9. pagination preserves criteria; grid/list/map show the same IDs; 10. direct venue/location deep links and booking handoff obey the same scope; 11. super-admin category on/off authorization, audit logging and cache refresh; 12. non-JavaScript GET form behavior plus browser tests for the visible controls. Run the focused suite on PHP 8.3+ and report exact commands/results. If the current local runtime is not PHP 8.3+, configure/use the project-supported runtime; do not bypass platform checks. ## Deliverable At completion provide: 1. root-cause summary and the final canonical query contract; 2. changed files and migrations/data-repair steps; 3. a precise rollout order, cache/queue commands and rollback plan; 4. tests run and results; 5. any remaining product decisions that require owner approval (for example, canonical count semantics, tax display policy, or availability rules).