OpenSolve — Devpost Submission (Final)
Track: Track 2 (Monetizable B2B App) — also a strong fit for "Most Impactful" and "Best Technical Implementation" special prizes. AWS Database Used: Amazon DynamoDB (on-demand / PAY_PER_REQUEST) Frontend: Deployed on Vercel (Next.js 15 App Router)
Inspiration
A student graduating this year has done everything right. They finished the degree. Kept their GPA up. Learned the frameworks. Stayed curious. They are walking into the worst entry-level hiring market computer science has seen in a generation.
The numbers are not subtle. Recent CS graduates face a 6.1% unemployment rate — nearly double that of philosophy majors. Underemployment, graduates stuck in jobs that don't require a degree, has climbed to 41.5% as of early 2026. Entry-level software job postings are down 30% year-over-year. The average engineering internship listing now receives 273 applications. And for every student who lands quickly, a measurable pattern repeats: 78% of fast-placed students have a strong GitHub portfolio or verifiable real-world project history. Only 31% of those who rely on their degree alone succeed at the same rate.
This is not a pipeline problem. It is a trust gap. Employers cannot verify capability from a transcript. Students cannot prove themselves without opportunity. The feedback loop is broken.
OpenSolve exists to close that gap. We built a platform where real organizations — startups, enterprises, government innovation programs — post real technical problems with real prize money. Students and small teams apply, build, and submit verifiable solutions. Submissions are evaluated and ranked publicly. The result is a live, tamper-evident portfolio of shipped software — the exact artifact the job market has started to demand.
What It Does
OpenSolve is a two-sided B2B/B2C marketplace for technical talent validation.
For Organizations: Post a technical challenge or unsolved backlog problem, fund a prize pool via Stripe, and receive ranked, pre-evaluated submissions from student teams. Each submission includes a live GitHub repository, a technical writeup, and an automated quality score — eliminating the resume-screening noise of traditional hiring. Organizations can also run internal evaluations using a custom rubric, score submissions, and message winning teams directly.
For Students: Browse a verified, actively curated problem board. Some problems are posted directly by companies. Others are automatically ingested daily from public innovation pools — YC Requests for Startups, UK Government Innovation Funding, and SPRIND (Germany's Federal Agency for Disruptive Innovation). Apply as a team of up to 4, build a real solution, submit a GitHub repo and writeup, and watch yourself climb a public, real-time leaderboard.
For Everyone: A live, cross-platform leaderboard surfaces the highest-scoring builders across all challenges. Your OpenSolve profile becomes a portable signal of proven, ranked technical output — the trust artifact that a degree no longer provides alone.
Why DynamoDB: The Architecture Decision That Shaped Everything
This is not the part of the submission where we say "we picked DynamoDB and it worked." This is the part where we explain the specific access patterns we needed, why each alternative failed to meet them, and how DynamoDB's data model shaped the entire product.
The Core Access Pattern Problem
We had five leaderboard and ranking requirements that were non-negotiable:
- Per-challenge leaderboard: Given a challenge ID, return all submissions in descending score order — instantly, with no secondary sort step.
- Global leaderboard: Across all challenges and all users, surface the top builders by total score.
- Atomic re-rank: When a score is recalculated (GitHub signals update, org manual review), the record must move to its new sorted position atomically — no partial states where a builder appears twice or disappears.
- Concurrent team formation: Multiple users clicking "Join Team" simultaneously must never bypass a hard cap of 4 members.
- Platform-wide counters: Global metrics (total builders, total prize pool, total submissions, active problems) must update atomically with zero read-modify-write race conditions — and must not create a hot partition under surge traffic.
We evaluated PostgreSQL and relational databases first. They would require ORDER BY queries on a large table, connection pool management under serverless concurrency, and explicit locking for counter updates. In Vercel's serverless model, each function invocation is a cold HTTP request with no persistent connection. Under a real traffic spike — say, a viral Twitter thread pointing CS graduates to OpenSolve — hundreds of concurrent Vercel functions would exhaust a standard Postgres connection pool in seconds.
DynamoDB's HTTP/2 API model has no connection pool. Every request is a stateless HTTPS call. Hundreds of concurrent Vercel serverless functions can hit DynamoDB simultaneously without any connection exhaustion. That single property eliminated the biggest reliability risk for a viral-ready B2B platform.
The second structural advantage: DynamoDB's Sort Key is a native B-Tree index. If you encode ranking information into the Sort Key, every Query is already sorted at the storage layer — zero application-side sorting, zero secondary indexes required for the primary leaderboard use case.
We designed the entire data model around these five access patterns before writing a single line of application code.
How We Built It
Single-Table Architecture
We maintain five DynamoDB tables, each designed around a specific access pattern family:
| Table | Primary Key | Sort Key | Purpose |
|---|---|---|---|
OpenSolve_Submissions |
problemId |
rankKey (composite) |
Per-challenge leaderboard |
OpenSolve_Problems |
problemId |
— | Challenge catalog |
OpenSolve_Organizations |
orgId |
— | Org profiles |
OpenSolve_Profiles |
userId |
— | Student profiles + scout points |
OpenSolve_Evaluations |
submissionKey |
evaluatedAt |
Manual org rubric scores |
Pattern 1: Pre-Sorted Leaderboards via Composite Sort Keys
The per-challenge leaderboard is the most frequently queried path in the entire system. We needed it to return submissions already in rank order without a sort step.
The rankKey Sort Key is structured as:
{inverseScore}#{submittedAt}#{userId}
Where inverseScore is 1,000,000 - actualScore, zero-padded to 7 digits. A score of 87 becomes 0999913. Because DynamoDB sorts Sort Keys lexicographically, the lowest inverseScore values (highest actual scores) appear first in every Query. Ties are broken chronologically by submittedAt.
The result: a single QueryCommand with ScanIndexForward: false returns the leaderboard already ranked. No ORDER BY, no application-side sort. The database does the work.
// src/lib/data.ts — getSubmissions()
const command = new QueryCommand({
TableName: SUBMISSIONS_TABLE,
KeyConditionExpression: "problemId = :pid",
ExpressionAttributeValues: { ":pid": problemId },
Limit: 50
});
Pattern 2: Atomic Leaderboard Re-Ranking via TransactWriteCommand
GitHub repositories improve over time. Organizations submit manual rubric scores after deadline. Both events trigger a score update. Since the score is embedded in the Sort Key (rankKey), updating a score requires replacing the entire record at a new key position.
A naive implementation would delete the old record, then put a new one. If the process crashes between those two steps, the builder vanishes from the leaderboard permanently. We solved this with DynamoDB TransactWriteCommand, which makes the delete and the put atomic — both succeed together, or neither does:
// src/lib/evaluator.ts — evaluateSubmissionAsynchronously()
await docClient.send(new TransactWriteCommand({
TransactItems: [
{
Delete: {
TableName: TABLE_NAME,
Key: { problemId, rankKey: oldRankKey }
}
},
{
Put: {
TableName: TABLE_NAME,
Item: { ...existingItem, score: finalScore, rankKey: newRankKey }
}
}
]
}));
This means a leaderboard re-rank can never leave a builder invisible. The old position is retired and the new position is created in a single atomic operation.
The evaluation itself is deterministic: we query the GitHub API for repository signals (description, wiki, pages, stars, primary language detection, days active), combine with writeup length, and produce a score on a 0–100 scale. All reproducible, all auditable.
Pattern 3: Optimistic Concurrency for Team Formation
A student platform during a deadline rush creates a classic distributed systems race condition: two students click "Join Team" on the same team at the exact same millisecond. Without coordination, both succeed, the team exceeds 4 members, and the cap is meaningless.
We do not use database locks. We use DynamoDB's native ConditionExpression for optimistic concurrency control:
// src/app/api/submissions — team join handler
ConditionExpression: "attribute_not_exists(member4UserId)"
If the team is already full when the write arrives, DynamoDB rejects it with a ConditionalCheckFailedException. The application catches this and returns an honest "team is full" error. Under any concurrency level — 10 clicks, 1,000 clicks — exactly 4 members are ever added. No locks, no transactions, no coordination overhead.
Pattern 4: Hot Partition Prevention via Scatter-Gather Sharding
Platform-wide statistics (total builders, total prize pool, total submissions) are updated on every user registration, submission, and challenge post. With a naive approach, all these writes would land on a single DynamoDB item, creating a hot partition that throttles under surge traffic.
We implemented a 10-shard scatter-gather pattern:
// src/lib/data.ts — incrementPlatformStat() / getPlatformStats()
const SHARD_COUNT = 10;
// On write: pick a random shard
const shardId = Math.floor(Math.random() * SHARD_COUNT);
await docClient.send(new UpdateCommand({
TableName: PROBLEMS_TABLE,
Key: { problemId: `GLOBAL_METADATA#${shardId}` },
UpdateExpression: "ADD #field :val",
ExpressionAttributeNames: { "#field": field },
ExpressionAttributeValues: { ":val": value },
}));
// On read: BatchGet all 10 shards and sum
const keys = Array.from({ length: SHARD_COUNT }).map((_, i) => ({
problemId: `GLOBAL_METADATA#${i}`
}));
const result = await docClient.send(new BatchGetCommand({ ... }));
// Sum across all shards
Each write goes to one of 10 randomly chosen shard partitions. DynamoDB can sustain 1,000 writes/second per partition. With 10 shards, the platform can absorb 10,000 concurrent stat-update writes per second before any throttling — the kind of burst that happens when 50,000 CS graduates share the platform on graduation day.
Pattern 5: GSI-Based Deduplication in the Automated Ingestion Pipeline
A daily Vercel Cron Job (0 0 * * *) scrapes real-world problems from three external sources: YC Requests for Startups, UK Government Innovation Funding, and SPRIND. When new items arrive, we must not re-insert a problem we already have.
We solve this with a GSI on sourceUrl. Before inserting, we query:
// src/lib/scrapers/run-ingestion.ts
const queryResult = await docClient.send(new QueryCommand({
TableName: TABLE_NAME,
IndexName: "sourceUrl-index",
KeyConditionExpression: "sourceUrl = :url",
ExpressionAttributeValues: { ":url": p.sourceUrl }
}));
This is a targeted QueryCommand against a GSI — $O(1)$ cost regardless of how many problems exist in the table. No table scans, no N+1 lookups. The deduplication check is as fast on day 1 as it will be when the platform holds 100,000 problems.
Vercel + AWS: Beyond Deployment
The Vercel integration is not "frontend on Vercel, database somewhere else." These two systems cooperate at the product level:
Edge Middleware + Clerk RBAC: Vercel Edge Middleware intercepts every request before it reaches a serverless function. We verify Clerk role metadata (
student,company,organization,admin) at the edge, blocking unauthorized role access before any DynamoDB read or write is attempted. This protects read capacity and prevents unauthorized data exposure at the cheapest possible point in the stack.Vercel Cron → DynamoDB: The automated problem ingestion pipeline is a native Vercel Cron function. It runs at midnight daily, scrapes three external sources, and writes deduplicated results directly to DynamoDB using the
sourceUrl-indexGSI. The cron job is configured invercel.jsonand requires zero external scheduling infrastructure.Credential Security via Vercel Environment Variables: AWS IAM credentials (
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_REGION) are managed through Vercel's encrypted environment variable system. The DynamoDB SDK's Default Credential Provider Chain picks these up automatically — no hardcoded secrets, no.envfiles, no VPC, no bastion host.Serverless-Native SDK Design: We configure the DynamoDB client with
maxAttempts: 5and rely on the AWS SDK v3's built-in exponential backoff. Because every Vercel serverless function is stateless, the client re-initializes cold on each invocation. The HTTP/2 connection model means this adds zero overhead compared to a long-lived process.
Design: Full-Stack Coherence
The frontend was designed in direct response to backend performance characteristics.
Because DynamoDB Queries return leaderboard data already sorted, our Next.js pages receive pre-ranked arrays. There is no loading spinner while the application re-sorts client-side. The data arrives ready. This allowed us to build optimistic UI updates — when a student joins a team or submits an application, the UI responds immediately while the DynamoDB write completes in the background.
The visual design reflects the no-compromise tone of the platform itself: a true-dark glassmorphic interface (#050505 background, bg-white/5 glass layers, border-white/10 hairlines). No generic component libraries. Every page is purposeful — student views, organization dashboards, admin panels, and leaderboards each expose only the data relevant to that role. The RBAC enforced at the Vercel edge is mirrored exactly in the UI layer.
Accomplishments
- A production-grade DynamoDB data model where every access pattern is an indexed Query — no table scans exist in the hot path.
- Atomic leaderboard re-ranking that can never produce a partial state, using DynamoDB native transactions.
- A hot-partition-proof global statistics counter using scatter-gather sharding across 10 DynamoDB partitions.
- Race-condition-free team formation under unlimited concurrency using
ConditionExpressions. - A fully automated problem ingestion pipeline — Vercel Cron to DynamoDB — that deduplicates using a GSI, with zero ops overhead.
- Role-based access control enforced at the Vercel edge layer, protecting DynamoDB capacity from unauthorized access.
- A complete Stripe-integrated prize funding flow where organizations fund challenges that go live immediately on the platform.
What We Learned
NoSQL forces honesty. In a relational database, you can defer data modeling and fix it later with a new query or a JOIN. DynamoDB makes you commit: what questions will your application ask, and in what order? Getting that wrong at the start means expensive migrations. We wrote out every access pattern — sorted leaderboards, user submission histories, org dashboards, cross-platform rankings — before creating a single table. The discipline made the system faster and the code simpler.
Vercel and DynamoDB are philosophically aligned. Both are pay-per-request, infinitely elastic, and stateless. Designing for one naturally designs for the other. The connection pool problem that haunts serverless PostgreSQL deployments simply does not exist here.
What's Next for OpenSolve
- DynamoDB Streams → Vercel Serverless → Real-Time Push: Connect DynamoDB Streams to a Vercel Serverless Function to trigger WebSocket or Server-Sent Event notifications the instant a student's leaderboard rank changes or a submission receives a new evaluation score. No client polling. No delay.
- Deadline-Gated Submission Reveal: Suppress competitor submissions from public view until the challenge deadline passes, preventing mid-challenge plagiarism. Implemented as a DynamoDB
FilterExpressionon deadline timestamp. - Stripe Connect Disbursements: Automated direct prize payments to winning teams' bank accounts once an organization confirms the winner.
- Aurora DSQL for Transactional Billing: As the financial layer scales, migrate the Stripe ledger to Aurora DSQL for full ACID compliance across multi-region financial records.
Built With
- aws-dynamodb
- aws-sdk-v3
- clerk-(auth-&-rbac)
- funding
- github-api
- imgbb
- innovation
- next.js-15
- node.js
- posthog
- react-19
- resend
- sprind-scraper
- stripe
- tailwind-css
- typescript
- uk
- vercel
- vercel-cron-jobs
- vercel-edge-middleware
- yc-rfs-scraper
Log in or sign up for Devpost to join the conversation.