admin: view order PDFs from MinIO (signed forms, prepared filings, evidence)

Adds a Documents section to the compliance-order detail drawer so you can
review the actual filing PDFs before approving an order:
  GET /api/v1/admin/compliance-orders/:id/documents  list viewable objects
  GET /api/v1/admin/compliance-orders/:id/document?key=&token=  stream one

Key discovery pulls from esign_records (unsigned + signed docs per order),
intake_data.filing_status (pdf_minio_path, attested_pdf, evidence/*), and the
order's engagement_letter / rmd_packet columns.

Rather than hand out presigned URLs (MinIO's public host is IP-allowlisted to a
few office IPs, so links break elsewhere), the API streams the object through
itself from internal minio:9000, gated by the admin JWT. The stream endpoint
accepts the token via ?token= (new middleware requireAdminQueryOrHeader) so a
PDF opens in a new tab, and refuses any key that isn't one of the order's own
documents.
This commit is contained in:
justin 2026-06-16 00:20:15 -05:00
parent d65f5ea279
commit bce5db4a09
3 changed files with 192 additions and 1 deletions

View file

@ -39,3 +39,26 @@ export function requireAdmin(req: Request, res: Response, next: NextFunction): v
res.status(401).json({ error: "Invalid or expired token." });
}
}
/**
* Verify admin JWT from EITHER the Authorization header OR a `?token=` query
* param. Needed for endpoints opened directly by the browser (e.g. a PDF in a
* new tab / <iframe>), where custom request headers cannot be set. The token is
* the same short-lived admin JWT; only use this for read-only document streams.
*/
export function requireAdminQueryOrHeader(req: Request, res: Response, next: NextFunction): void {
const header = req.headers.authorization;
const headerTok = header && header.startsWith("Bearer ") ? header.slice(7) : null;
const queryTok = typeof req.query.token === "string" ? req.query.token : null;
const token = headerTok || queryTok;
if (!token) {
res.status(401).json({ error: "Authentication required." });
return;
}
try {
req.admin = jwt.verify(token, JWT_SECRET) as AdminPayload;
next();
} catch {
res.status(401).json({ error: "Invalid or expired token." });
}
}