assessment-model/bulk-address-upload.md
2026-04-16 17:47:53 +00:00

98 lines
3.2 KiB
Markdown

# Bulk Address Upload — Implementation Tracker
## Overview
Upload CSV/XLSX to S3 (browser-direct via XHR with progress bar) → confirm in DB → redirect to upload list.
Portfolio shows all uploads ordered by date. User picks which to continue.
---
## DB Migration (manual — do this first)
```sql
CREATE TABLE bulk_address_uploads (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
portfolio_id TEXT NOT NULL,
user_id TEXT NOT NULL,
s3_bucket TEXT NOT NULL,
s3_key TEXT NOT NULL,
filename TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'ready_for_processing',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
```
Status values: `ready_for_processing` | `processing` | `complete` | `failed`
- [ ] Migration applied to dev
- [ ] Migration applied to staging
- [ ] Migration applied to prod
---
## Tasks
### 1. Drizzle Schema
- [ ] Create `src/app/db/schema/bulk_address_uploads.ts`
- [ ] Import + spread into `src/app/db/db.ts`
### 2. Confirm API Route
- [ ] Create `src/app/api/upload/bulk-addresses/confirm/route.ts`
- POST `{ fileKey, filename, portfolioId, userId }`
- Inserts into `bulk_address_uploads`, `s3Bucket` from `RETROFIT_PLAN_INPUT_BUCKET_NAME` env
- Returns `{ id, s3Key, s3Bucket, status }`
### 3. List API Route
- [ ] Create `src/app/api/portfolio/[portfolioId]/bulk-uploads/route.ts`
- GET → all uploads for portfolio ordered by `created_at DESC`
- Returns array of upload records
### 4. Modal — XHR Upload + Progress + Redirect to List
- [ ] Replace `fetch` PUT → `XMLHttpRequest` in `handleUpload`
- [ ] Add `progress: number | null` state
- [ ] Show progress bar in dropzone while uploading
- [ ] After XHR load: POST confirm → `router.push(/portfolio/[id]/bulk-upload)`
### 5. Upload List Page
- [ ] Create `src/app/portfolio/[portfolioId]/bulk-upload/page.tsx`
- Server component
- List all uploads: filename, status badge, created date, "Continue →" link
- Empty state if none
- Each row links to `/bulk-upload/[uploadId]`
### 6. Upload Detail Page
- [ ] Create `src/app/portfolio/[portfolioId]/bulk-upload/[uploadId]/page.tsx`
- Server component
- Shows: filename, `s3://bucket/key`, status, created date
- For now: "Your file is queued for processing"
---
## Flow
```
User drops/clicks file
→ validate (size, extension, headers)
→ GET presigned URL (/api/upload/bulk-addresses)
→ XHR PUT to S3 (progress bar shown)
→ POST confirm (/api/upload/bulk-addresses/confirm)
→ redirect to list (/portfolio/[id]/bulk-upload)
→ list page (all uploads, status badges, click to continue)
→ detail page (/portfolio/[id]/bulk-upload/[uploadId])
→ shows s3_uri + status
```
---
## Files Touched
| File | Status |
|------|--------|
| `src/app/db/schema/bulk_address_uploads.ts` | not started |
| `src/app/db/db.ts` | not started |
| `src/app/api/upload/bulk-addresses/confirm/route.ts` | not started |
| `src/app/api/portfolio/[portfolioId]/bulk-uploads/route.ts` | not started |
| `src/app/components/portfolio/BulkUploadComingSoonModal.tsx` | not started |
| `src/app/portfolio/[portfolioId]/bulk-upload/page.tsx` | not started |
| `src/app/portfolio/[portfolioId]/bulk-upload/[uploadId]/page.tsx` | not started |