Files
orion/16.jinja2_migration_progress.md

520 lines
15 KiB
Markdown

# Jinja2 Migration Progress - Admin Panel
**Date:** October 20, 2025
**Project:** Multi-Tenant E-commerce Platform
**Goal:** Migrate from static HTML files to Jinja2 server-rendered templates
---
## 🎯 Current Status: DEBUGGING AUTH LOOP
We successfully set up the Jinja2 infrastructure but are experiencing authentication redirect loops. We're in the process of simplifying the auth flow to resolve this.
---
## ✅ What's Been Completed
### 1. Infrastructure Setup ✅
- [x] Added Jinja2Templates to `main.py`
- [x] Created `app/templates/` directory structure
- [x] Created `app/api/v1/admin/pages.py` for HTML routes
- [x] Integrated pages router into the main app
**Files Created:**
```
app/
├── templates/
│ ├── admin/
│ │ ├── base.html ✅ Created
│ │ ├── login.html ✅ Created
│ │ └── dashboard.html ✅ Created
│ └── partials/
│ ├── header.html ✅ Moved from static
│ └── sidebar.html ✅ Moved from static
└── api/
└── v1/
└── admin/
└── pages.py ✅ Created
```
### 2. Route Configuration ✅
**New Jinja2 Routes (working):**
- `/admin/` → redirects to `/admin/dashboard`
- `/admin/login` → login page (no auth)
- `/admin/dashboard` → dashboard page (requires auth)
- `/admin/vendors` → vendors page (requires auth)
- `/admin/users` → users page (requires auth)
**Old Static Routes (disabled):**
- Commented out admin routes in `app/routes/frontend.py`
- Old `/static/admin/*.html` routes no longer active
### 3. Exception Handler Updates ✅
- [x] Updated `app/exceptions/handler.py` to redirect HTML requests on 401
- [x] Added `_is_html_page_request()` helper function
- [x] Server-side redirects working for unauthenticated page access
### 4. JavaScript Updates ✅
Updated all JavaScript files to use new routes:
**Files Updated:**
- `static/admin/js/dashboard.js` - viewVendor() uses `/admin/vendors`
- `static/admin/js/login.js` - redirects to `/admin/dashboard`
- `static/admin/js/vendors.js` - auth checks use `/admin/login`
- `static/admin/js/vendor-edit.js` - all redirects updated
- `static/shared/js/api-client.js` - handleUnauthorized() uses `/admin/login`
### 5. Template Structure ✅
**Base Template (`app/templates/admin/base.html`):**
- Server-side includes for header and sidebar (no more AJAX loading!)
- Proper script loading order
- Alpine.js integration
- No more `partial-loader.js`
**Dashboard Template (`app/templates/admin/dashboard.html`):**
- Extends base template
- Uses Alpine.js `adminDashboard()` component
- Stats cards and recent vendors table
**Login Template (`app/templates/admin/login.html`):**
- Standalone page (doesn't extend base)
- Uses Alpine.js `adminLogin()` component
---
## ❌ Current Problem: Authentication Loop
### Issue Description
Getting infinite redirect loops in various scenarios:
1. After login → redirects back to login
2. On login page → continuous API calls to `/admin/auth/me`
3. Dashboard → redirects to login → redirects to dashboard
### Root Causes Identified
1. **Multiple redirect handlers fighting:**
- Server-side: `handler.py` redirects on 401 for HTML pages
- Client-side: `api-client.js` also redirects on 401
- Both triggering simultaneously
2. **Login page checking auth on init:**
- Calls `/admin/auth/me` on page load
- Gets 401 → triggers redirect
- Creates loop
3. **Token not being sent properly:**
- Token stored but API calls not including it
- Gets 401 even with valid token
### Latest Approach (In Progress)
Simplifying to minimal working version:
- Login page does NOTHING on init (no auth checking)
- API client does NOT redirect (just throws errors)
- Server ONLY redirects browser HTML requests (not API calls)
- One source of truth for auth handling
---
## 📝 Files Modified (Complete List)
### Backend Files
1. **`main.py`**
```python
# Added:
- Jinja2Templates import and configuration
- admin_pages router include at /admin prefix
```
2. **`app/api/main.py`** (unchanged - just includes v1 routes)
3. **`app/api/v1/admin/__init__.py`**
```python
# Added:
- import pages
- router.include_router(pages.router, tags=["admin-pages"])
```
4. **`app/api/v1/admin/pages.py`** (NEW FILE)
```python
# Contains:
- @router.get("/") - root redirect
- @router.get("/login") - login page
- @router.get("/dashboard") - dashboard page
- @router.get("/vendors") - vendors page
- @router.get("/users") - users page
```
5. **`app/routes/frontend.py`**
```python
# Changed:
- Commented out all /admin/ routes
- Left vendor and shop routes active
```
6. **`app/exceptions/handler.py`**
```python
# Added:
- 401 redirect logic for HTML pages
- _is_html_page_request() helper
# Status: Needs simplification
```
### Frontend Files
1. **`static/admin/js/login.js`**
```javascript
// Changed:
- Removed /static/admin/ paths
- Updated to /admin/ paths
- checkExistingAuth() logic
# Status: Needs simplification
```
2. **`static/admin/js/dashboard.js`**
```javascript
// Changed:
- viewVendor() uses /admin/vendors
# Status: Working
```
3. **`static/admin/js/vendors.js`**
```javascript
// Changed:
- checkAuth() redirects to /admin/login
- handleLogout() redirects to /admin/login
# Status: Not tested yet
```
4. **`static/admin/js/vendor-edit.js`**
```javascript
// Changed:
- All /static/admin/ paths to /admin/
# Status: Not tested yet
```
5. **`static/shared/js/api-client.js`**
```javascript
// Changed:
- handleUnauthorized() uses /admin/login
# Status: Needs simplification - causing loops
```
6. **`static/shared/js/utils.js`** (unchanged - working fine)
### Template Files (NEW)
1. **`app/templates/admin/base.html`** ✅
- Master layout with sidebar and header
- Script loading in correct order
- No partial-loader.js
2. **`app/templates/admin/login.html`** ✅
- Standalone login page
- Alpine.js adminLogin() component
3. **`app/templates/admin/dashboard.html`** ✅
- Extends base.html
- Alpine.js adminDashboard() component
4. **`app/templates/partials/header.html`** ✅
- Top navigation bar
- Updated logout link to /admin/login
5. **`app/templates/partials/sidebar.html`** ✅
- Side navigation menu
- Updated all links to /admin/* paths
---
## 🔧 Next Steps (Tomorrow)
### Immediate Priority: Fix Auth Loop
Apply the simplified approach from the last message:
1. **Simplify `login.js`:**
```javascript
// Remove all auth checking on init
// Just show login form
// Only redirect after successful login
```
2. **Simplify `api-client.js`:**
```javascript
// Remove handleUnauthorized() redirect logic
// Just throw errors, don't redirect
// Let server handle redirects
```
3. **Simplify `handler.py`:**
```javascript
// Only redirect browser HTML requests (text/html accept header)
// Don't redirect API calls (application/json)
// Don't redirect if already on login page
```
**Test Flow:**
1. Navigate to `/admin/login` → should show form (no loops)
2. Login → should redirect to `/admin/dashboard`
3. Dashboard → should load with sidebar/header
4. No console errors, no 404s for partials
### After Auth Works
1. **Create remaining page templates:**
- `app/templates/admin/vendors.html`
- `app/templates/admin/users.html`
- `app/templates/admin/vendor-edit.html`
2. **Test all admin flows:**
- Login ✓
- Dashboard ✓
- Vendors list
- Vendor create
- Vendor edit
- User management
3. **Cleanup:**
- Remove old static HTML files
- Remove `app/routes/frontend.py` admin routes completely
- Remove `partial-loader.js`
4. **Migrate vendor portal:**
- Same process for `/vendor/*` routes
- Create vendor templates
- Update vendor JavaScript files
---
## 📚 Key Learnings
### What Worked
1. ✅ **Server-side template rendering** - Clean, fast, no AJAX for partials
2. ✅ **Jinja2 integration** - Easy to set up, works with FastAPI
3. ✅ **Route separation** - HTML routes in `pages.py`, API routes separate
4. ✅ **Template inheritance** - `base.html` + `{% extends %}` pattern
### What Caused Issues
1. ❌ **Multiple redirect handlers** - Client + server both handling 401
2. ❌ **Auth checking on login page** - Created loops
3. ❌ **Complex error handling** - Too many places making decisions
4. ❌ **Path inconsistencies** - Old `/static/admin/` vs new `/admin/`
### Best Practices Identified
1. **Single source of truth for redirects** - Choose server OR client, not both
2. **Login page should be dumb** - No auth checking, just show form
3. **API client should be simple** - Fetch data, throw errors, don't redirect
4. **Server handles page-level auth** - FastAPI dependencies + exception handler
5. **Clear separation** - HTML pages vs API endpoints
---
## 🗂️ Project Structure (Current)
```
project/
├── main.py ✅ Updated
├── app/
│ ├── api/
│ │ ├── main.py ✅ Unchanged
│ │ └── v1/
│ │ └── admin/
│ │ ├── __init__.py ✅ Updated
│ │ ├── pages.py ✅ NEW
│ │ ├── auth.py ✅ Existing (API routes)
│ │ ├── vendors.py ✅ Existing (API routes)
│ │ └── dashboard.py ✅ Existing (API routes)
│ ├── routes/
│ │ └── frontend.py ⚠️ Partially disabled
│ ├── exceptions/
│ │ └── handler.py ⚠️ Needs simplification
│ └── templates/ ✅ NEW
│ ├── admin/
│ │ ├── base.html
│ │ ├── login.html
│ │ └── dashboard.html
│ └── partials/
│ ├── header.html
│ └── sidebar.html
└── static/
├── admin/
│ ├── js/
│ │ ├── login.js ⚠️ Needs simplification
│ │ ├── dashboard.js ✅ Updated
│ │ ├── vendors.js ✅ Updated
│ │ └── vendor-edit.js ✅ Updated
│ └── css/
│ └── tailwind.output.css ✅ Unchanged
└── shared/
└── js/
├── api-client.js ⚠️ Needs simplification
├── utils.js ✅ Working
└── icons.js ✅ Working
```
**Legend:**
- ✅ = Working correctly
- ⚠️ = Needs attention/debugging
- ❌ = Not working/causing issues
---
## 🐛 Debug Commands
### Clear localStorage (Browser Console)
```javascript
localStorage.clear();
```
### Check stored tokens
```javascript
console.log('admin_token:', localStorage.getItem('admin_token'));
console.log('admin_user:', localStorage.getItem('admin_user'));
```
### Test API call manually
```javascript
fetch('/api/v1/admin/auth/me', {
headers: {
'Authorization': `Bearer ${localStorage.getItem('admin_token')}`
}
}).then(r => r.json()).then(d => console.log(d));
```
### Check current route
```javascript
console.log('Current path:', window.location.pathname);
console.log('Full URL:', window.location.href);
```
---
## 📖 Reference: Working Code Snippets
### Minimal Login.js (To Try Tomorrow)
```javascript
function adminLogin() {
return {
dark: false,
credentials: { username: '', password: '' },
loading: false,
error: null,
success: null,
errors: {},
init() {
this.dark = localStorage.getItem('theme') === 'dark';
// NO AUTH CHECKING - just show form
},
async handleLogin() {
if (!this.validateForm()) return;
this.loading = true;
try {
const response = await fetch('/api/v1/admin/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: this.credentials.username,
password: this.credentials.password
})
});
const data = await response.json();
if (!response.ok) throw new Error(data.message);
localStorage.setItem('admin_token', data.access_token);
localStorage.setItem('admin_user', JSON.stringify(data.user));
this.success = 'Login successful!';
setTimeout(() => window.location.href = '/admin/dashboard', 500);
} catch (error) {
this.error = error.message;
} finally {
this.loading = false;
}
}
}
}
```
### Simplified API Client Request Method
```javascript
async request(endpoint, options = {}) {
const url = `${this.baseURL}${endpoint}`;
const config = {
...options,
headers: this.getHeaders(options.headers)
};
const response = await fetch(url, config);
const data = await response.json();
if (!response.ok) {
throw new Error(data.message || 'Request failed');
}
return data;
// NO REDIRECT LOGIC HERE!
}
```
### Simplified Exception Handler
```python
if exc.status_code == 401:
accept_header = request.headers.get("accept", "")
is_browser = "text/html" in accept_header
if is_browser and not request.url.path.endswith("/login"):
if request.url.path.startswith("/admin"):
return RedirectResponse(url="/admin/login", status_code=302)
# Return JSON for API calls
return JSONResponse(status_code=exc.status_code, content=exc.to_dict())
```
---
## 💡 Questions to Answer Tomorrow
1. Does the simplified auth flow work without loops?
2. Can we successfully login and access dashboard?
3. Are tokens being sent correctly in API requests?
4. Do we need the auth check on login page at all?
5. Should we move ALL redirect logic to server-side?
---
## 🎯 Success Criteria
The migration will be considered successful when:
- [ ] Login page loads without loops
- [ ] Login succeeds and redirects to dashboard
- [ ] Dashboard displays with sidebar and header
- [ ] No 404 errors for partials
- [ ] Icons display correctly
- [ ] Stats cards load data from API
- [ ] Navigation between admin pages works
- [ ] Logout works correctly
---
**End of Session - October 20, 2025**
Good work today! We made significant progress on the infrastructure. Tomorrow we'll resolve the auth loop and complete the admin panel migration.