6.2 KiB
task, cycles, context, private, started, finished
| task | cycles | context | private | started | finished |
|---|---|---|---|---|---|
| enable store owner to delete and edit stores he owns in manage stores admin page | 5 | true | false | 2026-05-16T00:00:00Z | 2026-05-16T00:01:00Z |
files
- resources/js/Pages/ManageStoresAdmin.vue — frontend page; already has canModifyStore checks and edit/delete buttons conditioned on
store.user_can_manage; no changes needed unless navigation from service grid is added - resources/js/Pages/Fragments/Home/HomeStoreOwner.vue [lines 34-60] — store owner home page services grid; has "My Stores" in
balanceFooterItems→ ManageStoresAdmin but NOT in the services grid - app/Http/Controllers/Market/StoreController.php [lines 626-732] —
update()method; allows edit if$store->owner_id === $user->idbut does NOT check store_managers pivot table, causing a mismatch withuser_can_manageflag - app/Http/Controllers/Market/StoreController.php [lines 1403-1435] —
deleteStore_Admin()method; allows owner to delete but usescatch (Exception $e)without backslash (namespace bug) and does NOT check store_managers pivot - app/Http/Controllers/Market/StoreController.php [lines 1437-1475] —
toggleStoreStatus_Admin()method; samecatch (Exception $e)bug - app/Http/Controllers/Market/StoreController.php [lines 1297-1353] —
listStores_Admin(): setsuser_can_manage = truewhen user is inallowedUserIds(includes owner, manager_id, and managers pivot) — but backend edit/delete endpoints don't fully mirror this logic
steps
-
In
StoreController.phpdeleteStore_Admin()(line ~1425): fixcatch (Exception $e)→catch (\Exception $e)(namespace issue; unqualifiedExceptionin a namespace resolves toApp\Http\Controllers\Market\Exceptionwhich doesn't exist) -
In
StoreController.phptoggleStoreStatus_Admin()(line ~1468): same fix —catch (Exception $e)→catch (\Exception $e) -
In
StoreController.phpdeleteStore_Admin()(line ~1423): after$allowedIdsis defined, add a check for managers pivot so any user listed instore_managerstable can also delete (currently only checksowner_idandmanager_idcolumns). Add:$isManagerViaPivot = $store->managers()->whereIn('user_id', $allowedIds)->exists(); if (!in_array($store->owner_id, $allowedIds) && !in_array($store->manager_id, $allowedIds) && !$isManagerViaPivot) { return ResponseHelper::returnUnauthorized(); } -
In
StoreController.phpupdate()(line ~648): the permission check only allows: isBig3, isParentOfOwner, or$store->owner_id === $user->id. Add store managers pivot check so managers assigned via pivot can also edit:$isStoreOwner = $acctType === UserTypes::STORE_OWNER; $isManagerViaPivot = $store->managers()->where('user_id', $user->id)->exists(); $isDirectManager = $store->manager_id === $user->id; if (!$isBig3 && !$isParentOfOwner && $store->owner_id !== $user->id && !$isDirectManager && !$isManagerViaPivot) { return response()->json(['error' => 'Unauthorized to modify this store'], 403); }Also guard
owner_id/manager_idchanges for STORE_OWNER in update — they should not be able to reassign ownership away from themselves (mirror the restriction instore()create method):if ($isStoreOwner) { $ownerId = $store->owner_id; // lock owner to self } -
In
HomeStoreOwner.vueservicescomputed (line ~34): add a "Manage Stores" service button so store owners can navigate directly from their service grid (currently only accessible via balance box footer):{ icon: 'https://cdn.jsdelivr.net/gh/telemagnadon/obj-vault-3a@v2026.05.14-vendor-2/a/85605eacd4c8.bin', title: 'Manage Stores', pagename: 'ManageStoresAdmin', },
context
StoreController.php — update() permission block (lines 644-651)
$acctType = $user->acct_type instanceof UserTypes ? $user->acct_type : UserTypes::tryFrom($user->acct_type);
$isBig3 = in_array($acctType, [UserTypes::ULTIMATE, UserTypes::SUPER_OPERATOR, UserTypes::OPERATOR]);
// Permission check: Big 3 or Parent of Owner/Manager
$isParentOfOwner = UserPermissions::isDescendantOfCurrentUser($store->owner_id);
if (!$isBig3 && !$isParentOfOwner && $store->owner_id !== $user->id) {
return response()->json(['error' => 'Unauthorized to modify this store'], 403);
}
StoreController.php — deleteStore_Admin() (lines 1403-1435)
public function deleteStore_Admin(Request $request)
{
...
$isUltimate = $user->acct_type === UserTypes::ULTIMATE;
if (!$isUltimate) {
$descendants = $user->getAllDescendants();
$descendantIds = $descendants->pluck('id')->toArray();
$allowedIds = array_merge([$user->id], $descendantIds);
if (!in_array($store->owner_id, $allowedIds) && !in_array($store->manager_id, $allowedIds)) {
return ResponseHelper::returnUnauthorized();
}
}
$store->delete();
...
} catch (Exception $e) { // BUG: missing backslash
StoreController.php — listStores_Admin() user_can_manage logic (lines 1330-1334)
->each(function ($s) use ($allowedUserIds) {
$s->user_can_manage = in_array($s->owner_id, $allowedUserIds)
|| in_array($s->manager_id, $allowedUserIds)
|| $s->managers->pluck('user_id')->intersect($allowedUserIds)->isNotEmpty();
unset($s->managers);
});
The user_can_manage flag includes managers-pivot check, but update() and deleteStore_Admin() do not — this is the root mismatch that causes store managers to see buttons but get 403.
HomeStoreOwner.vue — services array (lines 34-60)
Currently has: Create Store, Import Products, New Product, My Products, POS Keys.
"My Stores" exists only in balanceFooterItems. Adding it to services makes it more discoverable.
Store model relations
$store->managers() returns StoreManager records (pivot model at app/Models/Market/StoreManager.php).
$store->managerUsers() returns User models via the pivot.
notes
- dictionary: /home/josh/development/personal/BukidBountyApp/ai-docs/dictionary.md
- linters: none detected
- constraints: Hypervel (not Laravel) — use
Hypervel\Support\Facades\*notIlluminate\*; table name for stores isstr(abbreviated);declare(strict_types=1)is in effect