# Store Keeper API Fix - Production Issue Resolution

## Problem Summary
The Store Keeper module was working perfectly on localhost but failing on cPanel production with **400 Bad Request** errors on all API calls:
- `GET store_keeper_api.php?action=get_metrics` - 400
- `GET store_keeper_api.php?action=get_low_stock` - 400
- `GET store_keeper_api.php?action=get_expiring_soon` - 400
- `GET store_keeper_api.php?action=get_recent_activities` - 400

## Root Cause Analysis

### Issue #1: Missing Session Credentials in Fetch Calls ⛔
**The Primary Issue**

When JavaScript makes fetch requests to API endpoints using `fetch(url)` without the `credentials: 'include'` option, the browser does NOT automatically send session cookies. This happens especially in production environments.

**What was happening:**
```javascript
// BEFORE - No credentials
const response = await fetch('../backend/store_keeper_api.php?action=get_metrics');
const data = await response.json();  // Response is probably 401 Unauthorized
```

The API checks: `if (!empty($_SESSION['store_keeper_id']))` - but the session cookie wasn't sent, so `$_SESSION` was empty, resulting in a 401 error that got converted to 400.

**The Fix:**
```javascript
// AFTER - With credentials
const response = await fetch('../backend/store_keeper_api.php?action=get_metrics', {
    credentials: 'include',  // Send cookies with request
    headers: {
        'Content-Type': 'application/json'
    }
});

// Add error checking
if (!response.ok) {
    console.error('API error - HTTP', response.status);
    return;
}

const data = await response.json();
```

### Issue #2: No Response Status Checking ⚠️
The code was directly parsing JSON from potentially failed responses, causing silent failures or mishandled errors.

**Fix Applied:**
Added `if (!response.ok)` check before parsing JSON on all fetch calls.

### Issue #3: Session Initialization Before Headers 🔧
**Backend Issue**

In `store_keeper_api.php`, headers were being set before `session_start()`:

```php
// BEFORE - Wrong order
header('Content-Type: application/json');
session_start();  // Too late!
```

This could cause session issues on strict server configurations.

**Fix Applied:**
```php
// AFTER - Correct order
if (session_status() === PHP_SESSION_NONE) {
    session_start();  // Initialize session FIRST
}
header('Content-Type: application/json');  // Then set headers
```

## Files Modified

### Frontend Files (30+ fetch calls updated)

1. **dashboard.php** (5 fetch calls)
   - `loadMetrics()` - Gets dashboard metrics
   - `loadLowStockItems()` - Gets low stock items
   - `loadExpiringItems()` - Gets expiring items
   - `loadRecentActivities()` - Gets recent activities
   - `handleLogout()` - Logout API call

2. **inventory.php** (4 fetch calls)
   - `loadIngredientsList()` - Gets active ingredients
   - `loadInventory()` - Gets inventory list
   - `submitAdjustForm()` - POST to adjust inventory
   - `handleLogout()` - Logout API call

3. **expiry_wastage.php** (9 fetch calls)
   - `loadIngredientsList()` - Gets ingredients
   - `loadMetrics()` - Gets wastage metrics
   - `loadExpiryTracking()` - Gets expiry tracking
   - `submitAutoExpiredWastage()` - POST auto-log wastage
   - `saveExpiryDate()` - POST update expiry date
   - `loadWastageRecords()` - Gets wastage records
   - `submitWastageForm()` - POST log wastage
   - `fixOldRecords()` - Debug functions (3 API calls)
   - `handleLogout()` - Logout API call

4. **stock_receiving.php** (8 fetch calls)
   - `loadIngredientsList()` - Gets ingredients
   - `submitReceiveForm()` - POST add stock receiving
   - `logExpiredAsWastage()` - POST log wastage
   - `viewReceipt()` - GET receipt details
   - `viewPOForReceiving()` - GET PO details
   - `shortClosePO()` - POST close PO
   - `loadPendingShipments()` - GET pending shipments
   - `handleLogout()` - Logout API call

### Backend Files

1. **store_keeper_api.php**
   - Fixed session initialization order

## What Changed in Each Fetch Call

### Pattern for GET Requests
```javascript
// BEFORE
const response = await fetch('../backend/store_keeper_api.php?action=get_metrics');
const data = await response.json();

// AFTER
const response = await fetch('../backend/store_keeper_api.php?action=get_metrics', {
    credentials: 'include',
    headers: { 'Content-Type': 'application/json' }
});

if (!response.ok) {
    console.error('API error - HTTP', response.status);
    return;
}

const data = await response.json();
```

### Pattern for POST Requests
```javascript
// BEFORE
const response = await fetch('../backend/store_keeper_api.php?action=adjust_inventory', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload)
});
const data = await response.json();

// AFTER
const response = await fetch('../backend/store_keeper_api.php?action=adjust_inventory', {
    method: 'POST',
    credentials: 'include',  // Added this
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload)
});

if (!response.ok) {  // Added this check
    throw new Error('HTTP ' + response.status + ': Failed to adjust inventory');
}

const data = await response.json();
```

## Testing Checklist

After deployment to production, verify:

- [ ] Dashboard loads metrics (total ingredients, low stock, expiring, received today)
- [ ] Inventory page loads and displays items
- [ ] Can adjust inventory
- [ ] Expiry/Wastage page loads with metrics
- [ ] Can log wastage items
- [ ] Stock receiving form works
- [ ] Logout functionality works
- [ ] Browser console shows no 400 errors
- [ ] All API responses are successful

## Key Takeaways

1. **Always use `credentials: 'include'`** when making fetch requests to same-origin APIs that require authentication
2. **Always check `response.ok`** before parsing JSON to avoid silent failures
3. **Initialize sessions before setting headers** in PHP to ensure compatibility
4. **What works locally might fail in production** due to different server configurations
5. **Console logging is your friend** - use browser DevTools to check HTTP status codes

## Why This Happens Locally vs Production

**Localhost:**
- Browser might not enforce strict CORS
- Sessions stored in local temp directory
- Less strict header handling

**Production (cPanel):**
- Strict CORS and security settings
- Sessions stored in different location
- Requires explicit cookie handling in fetch requests
- Stricter PHP configuration

## References

- [MDN: fetch credentials](https://developer.mozilla.org/en-US/docs/Web/API/fetch#credentials)
- [MDN: Response.ok](https://developer.mozilla.org/en-US/docs/Web/API/Response/ok)
- [PHP: session_start](https://www.php.net/manual/en/function.session-start.php)
