Files
ProjectE/apps/web/app/api/export/route.ts
T
mbatchelder b3ff23a5f0 feat: Phase 1 foundation - schema, auth, realtime, shell
- Rewrote Drizzle schema: 20 tables with enums, relations, indexes
- Generated migration with DROP TABLE records (v1 EAV removal)
- Added passkey auth routes (register/login)
- Added requireWorkspaceAccess helper
- Added seedDefaultData for Personal workspace + welcome note
- Updated SSE endpoint for v2 entities + workspace_id filtering
- Created recordActivity helper (insert + pg_notify)
- Updated sidebar: Graph replaces Reports, removed Analytics
- Updated command palette for v2 entities
- Created AGENTS.md with locked contract
- Created llm-wiki scaffold (5 stubs)
- Added inline AGENT INSTRUCTION comments to all 50 API route files
- Fixed globals.css border-border class conflict
- Updated database.ts stub for v1 compatibility
2026-07-29 05:53:13 -04:00

68 lines
1.9 KiB
TypeScript

// AGENT INSTRUCTION: After every write (INSERT/UPDATE/DELETE), you MUST:
// 1. Insert activity feed entry
// 2. Call pg.notify('project_e_events', JSON.stringify({ type, action, id, workspace_id }))
// See AGENTS.md for full rules.
import { NextRequest, NextResponse } from 'next/server';
import { withAuth, createErrorResponse } from '@/lib/auth';
import { createPocketBaseClient } from '@/lib/pocketbase';
const COLLECTIONS = [
'tasks',
'habits',
'projects',
'notes',
'reports',
'milestones',
'domains',
'tags',
'agents',
'webhooks',
] as const;
type ExportCollection = (typeof COLLECTIONS)[number];
// POST /api/export — Export all data as JSON
export const POST = withAuth(async (request: NextRequest, _user) => {
let body: { collections?: ExportCollection[] } = {};
try {
body = await request.json();
} catch {
// Empty body is fine — export everything
}
const requestedCollections = body.collections && body.collections.length > 0
? body.collections.filter((c): c is ExportCollection => COLLECTIONS.includes(c as ExportCollection))
: [...COLLECTIONS];
const pb = createPocketBaseClient();
const exportData: Record<string, unknown> = {
version: '1.0',
exportedAt: new Date().toISOString(),
};
for (const collection of requestedCollections) {
try {
const result = await pb.collection(collection).getList(1, 1000, {
sort: 'created',
});
exportData[collection] = result.items;
} catch (error) {
console.error(`Failed to export collection ${collection}:`, error);
exportData[collection] = [];
}
}
return NextResponse.json(exportData);
});
// GET /api/export — List available collections for export
export const GET = withAuth(async (_request: NextRequest, _user) => {
return NextResponse.json({
collections: COLLECTIONS.map((name) => ({
name,
label: name.charAt(0).toUpperCase() + name.slice(1).replace(/_/g, ' '),
})),
});
});