refactor: migrate main.py to modular routers and add project roadmap
CI / Test (Python 3.11) (push) Has been cancelled
CI / Test (Python 3.12) (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Type Check (push) Has been cancelled
CI / Summary (push) Has been cancelled

- Migrated monolithic main.py to feature-scoped routers in app/routers/
- Added GEMINI.md for project context and AI instructional guidelines
- Updated README.md with a comprehensive modernization plan (SQL migration, robust scraping DSL, frontend modernization)
- Improved authentication with cookie support and modular JS
- Updated test suite and documentation
This commit is contained in:
root
2026-03-24 10:12:04 +00:00
parent 1b5d7f9238
commit d4d8d8a3b6
42 changed files with 4518 additions and 2426 deletions
+73 -7
View File
@@ -5,9 +5,74 @@
// Use relative path for API
const AUTH_API_BASE = '/api';
const COOKIE_NAME = 'auth_token';
const COOKIE_MAX_AGE = 60 * 60 * 24 * 7; // 7 days
/**
* Set token in HTTP-only cookie (via server)
* Since we can't set HttpOnly cookies from JavaScript, we store in localStorage
* but also try to set a non-HttpOnly cookie for compatibility
*/
function setToken(token) {
// Store in localStorage as primary (for backward compatibility)
localStorage.setItem('auth_token', token);
// Also try to set cookie (non-HttpOnly, but better than nothing)
// Note: HttpOnly must be set by server, this is a fallback
const expires = new Date();
expires.setTime(expires.getTime() + COOKIE_MAX_AGE * 1000);
document.cookie = `${COOKIE_NAME}=${token};expires=${expires.toUTCString()};path=/;SameSite=Strict`;
}
/**
* Get token from cookie first, then fallback to localStorage
*/
function getToken() {
// Try cookie first
const cookieToken = getTokenFromCookie();
if (cookieToken) {
return cookieToken;
}
// Fallback to localStorage
return localStorage.getItem('auth_token');
}
/**
* Get token from cookie
*/
function getTokenFromCookie() {
const name = COOKIE_NAME + '=';
const decodedCookie = decodeURIComponent(document.cookie);
const cookieArray = decodedCookie.split(';');
for (let i = 0; i < cookieArray.length; i++) {
let cookie = cookieArray[i];
while (cookie.charAt(0) === ' ') {
cookie = cookie.substring(1);
}
if (cookie.indexOf(name) === 0) {
return cookie.substring(name.length, cookie.length);
}
}
return null;
}
/**
* Remove token from cookie and localStorage
*/
function removeToken() {
// Remove from localStorage
localStorage.removeItem('auth_token');
localStorage.removeItem('user');
// Remove cookie
document.cookie = `${COOKIE_NAME}=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/;`;
}
// Check if user is authenticated
async function checkAuth() {
const token = localStorage.getItem('auth_token');
const token = getToken();
const userStr = localStorage.getItem('user');
if (!token) {
@@ -31,8 +96,7 @@ async function checkAuth() {
return true;
} else {
// Token invalid, remove it and redirect
localStorage.removeItem('auth_token');
localStorage.removeItem('user');
removeToken();
redirectToLogin();
return false;
}
@@ -97,9 +161,8 @@ async function handleLogout() {
return;
}
// Remove token from localStorage
localStorage.removeItem('auth_token');
localStorage.removeItem('user');
// Remove token from localStorage and cookie
removeToken();
// Call logout endpoint
try {
@@ -114,7 +177,7 @@ async function handleLogout() {
// Add authorization header to all fetch requests
function addAuthHeader(options = {}) {
const token = localStorage.getItem('auth_token');
const token = getToken();
if (token) {
options.headers = options.headers || {};
options.headers['Authorization'] = `Bearer ${token}`;
@@ -135,6 +198,9 @@ window.showLoginPrompt = showLoginPrompt;
window.handleLogout = handleLogout;
window.authFetch = authFetch;
window.addAuthHeader = addAuthHeader;
window.getToken = getToken;
window.setToken = setToken;
window.removeToken = removeToken;
// Check authentication on page load
document.addEventListener('DOMContentLoaded', () => {