Submissions and matches
Industry technical intake and routing results
A submission is the record created when an industry organization shares a capability statement, white paper, pitch material, event summary, or profile update. It is not a contract offer and the portal warns users not to submit source-selection information.
Submission
| Column | Prisma type | Required? | Default | Meaning |
|---|---|---|---|---|
id | String | Yes | cuid() | Submission identifier. |
organizationId | String | Yes | None | Sending organization. |
type | SubmissionType | Yes | None | Kind of material. |
status | SubmissionStatus | Yes | SUBMITTED | Routing/review lifecycle state. |
title | String | Yes | None | Short descriptive title. |
summary | String | Yes | None | Plain-text technical summary. |
filePath | String? | No | NULL | Private object key/path when a file was uploaded. |
fileName | String? | No | NULL | Original filename shown to users. |
techTags | String | Yes | "" | Lowercase comma-separated tags. |
callId | String? | No | NULL | Optional call for technology answered. |
reviewerId | String? | No | NULL | Optional government reviewer. |
createdAt | DateTime | Yes | now() | Submission time. |
updatedAt | DateTime | Yes | @updatedAt | Last status or content update. |
Relations are organization, optional call, optional reviewer, and many matches. A text-only submission is valid because filePath and fileName are optional.
SubmissionType
| Value | Meaning |
|---|---|
CAPABILITY_STATEMENT | Organization capability overview. |
WHITE_PAPER | Deeper technical paper. |
PITCH_MATERIAL | Briefing or pitch material. |
EVENT_SUMMARY | Follow-up or summary from an event. |
PROFILE_UPDATE | Information intended to update an organization profile. |
SubmissionStatus
| Value | Meaning |
|---|---|
SUBMITTED | Accepted intake record awaiting or eligible for routing. |
ROUTED | At least one match was persisted. |
REVIEWED | A government reviewer has reviewed it. |
ARCHIVED | Retained record no longer in active workflow. |
SubmissionMatch
| Column | Prisma type | Required? | Default | Meaning |
|---|---|---|---|---|
id | String | Yes | cuid() | Match identifier. |
submissionId | String | Yes | None | Submission being routed. |
portfolioNodeId | String | Yes | None | Candidate technical node. |
score | Float | Yes | None | Score on a shared 0–1 scale; Bedrock scores are rescaled to it, so this field does not identify the scorer. |
rationale | String? | No | NULL | Optional explanation. |
createdAt | DateTime | Yes | now() | Match creation time. |
@@unique([submissionId, portfolioNodeId]) prevents duplicate matches for one submission/node pair. routeSubmission deletes old matches and recreates the current ranked set in a transaction.
File and routing lifecycle
File constraints are implemented in the portal route, not in Prisma: PDF, DOCX, PPTX, or TXT; maximum 15 MB; magic-byte checks; server-side encryption in S3 unless the deployment sets UPLOADS_S3_SSE=none. The database stores the private key, never a public upload URL.
Foreign-key behavior
organizationId is required, so every submission has an accountable industry owner. callId is optional and is checked by the route for an open call before creation. reviewerId is optional until government review begins. The schema's relation fields let a government detail page include organization and matches without copying organization name into every submission row.
The current schema does not store a MIME type, checksum, or extracted text. fileName is presentation metadata and filePath is the private storage key. If a future feature needs content scanning or deduplication, those are additive fields or services rather than assumptions about current behavior.
Rerouting is safe to repeat because (submissionId, portfolioNodeId) is unique and the matching service replaces the old set in a transaction. Notification de-duplication is handled separately by recipient, kind, and link URL.