--- 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": "", "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": "", "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 = '') 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": "", "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='')` — expect 25 - `SELECT COUNT(*) FROM pos_access_keys WHERE store_id=(SELECT id FROM str WHERE hashkey='')` — expect ≥ 1 - `SELECT COUNT(*) FROM pos_sessions WHERE store_id=(SELECT id FROM str WHERE hashkey='')` — 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: `` ## 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: // 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