Rides
Offer / request → seat request → capacity / status
Case study / 03
One trusted student network for the everyday logistics of campus life.
Loop brings rides, marketplace listings, study groups, and context-linked conversation previews into one authenticated Waterloo student network. A shared relational model connects users, trust fields, memberships, seat requests, and messages. Protected Next.js APIs validate create payloads with Zod, while serializable transactions and unique relationships protect capacity-sensitive actions. Marketplace contact preserves the originating listing, and shared identity keeps coordination consistent across otherwise different campus workflows.
One authenticated User model connects every product domain.
Conversation context links messages to listings, rides, or groups.
Protected handlers and Zod validate create payloads before persistence.
Transactions and unique relationships protect joins and seat requests.

One identity. Four connected workflows. Credentials are restricted to @uwaterloo.ca addresses; stored verification levels are prototype trust fields, not proof of institutional verification.
| Decision | Why | Tradeoff |
|---|---|---|
| One relational model across product surfaces. | Users, trust fields, listings, memberships, and conversations need consistent relationships. | Cross-domain schema changes require careful migrations. |
| Context-linked conversations. | Messages retain the resource that initiated the interaction. | Extra contextual state; resource references are enforced by application logic. |
| Serializable capacity mutations and unique relations. | Ride seats and group joins must resist duplicates and oversubscription. | Transaction complexity and explicit conflicts for callers to handle. |

Shared users connect listings, seat requests, memberships, conversations, and reviews.
Conversation contextId is a logical reference, not a database foreign key. Marketplace contact creates or reuses a contextual conversation; the schema also supports ride and group contexts.

Seat requests and group joins use the same transaction pattern to protect capacity.
Existing relationships return 200 without another decrement. New relationships return 201; exhausted capacity or transaction failures return 409. There is no automatic transaction retry loop.
Offer / request → seat request → capacity / status
Listing → contact → contextual conversation
Group → join → membership / capacity
Conversation → domain context → latest / unread preview
Evolve prototype trust into institutional verification and stronger authorization policies. Add production messaging and event delivery beyond the current previews, and exercise capacity conflicts with concurrent database integration tests.