feat: Implement comprehensive OAuth and email verification authentication system

- Add email verification with token-based validation
- Integrate Google, Facebook, and Yahoo OAuth providers
- Add OAuth configuration and email service modules
- Update User model with email_verified, oauth_provider, oauth_id fields
- Implement async password hashing/verification to prevent blocking
- Add database migration script for new user fields
- Create email verification page with professional UI
- Update login page with social login buttons (Google, Facebook, Yahoo)
- Add OAuth callback token handling
- Implement scroll-to-top navigation component
- Add 5-second real-time polling for Products and Services pages
- Enhance About page with Apple-style scroll animations
- Update Home and Contact pages with branding and business info
- Optimize API cache with prefix-based clearing
- Create comprehensive setup documentation and quick start guide
- Fix login performance with ThreadPoolExecutor for bcrypt operations

Performance improvements:
- Login time optimized to ~220ms with async password verification
- Real-time data updates every 5 seconds
- Non-blocking password operations

Security enhancements:
- Email verification required for new accounts
- OAuth integration for secure social login
- Verification tokens expire after 24 hours
- Password field nullable for OAuth users
This commit is contained in:
2026-02-04 00:41:16 -06:00
parent 72f17c8be9
commit 9a7b00649b
22 changed files with 2273 additions and 128 deletions

View File

@@ -1,6 +1,6 @@
// Simple in-memory cache for API responses
const cache = new Map();
const CACHE_DURATION = 60000; // 60 seconds
const CACHE_DURATION = 30000; // 30 seconds (reduced from 60)
export const getCached = (key) => {
const cached = cache.get(key);
@@ -24,7 +24,19 @@ export const setCache = (key, data) => {
export const clearCache = (key) => {
if (key) {
cache.delete(key);
// If key ends with a dash, clear all keys starting with that prefix
if (key.endsWith("-")) {
const prefix = key;
const keysToDelete = [];
for (const [cacheKey] of cache) {
if (cacheKey.startsWith(prefix)) {
keysToDelete.push(cacheKey);
}
}
keysToDelete.forEach((k) => cache.delete(k));
} else {
cache.delete(key);
}
} else {
cache.clear();
}