Workflow-App/Workflow/app/api/documents/company/upload/route.ts
sjcoetzeesj-coder 11d0178ab1 feat: commit Workflow app source; move CIPC credentials to env
Adds the full Next.js app (app/, components/, lib/, scripts/, assets/,
docs/, Dockerfile, compose, configs) to version control.

Security:
- CIPC BizPortal customer-code logins (Login 1 + Login 3) now read
  CIPC_LOGIN1_CODE / CIPC_LOGIN1_PASSWORD / CIPC_LOGIN3_CODE /
  CIPC_LOGIN3_PASSWORD from .env.local instead of source.
- BizPortal personal login in apply-bizportal route reads
  BIZPORTAL_ID_NO / BIZPORTAL_PASSWORD.
- Added .env.example as the committed template.

.gitignore excludes .env*, node_modules, .next, logs, sqlite, Playwright
storage_state.json (live CIPC cookies), scratch dirs, client PDFs and
debug screenshots.
2026-10-18 15:21:45 +02:00

50 lines
1.9 KiB
TypeScript

// app/api/documents/company/upload/route.ts
// POST — upload a document for a company
import { NextRequest, NextResponse } from "next/server";
import { createRecordMultipart } from "@/lib/pb";
export async function POST(req: NextRequest) {
let formData: FormData;
try {
formData = await req.formData();
} catch {
return NextResponse.json({ error: "Could not parse form data" }, { status: 400 });
}
const companyId = formData.get("company_id") as string | null;
const documentTypeId = formData.get("document_type_id") as string | null;
const notes = formData.get("notes") as string | null;
const file = formData.get("file") as File | null;
const originalFilename = formData.get("original_filename") as string | null;
if (!companyId) return NextResponse.json({ error: "company_id is required" }, { status: 400 });
if (!documentTypeId) return NextResponse.json({ error: "document_type_id is required" }, { status: 400 });
if (!file) return NextResponse.json({ error: "file is required" }, { status: 400 });
const allowedTypes = ["application/pdf", "image/jpeg", "image/jpg"];
if (!allowedTypes.includes(file.type)) {
return NextResponse.json({ error: "Only PDF and JPEG files are allowed" }, { status: 400 });
}
if (file.size > 10 * 1024 * 1024) {
return NextResponse.json({ error: "File must be smaller than 10MB" }, { status: 400 });
}
try {
const record = await createRecordMultipart(
"ysterbaard_company_documents",
{
company: companyId,
document_type: documentTypeId,
notes: notes?.trim() || "",
original_filename: originalFilename || file.name,
uploaded_at: new Date().toISOString().split("T")[0],
},
[{ field: "file", file }]
);
return NextResponse.json(record, { status: 200 });
} catch (err) {
const message = err instanceof Error ? err.message : "Unknown error";
return NextResponse.json({ error: message }, { status: 502 });
}
}