AppForge: migrate off Supabase to external Postgres + Better Auth + local storage

- New Express + TypeScript backend (server/) with pg, Better Auth, local file storage
- De-Supabased Postgres schema (server/db) and TS reimplementations of DB functions
- Frontend data layer rewired to REST (rest-client + backend-client compat shim)
- Removed all Supabase references (code, config, deps, docs)
- New brand assets: gradient favicon/app icons + dark/white wordmark logos

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Leon Serfaty
2026-06-28 04:50:29 -04:00
co-authored by Claude Opus 4.8
commit 1a8b8ee5a0
271 changed files with 63734 additions and 0 deletions
+38
View File
@@ -0,0 +1,38 @@
import { Router } from 'express';
import multer from 'multer';
import { h } from '../lib/respond.js';
import { requireAuth, type AuthedRequest } from '../middleware/auth.js';
import { writeFile, deleteFile, listFiles, publicUrl } from '../lib/storage.js';
const r = Router();
const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 600 * 1024 * 1024 } });
// POST /storage/upload (multipart: bucket, path, file)
r.post('/upload', requireAuth, upload.single('file'), h(async (req: AuthedRequest) => {
const bucket = req.body.bucket as string;
const relPath = (req.body.path as string) || (req as any).file?.originalname;
const file = (req as any).file;
if (!file) throw new Error('No file provided');
if (!bucket) throw new Error('No bucket provided');
const result = writeFile(bucket, relPath, file.buffer);
return result;
}));
// DELETE /storage (body: bucket, path)
r.delete('/', requireAuth, h(async (req) => {
const { bucket, path: relPath } = req.body || {};
deleteFile(bucket, relPath);
return { message: 'File deleted successfully' };
}));
// GET /storage/list?bucket=&folder=
r.get('/list', requireAuth, h(async (req) => {
return listFiles(req.query.bucket as string, (req.query.folder as string) || '');
}));
// GET /storage/public-url?bucket=&path=
r.get('/public-url', h(async (req) => {
return { url: publicUrl(req.query.bucket as string, req.query.path as string) };
}));
export default r;