Add bnfexpress signed admin client and AI Agent Filament UI
- Modules\Shared\Bnfexpress\BnfexpressAdminClient: HMAC-signed HTTP client for bnfexpress's admin API (EV FAQs, agent instructions, chat history), with a bnfexpress:smoke-test command and full unit coverage. - New ai-agent module: Filament pages to manage EV FAQs, publish/roll back agent instruction versions, and browse EV chat history + transcripts. - New manage_ai_agent permission (super_admin/admin). - Recorded .ai/rules for the client's auth scheme and non-Resource Filament page/table testing gotchas.
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
---
|
||||
paths:
|
||||
- 'app-modules/shared/src/Bnfexpress/**'
|
||||
---
|
||||
|
||||
# Bnfexpress
|
||||
|
||||
## bnfexpress admin API calls go through BnfexpressAdminClient
|
||||
Signed backend-to-backend calls to bnfexpress's admin API (EV FAQs, agent instructions, chat history) go through `Modules\Shared\Bnfexpress\BnfexpressAdminClient` — do not call `Http::` directly against BNFEXPRESS_AI_API_URL elsewhere.
|
||||
|
||||
Auth is HMAC, not JWT/session: X-Client-Id/X-Timestamp/X-Signature per `BnfexpressSignature::headers()`, signed over `METHOD\nPATH\nTIMESTAMP\nRAW_BODY` (path only, no query string; empty string body for GET/DELETE). Timestamps must be generated fresh per request (server rejects >300s skew) — never cache/reuse a signed header set.
|
||||
|
||||
Config lives in `config('services.bnfexpress')` (BNFEXPRESS_AI_API_URL/CLIENT_ID/CLIENT_SECRET in .env). The client_secret must match bnfexpress's own ADMIN_SERVICE_CLIENTS entry for ev_admin — get it from whoever manages that deploy.
|
||||
|
||||
Non-2xx responses throw `BnfexpressApiException` carrying the gateway's `{"detail": "..."}` message. Verify signing end-to-end with `php artisan bnfexpress:smoke-test` before wiring up any UI.
|
||||
@@ -0,0 +1,8 @@
|
||||
# Project Rules Index
|
||||
|
||||
Before planning or editing, find the row whose globs match the file's path and read that rule file.
|
||||
|
||||
| Applies to | Rule file |
|
||||
| --- | --- |
|
||||
| app-modules/shared/src/Bnfexpress/** | .ai/rules/bnfexpress.md |
|
||||
| app-modules/*/src/Filament/Pages/** | .ai/rules/pages.md |
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
paths:
|
||||
- 'app-modules/*/src/Filament/Pages/**'
|
||||
---
|
||||
|
||||
# Pages
|
||||
|
||||
## Non-Resource Filament pages need an explicit table-rendering view + deferLoading-aware tests
|
||||
A `Filament\Pages\Page implements HasTable` (not a Resource) does NOT render its table automatically — it must set `protected string $view = '<module>::filament.pages.<slug>';` pointing at a Blade file containing `<x-filament-panels::page>{{ $this->table }}</x-filament-panels::page>` (see `ManageFaqs`/`ViewEvChatHistory`/`BookingsRevenueReport`). Omitting this silently renders an empty page — no error, just a blank `fi-page-content`.
|
||||
|
||||
Filament v4 tables default to deferred loading. In Pest/Livewire tests, call `->loadTable()` before any `assertSee()`/`assertCanSeeTableRecords()` on a freshly-mounted component, or the table body won't be in the rendered HTML yet.
|
||||
|
||||
For custom-data (`->records()`-backed, non-Eloquent) tables: use `->callTableAction($name, $record, data: [...])` / `->mountTableAction(...)` (not the generic `->callAction()`, which targets page-level actions and misses table header/record actions), and use `->assertMountedActionModalSee(...)` to check `->modalContent()` output — modal content is lazily rendered and won't appear in a plain `->html()`/`->assertSee()` snapshot even after mounting the action. See `[[project_internachi_modular]]`-style module layout in `app-modules/ai-agent`.
|
||||
Reference in New Issue
Block a user