Project ROUNDTABLE Docs
Architecture

Workstreams and contracts

WS1 through WS4 ownership and the shared functions between them

A workstream is a functional ownership boundary, not a separate deployable service. Every workstream uses the same Next.js process, Prisma client, and PostgreSQL database. The labels help contributors know where behavior belongs and which shared contract must remain stable.

Ownership table

WorkstreamUser problemMain pages/routesShared contract
WS1Industry needs a safe way to register and share capabilities./portal, /api/portal/**Creates a submission, then calls routeSubmission.
WS2Government needs one ledger of organizations and interactions./gov, /api/gov/**Writes organization, engagement, call, announcement, and admin records.
WS3Technical submissions need routing and POC alerts.Matching helpers and notifications UIrouteSubmission, notifyUser, notifyGovByTags, notifyAllIndustry.
WS4Government needs discovery and portable exports.Search and export pages/routessearchAll backend seam and export role gate.

WS1 to WS3 contract

routeSubmission(submissionId) receives only an ID. It reloads the submission, organization, tags, and portfolio nodes inside the service so callers cannot pass an untrusted score or arbitrary recipient. The service:

  1. Normalizes submission and organization tags.
  2. Calculates scores with the selected scorer: deterministic tag/keyword overlap by default, or Bedrock cosine similarity when MATCHING_SCORER=bedrock.
  3. Persists ranked SubmissionMatch rows.
  4. Changes SUBMITTED to ROUTED when matches exist.
  5. Notifies matching interest profiles without duplicate identical links.
  6. Writes submission_routed.

This function is called after the submission row exists. Upload storage is complete before routing so the database never claims an object that failed its validation or write.

WS2 to WS3 notification contracts

notifyUser() creates one notification after checking a user's category setting. notifyUserForTags() performs the same check with event tags. notifyGovByTags() finds government users whose interest profile overlaps event tags. notifyAllIndustry() finds every industry user and applies their category setting. None sends external email; all create Notification rows for the in-app bell.

WS2 hierarchy contracts

getDescendantCommandIds() is a traversal utility for system-admin hierarchy operations. getScopedCommandIds() is the authorization policy used by admin lists. assertCommandInScope() is the per-record guard. Do not replace an exact scope check with a descendant traversal for command leads; the code intentionally denies downward inheritance to non-enterprise roles.

WS4 search contract

searchAll(query, options) returns { query, total, groups }, where each item contains a type, ID, title, snippet, URL, and optional metadata. setSearchBackend() allows an alternative backend (e.g. vector embeddings) without changing route callers. The default implementation is a hybrid: PostgreSQL full-text search against expression GIN indexes runs first — websearch_to_tsquery for plain queries and boolean/phrase syntax, or a translation to raw to_tsquery syntax when the query needs prefix wildcards, which websearch_to_tsquery cannot express —, degrading to typo-tolerant pg_trgm trigram fuzzy search (word_similarity()/%> over GIN trigram indexes, threshold tunable via SEARCH_SIMILARITY_THRESHOLD) when it finds nothing. Each stage is selectable on its own at deploy time via SEARCH_BACKEND (hybrid/fts/trigram/prisma — the original contains substring fallback).

Change checklist

When adding a feature:

Identify which workstream owns the user-visible behavior and which model changes are required.
Put request parsing and authorization in the route handler, not in a client component.
Reuse the shared helper for matching, notification, scope, search, or storage behavior.
Write an audit event for security-sensitive or administrative mutations.
Update the corresponding data-model, API-reference, and security documentation.
Run the docs build and root lint/typecheck before handoff.

Testing a cross-workstream change

A submission feature is a useful example because it crosses all four workstreams:

  1. WS1 validates the form and creates the submission.
  2. WS3 calculates matches and notifications.
  3. WS2 consumes the resulting organization/submission record and may log follow-up.
  4. WS4 discovers the record through search and includes eligible fields in an export.

Review the API response and database side effects at each boundary. A successful HTTP 201 proves only that the first route accepted the record; it does not prove a match or notification was produced.

Documentation contract

When a route changes, update three views:

ViewMinimum update
User feature pageNew URL, walkthrough step, edge case.
API referenceMethod, field constraints, status/error behavior, example.
Data/security pageNew model relation or control if applicable.

This prevents a route implementation from becoming the only place where a behavior is discoverable.