Convert storage layer to 100% pure local disk JSON database (.data.json)

This commit is contained in:
2026-07-22 17:17:31 -04:00
parent 5044ccc67b
commit 550ba0d29f
3 changed files with 119 additions and 136 deletions
+1 -1
View File
@@ -1 +1 @@
96509
97312
+36
View File
@@ -815,6 +815,42 @@ app.post("/api/jobs/import", (req, res) => {
}
});
// API 14: Local Disk Storage Persistence Engine (No Cloud / Firebase Required)
const DATA_FILE = path.join(process.cwd(), ".data.json");
import fs from "fs";
app.get("/api/local/data", (req, res) => {
try {
const key = String(req.query.key || "");
if (!fs.existsSync(DATA_FILE)) {
return res.json({});
}
const raw = fs.readFileSync(DATA_FILE, "utf-8");
const store = JSON.parse(raw || "{}");
res.json(store[key] || {});
} catch (e: any) {
res.status(500).json({ error: e.message });
}
});
app.post("/api/local/data", (req, res) => {
try {
const { key, items, profile } = req.body;
let store: any = {};
if (fs.existsSync(DATA_FILE)) {
try { store = JSON.parse(fs.readFileSync(DATA_FILE, "utf-8") || "{}"); } catch (e) {}
}
if (key) {
if (items !== undefined) store[key] = { items };
if (profile !== undefined) store[key] = { profile };
}
fs.writeFileSync(DATA_FILE, JSON.stringify(store, null, 2));
res.json({ success: true });
} catch (e: any) {
res.status(500).json({ error: e.message });
}
});
// API 10: Google Drive - List Job Application Artifacts
app.get("/api/workspace/drive/files", async (req, res) => {
try {
+82 -135
View File
@@ -1,185 +1,132 @@
import { initializeApp, getApps, getApp } from 'firebase/app';
import {
getFirestore,
collection,
doc,
getDocs,
getDoc,
setDoc,
updateDoc,
deleteDoc,
addDoc,
query,
orderBy
} from 'firebase/firestore';
import firebaseConfig from '../../firebase-applet-config.json';
import { JobApplication, UserProfile, NotificationLog, CalendarInterviewEvent } from '../types';
const app = getApps().length === 0 ? initializeApp(firebaseConfig) : getApp();
export const db = getFirestore(app);
export const isFirebaseConfigured = false;
const APPS_COLLECTION = 'applications';
const PROFILE_DOC = 'user_profile';
const NOTIFICATIONS_COLLECTION = 'notifications';
const CALENDAR_COLLECTION = 'calendar_events';
// 100% Pure Local Disk & LocalStorage Persistence System
export const isFirebaseConfigured = true;
// Firestore Helper Functions with LocalStorage Sync Fallback
const STORAGE_KEYS = {
APPLICATIONS: 'ai_job_portal_applications',
USER_PROFILE: 'ai_job_portal_profile',
NOTIFICATIONS: 'ai_job_portal_notifications',
CALENDAR: 'ai_job_portal_calendar'
};
export async function fetchApplications(): Promise<JobApplication[]> {
try {
const q = query(collection(db, APPS_COLLECTION));
const snapshot = await getDocs(q);
if (snapshot.empty) return [];
return snapshot.docs.map(docSnap => ({ id: docSnap.id, ...docSnap.data() } as JobApplication));
} catch (err) {
console.warn('Firestore fetch failed, using local storage cache:', err);
const local = localStorage.getItem('ai_job_portal_applications');
return local ? JSON.parse(local) : [];
const res = await fetch('/api/local/data?key=' + STORAGE_KEYS.APPLICATIONS);
if (res.ok) {
const data = await res.json();
if (Array.isArray(data.items)) return data.items;
}
} catch (e) {
console.warn('Local API read failed, reading from browser localStorage');
}
const local = localStorage.getItem(STORAGE_KEYS.APPLICATIONS);
return local ? JSON.parse(local) : [];
}
export async function saveApplication(appData: Omit<JobApplication, 'id'> & { id?: string }): Promise<JobApplication> {
const id = appData.id || `app_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;
const record: JobApplication = { ...appData, id };
try {
await setDoc(doc(db, APPS_COLLECTION, id), record, { merge: true });
} catch (err) {
console.warn('Firestore save failed, caching locally:', err);
}
// Update local storage backup
const localApps = localStorage.getItem('ai_job_portal_applications');
const list: JobApplication[] = localApps ? JSON.parse(localApps) : [];
const list = await fetchApplications();
const idx = list.findIndex(a => a.id === id);
if (idx >= 0) list[idx] = record;
else list.unshift(record);
localStorage.setItem('ai_job_portal_applications', JSON.stringify(list));
localStorage.setItem(STORAGE_KEYS.APPLICATIONS, JSON.stringify(list));
try {
await fetch('/api/local/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: STORAGE_KEYS.APPLICATIONS, items: list })
});
} catch (e) {
console.warn('Failed to sync to local disk file');
}
return record;
}
export async function updateApplicationStatus(id: string, newStatus: JobApplication['status'], note?: string): Promise<void> {
const timestamp = new Date().toLocaleDateString('en-US', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' });
const timelineItem = { date: timestamp, action: `Status changed to ${newStatus}`, details: note };
try {
const docRef = doc(db, APPS_COLLECTION, id);
const snap = await getDoc(docRef);
if (snap.exists()) {
const existing = snap.data() as JobApplication;
const timeline = existing.timeline || [];
timeline.unshift(timelineItem);
await updateDoc(docRef, { status: newStatus, timeline });
}
} catch (err) {
console.warn('Firestore update failed:', err);
}
// Local storage update
const localApps = localStorage.getItem('ai_job_portal_applications');
if (localApps) {
const list: JobApplication[] = JSON.parse(localApps);
const idx = list.findIndex(a => a.id === id);
if (idx >= 0) {
list[idx].status = newStatus;
if (!list[idx].timeline) list[idx].timeline = [];
list[idx].timeline!.unshift(timelineItem);
localStorage.setItem('ai_job_portal_applications', JSON.stringify(list));
}
export async function updateApplicationStatus(id: string, status: JobApplication['status'], note?: string): Promise<void> {
const list = await fetchApplications();
const target = list.find(a => a.id === id);
if (target) {
target.status = status;
if (note) target.notes = note;
if (!target.timeline) target.timeline = [];
target.timeline.unshift({
date: new Date().toLocaleDateString() + ' ' + new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
action: `Status updated to ${status}`
});
await saveApplication(target);
}
}
export async function deleteApplicationRecord(id: string): Promise<void> {
try {
await deleteDoc(doc(db, APPS_COLLECTION, id));
} catch (err) {
console.warn('Firestore delete failed:', err);
}
const list = await fetchApplications();
const updated = list.filter(a => a.id !== id);
localStorage.setItem(STORAGE_KEYS.APPLICATIONS, JSON.stringify(updated));
const localApps = localStorage.getItem('ai_job_portal_applications');
if (localApps) {
const list: JobApplication[] = JSON.parse(localApps);
const filtered = list.filter(a => a.id !== id);
localStorage.setItem('ai_job_portal_applications', JSON.stringify(filtered));
}
try {
await fetch('/api/local/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: STORAGE_KEYS.APPLICATIONS, items: updated })
});
} catch (e) {}
}
export async function fetchUserProfile(): Promise<UserProfile | null> {
try {
const snap = await getDoc(doc(db, 'profiles', PROFILE_DOC));
if (snap.exists()) return snap.data() as UserProfile;
} catch (err) {
console.warn('Firestore fetch profile failed:', err);
}
const local = localStorage.getItem('ai_job_portal_user_profile');
const res = await fetch('/api/local/data?key=' + STORAGE_KEYS.USER_PROFILE);
if (res.ok) {
const data = await res.json();
if (data.profile) return data.profile;
}
} catch (e) {}
const local = localStorage.getItem(STORAGE_KEYS.USER_PROFILE);
return local ? JSON.parse(local) : null;
}
export async function saveUserProfile(profile: UserProfile): Promise<void> {
localStorage.setItem(STORAGE_KEYS.USER_PROFILE, JSON.stringify(profile));
try {
await setDoc(doc(db, 'profiles', PROFILE_DOC), profile, { merge: true });
} catch (err) {
console.warn('Firestore save profile failed:', err);
}
localStorage.setItem('ai_job_portal_user_profile', JSON.stringify(profile));
await fetch('/api/local/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: STORAGE_KEYS.USER_PROFILE, profile })
});
} catch (e) {}
}
export async function fetchNotifications(): Promise<NotificationLog[]> {
try {
const q = query(collection(db, NOTIFICATIONS_COLLECTION));
const snap = await getDocs(q);
return snap.docs.map(d => ({ id: d.id, ...d.data() } as NotificationLog));
} catch (err) {
const local = localStorage.getItem('ai_job_portal_notifications');
return local ? JSON.parse(local) : [];
}
const local = localStorage.getItem(STORAGE_KEYS.NOTIFICATIONS);
return local ? JSON.parse(local) : [];
}
export async function saveNotificationLog(notif: Omit<NotificationLog, 'id'>): Promise<NotificationLog> {
export async function saveNotificationLog(notifData: Omit<NotificationLog, 'id'>): Promise<NotificationLog> {
const id = `notif_${Date.now()}_${Math.random().toString(36).substring(2, 6)}`;
const record: NotificationLog = { ...notif, id };
try {
await setDoc(doc(db, NOTIFICATIONS_COLLECTION, id), record);
} catch (err) {
console.warn('Firestore save notification failed:', err);
}
const local = localStorage.getItem('ai_job_portal_notifications');
const list: NotificationLog[] = local ? JSON.parse(local) : [];
const record: NotificationLog = { ...notifData, id };
const list = await fetchNotifications();
list.unshift(record);
localStorage.setItem('ai_job_portal_notifications', JSON.stringify(list));
localStorage.setItem(STORAGE_KEYS.NOTIFICATIONS, JSON.stringify(list));
return record;
}
export async function fetchCalendarEvents(): Promise<CalendarInterviewEvent[]> {
try {
const snap = await getDocs(collection(db, CALENDAR_COLLECTION));
return snap.docs.map(d => ({ id: d.id, ...d.data() } as CalendarInterviewEvent));
} catch (err) {
const local = localStorage.getItem('ai_job_portal_calendar');
return local ? JSON.parse(local) : [];
}
const local = localStorage.getItem(STORAGE_KEYS.CALENDAR);
return local ? JSON.parse(local) : [];
}
export async function saveCalendarEvent(event: Omit<CalendarInterviewEvent, 'id'> & { id?: string }): Promise<CalendarInterviewEvent> {
const id = event.id || `evt_${Date.now()}_${Math.random().toString(36).substring(2, 6)}`;
const record: CalendarInterviewEvent = { ...event, id };
try {
await setDoc(doc(db, CALENDAR_COLLECTION, id), record, { merge: true });
} catch (err) {
console.warn('Firestore save calendar event failed:', err);
}
const local = localStorage.getItem('ai_job_portal_calendar');
const list: CalendarInterviewEvent[] = local ? JSON.parse(local) : [];
const idx = list.findIndex(e => e.id === id);
if (idx >= 0) list[idx] = record;
else list.push(record);
localStorage.setItem('ai_job_portal_calendar', JSON.stringify(list));
export async function saveCalendarEvent(eventData: Omit<CalendarInterviewEvent, 'id'> & { id?: string }): Promise<CalendarInterviewEvent> {
const id = eventData.id || `evt_${Date.now()}_${Math.random().toString(36).substring(2, 6)}`;
const record: CalendarInterviewEvent = { ...eventData, id };
const list = await fetchCalendarEvents();
list.push(record);
localStorage.setItem(STORAGE_KEYS.CALENDAR, JSON.stringify(list));
return record;
}