What the code can tell you about your bid package.
This page stays deliberately narrow: it describes visible application behavior for PDF uploads, saved reports, access checks, deletion, and analytics. It does not turn those observations into provider or infrastructure assurances.
Read the verified facts first, then the UNKNOWN register. If the code cannot establish something, ScopeSpindle does not claim it here.
01 / The short version
Evidence, storage, and limits.
The public flow returns a teaser without creating a saved report. The authenticated flow saves structured report data—not the original PDF binary—and scopes report operations to the signed-in owner.
Public teaser
Analyzed in memory, no report row created.
Saved report
Structured JSON and retained passages are stored.
Access
Report routes require auth and match the owner ID.
02 / The upload paths
Two flows. Different persistence.
Both paths validate one non-empty PDF up to 25 MB. The application behavior after that validation is different by design.
Public /api/free-analysis
The browser base64-encodes the selected PDF and posts it to the public route. The route validates the file, reconstructs an in-memory File, and sends it for analysis.
The response is a teaser: decision and confidence, filename and project name when available, counts for risks, requirements, RFIs, and missing items, plus selected retained source passages for the refrigerant and HVAC risk lenses.
This route does not create a BidIntelligenceReport database row.
Authenticated /api/bid-recommendation
After file validation and requireAuth(), the route sends the PDF bytes as a base64 PDF data URL to the configured AI proxy and validates the structured analysis.
It adds citation IDs and the professional-review disclaimer, then stores one report row keyed by the authenticated userId. The original PDF binary is not stored in the application report model.
A report-ready email contains the project, recommendation, confidence, and a link to the saved report. A failed email emits a warning; it does not change the saved report result.
03 / What is stored
A report record, not the source file.
The application database model stores the report output and its evidence structure. It does not define a column for the uploaded PDF binary.
BidIntelligenceReport
The JSON can contain the recommendation and confidence; reasons; summary, project, and deadline fields; eight named report sections and their claims; citations; refrigerant and HVAC risk checks; suggested RFIs; the disclaimer; and up to 24 verbatim source passages. Each retained passage includes document filename, page, and text capped at 1,200 characters.
04 / Application deletion
Delete the saved row.
The delete route is application-level and owner-scoped. It is precise about what it removes and deliberately silent about systems the route cannot inspect.
DELETE /api/bid-reports/[id]
What success means
After requireAuth(), the route calls deleteMany with both the report ID and authenticated userId. A successful deletion removes that saved report row, including its JSON and retained source passages, from the application database.
Application deletion makes no claim about provider logs, backups, AI systems, email copies, caches, or infrastructure deletion.
05 / Access and analytics
The visible control points.
These are concrete application paths, not a generalized security or compliance claim.
Report reads
The report index and detail GET look up records with the authenticated user ID. A report from another owner is returned as not found.
Report actions
Authenticated upload, QA, suggested RFIs, PDF export, and deletion paths call requireAuth(). Creation records the authenticated user ID.
Boundary of the claim
This is a report-route access observation, not a platform-wide tenant-isolation or infrastructure-controls claim.
First-party analytics
App analytics posts an allowlisted event to /api/analytics/events. TheAnalyticsEvent row contains event name, timestamp, optional authenticated user ID, a local-storage visitor ID, route, and bounded metadata.
Funnel events are best-effort. The free flow records upload-started, completed, and abandoned events; the authenticated detail route records report views. Separately, the framework conditionally emits a page-load beacon to its configured platform base when POLSIA_ANALYTICS_SLUG is present.
Visible warnings and errors include failed report-ready email delivery and startup seed diagnostics. No report or PDF content logging is established in the reviewed application paths.
What this code review cannot establish.
An absent application code path is not proof that an infrastructure behavior is absent. These boundaries stay explicit until separately verified.
Until handling is otherwise verified, upload only synthetic, public, redacted, non-confidential, or otherwise authorized material.
The authenticated app does not retain the original PDF binary in its report row. That does not make a promise about provider retention or other systems outside the visible application database.
The human-review boundary
A first pass is not approval.
ScopeSpindle’s result is an AI-generated first pass. A qualified estimator must verify scope, requirements, pricing, schedule, and commercial risk before a bid decision.