feat: rewrite lib/server/projects.ts to use Postgres instead of Firestore

This commit is contained in:
2026-02-18 01:24:50 +00:00
parent f7bbf2ea5e
commit 065f0f6b33

View File

@@ -1,5 +1,4 @@
import { FieldValue } from 'firebase-admin/firestore'; import { query } from '@/lib/db-postgres';
import { getAdminDb } from '@/lib/firebase/admin';
import type { import type {
ProjectPhase, ProjectPhase,
ProjectPhaseData, ProjectPhaseData,
@@ -21,14 +20,17 @@ export function toStage(stage?: string | null): ProjectStage {
} }
export async function loadPhaseContainers(projectId: string) { export async function loadPhaseContainers(projectId: string) {
const adminDb = getAdminDb(); const rows = await query<{ id: string; data: any }>(`
const projectRef = adminDb.collection('projects').doc(projectId); SELECT id, data FROM fs_projects WHERE id = $1 LIMIT 1
const snapshot = await projectRef.get(); `, [projectId]);
const doc = snapshot.data() || {};
if (rows.length === 0) throw new Error(`Project ${projectId} not found`);
const doc = rows[0].data || {};
const phaseData = (doc.phaseData ?? {}) as ProjectPhaseData; const phaseData = (doc.phaseData ?? {}) as ProjectPhaseData;
const phaseScores = (doc.phaseScores ?? {}) as ProjectPhaseScores; const phaseScores = (doc.phaseScores ?? {}) as ProjectPhaseScores;
const phaseHistory = Array.isArray(doc.phaseHistory) ? [...doc.phaseHistory] : []; const phaseHistory = Array.isArray(doc.phaseHistory) ? [...doc.phaseHistory] : [];
return { projectRef, phaseData, phaseScores, phaseHistory }; return { projectId, doc, phaseData, phaseScores, phaseHistory };
} }
interface PersistencePayload { interface PersistencePayload {
@@ -46,19 +48,19 @@ export async function persistPhaseArtifacts(
phaseHistory: Array<Record<string, unknown>>, phaseHistory: Array<Record<string, unknown>>,
) => PersistencePayload, ) => PersistencePayload,
) { ) {
const { projectRef, phaseData, phaseScores, phaseHistory } = await loadPhaseContainers(projectId); const { doc, phaseData, phaseScores, phaseHistory } = await loadPhaseContainers(projectId);
const payload = builder(phaseData, phaseScores, phaseHistory); const payload = builder(phaseData, phaseScores, phaseHistory);
await projectRef.set( const updated = {
{ ...doc,
phaseData: payload.phaseData, phaseData: payload.phaseData,
phaseScores: payload.phaseScores, phaseScores: payload.phaseScores,
phaseHistory: payload.phaseHistory, phaseHistory: payload.phaseHistory,
...(payload.nextPhase ? { currentPhase: payload.nextPhase, phaseStatus: 'completed' as const } : {}), updatedAt: new Date().toISOString(),
updatedAt: FieldValue.serverTimestamp(), ...(payload.nextPhase ? { currentPhase: payload.nextPhase, phaseStatus: 'completed' } : {}),
}, };
{ merge: true },
); await query(`
UPDATE fs_projects SET data = $1::jsonb WHERE id = $2
`, [JSON.stringify(updated), projectId]);
} }