Add DELETE /api/auth/account endpoint for full account deletion
Implements task 6.3: deletes all user data in correct FK order (span_annotations, annotations, candles, charts, span_label_types, annotation_types) then deletes the user record. Returns 401 if not authenticated, 200 on success. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
93f7d20382
commit
aa2c5fdb69
2 changed files with 55 additions and 1 deletions
|
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
- [x] 6.1 `[haiku]` Create `PUT /api/auth/profile` endpoint: update user display name
|
- [x] 6.1 `[haiku]` Create `PUT /api/auth/profile` endpoint: update user display name
|
||||||
- [x] 6.2 `[sonnet]` Create `PUT /api/auth/password` endpoint: verify current password, hash new password, update; reject for OAuth users
|
- [x] 6.2 `[sonnet]` Create `PUT /api/auth/password` endpoint: verify current password, hash new password, update; reject for OAuth users
|
||||||
- [ ] 6.3 `[sonnet]` Create `DELETE /api/auth/account` endpoint: delete all user data (cascade) and user record
|
- [x] 6.3 `[sonnet]` Create `DELETE /api/auth/account` endpoint: delete all user data (cascade) and user record
|
||||||
|
|
||||||
## 7. Update Existing API Routes
|
## 7. Update Existing API Routes
|
||||||
|
|
||||||
|
|
|
||||||
54
src/app/api/auth/account/route.ts
Normal file
54
src/app/api/auth/account/route.ts
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
import { NextResponse } from 'next/server';
|
||||||
|
import { eq } from 'drizzle-orm';
|
||||||
|
import { db } from '@/lib/db';
|
||||||
|
import {
|
||||||
|
users,
|
||||||
|
spanAnnotations,
|
||||||
|
annotations,
|
||||||
|
candles,
|
||||||
|
charts,
|
||||||
|
spanLabelTypes,
|
||||||
|
annotationTypes,
|
||||||
|
} from '@/lib/db/schema';
|
||||||
|
import { getAuthUser } from '@/lib/auth';
|
||||||
|
|
||||||
|
export async function DELETE() {
|
||||||
|
// Get authenticated user
|
||||||
|
const user = await getAuthUser();
|
||||||
|
if (!user) {
|
||||||
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const userId = user.id;
|
||||||
|
|
||||||
|
// Delete in FK-safe order:
|
||||||
|
// 1. span_annotations (references charts)
|
||||||
|
await db.delete(spanAnnotations).where(eq(spanAnnotations.user_id, userId));
|
||||||
|
|
||||||
|
// 2. annotations (references charts)
|
||||||
|
await db.delete(annotations).where(eq(annotations.user_id, userId));
|
||||||
|
|
||||||
|
// 3. candles (references charts — no user_id, must go via chart_id)
|
||||||
|
const userCharts = await db
|
||||||
|
.select({ id: charts.id })
|
||||||
|
.from(charts)
|
||||||
|
.where(eq(charts.user_id, userId));
|
||||||
|
|
||||||
|
for (const chart of userCharts) {
|
||||||
|
await db.delete(candles).where(eq(candles.chart_id, chart.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. charts
|
||||||
|
await db.delete(charts).where(eq(charts.user_id, userId));
|
||||||
|
|
||||||
|
// 5. span_label_types (references users)
|
||||||
|
await db.delete(spanLabelTypes).where(eq(spanLabelTypes.user_id, userId));
|
||||||
|
|
||||||
|
// 6. annotation_types (references users)
|
||||||
|
await db.delete(annotationTypes).where(eq(annotationTypes.user_id, userId));
|
||||||
|
|
||||||
|
// 7. user record
|
||||||
|
await db.delete(users).where(eq(users.id, userId));
|
||||||
|
|
||||||
|
return NextResponse.json({ message: 'Account deleted successfully' }, { status: 200 });
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue