174 lines
8.9 KiB
Markdown
174 lines
8.9 KiB
Markdown
---
|
||
task: Seed real agricultural demo products, create a named demo store, assign products to the store, and set up a POS access key — all via the performance seeder API so no server-side code changes are needed
|
||
cycles: 3
|
||
context: true
|
||
private: false
|
||
started: 2026-05-16T00:00:00Z
|
||
finished: 2026-05-16T00:04:00Z
|
||
---
|
||
|
||
## files
|
||
- `app/Http/Controllers/Market/PerformanceController.php` — seeder endpoints already exist; use these instead of writing new code
|
||
- `routes/api.php` — perf endpoints: `POST /api/perf/seed/stores`, `POST /api/perf/seed/products`, `POST /api/perf/pos/simulate`
|
||
- `.env` — needs `PERF_API_TOKEN` and `PERF_ACTOR_HASH` set (check if already configured)
|
||
- `resources/js/Pages/ManageProductsAdmin.vue` — can verify products after seed
|
||
- `resources/js/Pages/PosMain.vue` — target for POS demo verification
|
||
|
||
## steps
|
||
### Step 0 — Verify perf API is enabled
|
||
1. Check `.env` for `PERF_API_TOKEN` and `PERF_ACTOR_HASH`. If missing:
|
||
- Set `PERF_API_TOKEN=bukid-demo-seed-2026` in `.env`
|
||
- Set `PERF_ACTOR_HASH` to the hashkey of the ULTIMATE user account (query: `SELECT hashkey FROM users WHERE acct_type='ULTIMATE' LIMIT 1` via UltimateConsole or direct DB)
|
||
2. Test with: `curl -s -H "X-Perf-Token: bukid-demo-seed-2026" http://localhost:9522/api/perf/ping`
|
||
- Expect `{"ok":true}`. If 403, token mismatch. If connection refused, server is down (task must wait for server).
|
||
|
||
### Step 1 — Create a demo store owner account (if the `099` store owner account doesn't own any store yet)
|
||
- Via the app UI or via Ultimate console SQL: confirm the store owner `099` (mobile) has a store. If not, proceed to create one.
|
||
|
||
### Step 2 — Create the demo store via perf API
|
||
```bash
|
||
curl -s -X POST http://localhost:9522/api/perf/seed/stores \
|
||
-H "Content-Type: application/json" \
|
||
-H "X-Perf-Token: bukid-demo-seed-2026" \
|
||
-d '{
|
||
"count": 1,
|
||
"owner_hash": "<STORE_OWNER_099_HASHKEY>",
|
||
"category": "Agri-Market",
|
||
"prefix": "BukidBounty Fresh Market"
|
||
}'
|
||
```
|
||
Note the returned store hashkey as `DEMO_STORE_HASH`.
|
||
|
||
### Step 3 — Seed 25 real agricultural products via perf API
|
||
```bash
|
||
curl -s -X POST http://localhost:9522/api/perf/seed/products \
|
||
-H "Content-Type: application/json" \
|
||
-H "X-Perf-Token: bukid-demo-seed-2026" \
|
||
-d '{
|
||
"count": 25,
|
||
"target_store_hash": "<DEMO_STORE_HASH>",
|
||
"attach_to_store": true,
|
||
"prefix": ""
|
||
}'
|
||
```
|
||
|
||
**However**, the perf seeder creates synthetic product names like "Product-0001". For demo quality, the products need realistic agricultural names. Therefore, instead of the perf seeder for products, **write a standalone Node.js or PHP artisan seed script** that creates the following 25 products directly via the app's own API endpoints (POST `/Products/Admin/New/` and `POST /Products/AssignToStore/`):
|
||
|
||
**Product list (agricultural, Bukidnon/Philippines context):**
|
||
1. Organic White Rice (25kg sack) — ₱1,200 — unit: sack
|
||
2. Organic Brown Rice (5kg) — ₱280 — unit: kg
|
||
3. White Corn Grits — ₱85 — unit: kg
|
||
4. Yellow Corn (fresh ears) — ₱35 — unit: piece
|
||
5. Fresh Kangkong (Water Spinach) — ₱25 — unit: bundle
|
||
6. Pechay (Bok Choy) — ₱30 — unit: bundle
|
||
7. Ampalaya (Bitter Gourd) — ₱60 — unit: kg
|
||
8. Sitaw (String Beans) — ₱55 — unit: bundle
|
||
9. Kamote (Sweet Potato) — ₱40 — unit: kg
|
||
10. Gabi (Taro Root) — ₱50 — unit: kg
|
||
11. Sayote (Chayote) — ₱45 — unit: kg
|
||
12. Labanos (Radish) — ₱30 — unit: bundle
|
||
13. Fresh Tomatoes — ₱70 — unit: kg
|
||
14. Carabao Mango (green) — ₱90 — unit: kg
|
||
15. Banana (Latundan) — ₱65 — unit: hand
|
||
16. Pineapple (Bukidnon) — ₱80 — unit: piece
|
||
17. Native Chicken (live) — ₱350 — unit: piece
|
||
18. Free-range Eggs — ₱12 — unit: piece
|
||
19. Fresh Tilapia — ₱130 — unit: kg
|
||
20. Bangus (Milkfish) — ₱180 — unit: kg
|
||
21. Carabao Milk (1L) — ₱120 — unit: liter
|
||
22. Coconut Oil (Virgin, 1L) — ₱250 — unit: bottle
|
||
23. Organic Peanuts (roasted) — ₱95 — unit: 250g pack
|
||
24. Muscovado Sugar — ₱110 — unit: 250g pack
|
||
25. Fresh Turmeric (Luyang Dilaw) — ₱60 — unit: 100g pack
|
||
|
||
**Implementation approach for the seed script:**
|
||
|
||
Write a PHP artisan command `php artisan demo:seed-products` in `app/Console/Commands/SeedDemoProducts.php`:
|
||
- The command should authenticate as the ULTIMATE user (via `Auth::loginUsingId($ultimateUserId)`)
|
||
- For each product: call `ProductController@createNew_Admin` logic directly (or use Eloquent to create `Product` + attach to `prd_str`)
|
||
- Use categories: Fresh Produce, Livestock & Poultry, Seafood, Grains & Cereals, Processed Goods
|
||
- Set `is_active=true`, realistic prices, realistic `available` stock (50–500 units)
|
||
- After creating each product globally, attach to `DEMO_STORE_HASH` via the prd_str pivot: `Store::find($store->id)->products()->attach($product->id, ['price'=>$price, 'available'=>$stock, 'is_active'=>true])`
|
||
- Print summary table on completion
|
||
|
||
### Step 4 — Set up POS Access Key for the demo store
|
||
After the store exists, create a POS access key via the UI (`/pos-access-keys`) or directly:
|
||
```sql
|
||
INSERT INTO pos_access_keys (hashkey, access_key, terminal_name, store_id, is_active, created_by, updated_by, created_at, updated_at)
|
||
SELECT
|
||
CONCAT(UUID(), REPEAT(MD5(RAND()), 3)) as hashkey,
|
||
CONCAT('PK-DEMO-', UPPER(LEFT(MD5(RAND()), 8))) as access_key,
|
||
'Demo Counter 1' as terminal_name,
|
||
(SELECT id FROM str WHERE hashkey = '<DEMO_STORE_HASH>') as store_id,
|
||
1 as is_active,
|
||
(SELECT id FROM users WHERE acct_type='ULTIMATE' LIMIT 1) as created_by,
|
||
(SELECT id FROM users WHERE acct_type='ULTIMATE' LIMIT 1) as updated_by,
|
||
NOW() as created_at,
|
||
NOW() as updated_at;
|
||
```
|
||
Record the `access_key` value (starts with `PK-`) for use in POS demo.
|
||
|
||
### Step 5 — Simulate a POS session to generate demo history
|
||
```bash
|
||
curl -s -X POST http://localhost:9522/api/perf/pos/simulate \
|
||
-H "Content-Type: application/json" \
|
||
-H "X-Perf-Token: bukid-demo-seed-2026" \
|
||
-d '{
|
||
"store_hash": "<DEMO_STORE_HASH>",
|
||
"items": 5,
|
||
"cycles": 10,
|
||
"complete": true
|
||
}'
|
||
```
|
||
This creates 10 completed POS transactions with 5 items each, giving the POS History page real data.
|
||
|
||
### Step 6 — Verify via UltimateConsole SQL
|
||
Run these queries in UltimateConsole to confirm:
|
||
- `SELECT COUNT(*) FROM prd_items WHERE is_active=1` — expect ≥ 25
|
||
- `SELECT COUNT(*) FROM prd_str WHERE store_id=(SELECT id FROM str WHERE hashkey='<DEMO_STORE_HASH>')` — expect 25
|
||
- `SELECT COUNT(*) FROM pos_access_keys WHERE store_id=(SELECT id FROM str WHERE hashkey='<DEMO_STORE_HASH>')` — expect ≥ 1
|
||
- `SELECT COUNT(*) FROM pos_sessions WHERE store_id=(SELECT id FROM str WHERE hashkey='<DEMO_STORE_HASH>')` — expect ≥ 10
|
||
|
||
### Step 7 — Update presentation credentials note
|
||
Record for Playwright capture script (`/tmp/bukid-presentation/capture.js`):
|
||
- Store owner login: mobile `099`, password `polomiko32!`
|
||
- Demo store name: `BukidBounty Fresh Market` (first result)
|
||
- POS access key: `PK-DEMO-XXXXXXXX` (recorded in Step 4)
|
||
- Store hashkey: `<DEMO_STORE_HASH>`
|
||
|
||
## context
|
||
```
|
||
// Perf API endpoints (from PerformanceController.php / routes/api.php):
|
||
// GET /api/perf/ping — health check
|
||
// POST /api/perf/seed/stores — { count, owner_hash?, category?, prefix? }
|
||
// POST /api/perf/seed/products — { count, target_store_hash?, attach_to_store?, prefix? }
|
||
// POST /api/perf/pos/simulate — { store_hash, items?, cycles?, complete? }
|
||
// Auth: X-Perf-Token: <PERF_API_TOKEN env>
|
||
|
||
// Table names (canonical):
|
||
// str = stores
|
||
// prd_items = products
|
||
// prd_str = product-store pivot (price, available, is_active, description)
|
||
// pos_access_keys = POS terminal keys (prefix PK- for real terminals)
|
||
// pos_sessions = POS sessions
|
||
|
||
// Product model: App\Models\Market\Product
|
||
// Store model: App\Models\Market\Store
|
||
// Product↔Store attach: $store->products()->attach($product->id, ['price'=>..., 'available'=>..., 'is_active'=>true])
|
||
// ModelSavingListener auto-sets hashkey, created_by, updated_by for Eloquent saves
|
||
|
||
// Artisan command skeleton:
|
||
// php artisan make:command SeedDemoProducts
|
||
// class SeedDemoProducts extends Command { protected $signature = 'demo:seed-products {store_hash}'; }
|
||
```
|
||
|
||
## notes
|
||
- dictionary: `ai-docs/dictionary.md`
|
||
- linters: none — this is a data seeding task, no Vue/PHP linting needed
|
||
- constraints:
|
||
- Server must be running before executing curl commands (user confirmed server is currently down — this task runs later)
|
||
- The artisan command approach is preferred over direct SQL inserts for products because ModelSavingListener auto-populates hashkey/created_by/updated_by
|
||
- For pos_access_keys and SQL steps, manually include all required fields (created_by, updated_by, created_at, updated_at, hashkey) since raw SQL bypasses Eloquent events
|
||
- Perf seeder prefix names are synthetic ("BukidBounty Fresh Market-001") — use the prefix param to set the store name close to desired then rename via UI if needed
|
||
- Do not truncate existing data before seeding; additive only
|