How the freeCodeCamp Daily Coding Challenge Feature Works: Architecture and Implementation
The freeCodeCamp daily coding challenge combines a Prisma-managed PostgreSQL database, Fastify REST API endpoints, and a React frontend with Joi validation to serve time-gated programming exercises that support both JavaScript and Python.
The daily coding challenge feature in the freeCodeCamp/freeCodeCamp repository provides learners with a curated programming exercise every calendar day. This system ensures that only challenges with publication dates less than or equal to the current day (in US Central time) are accessible, while reusing the existing challenge rendering infrastructure. The implementation spans three distinct layers: a persistence tier using Prisma, a read-only API layer built with Fastify, and a client-side React component that validates and transforms data for the classic challenge UI.
Data Model and Storage
The foundation of the daily coding challenge system rests on a Prisma-managed database table named dailyCodingChallenges. This schema stores challenge metadata, bilingual content, and strict date boundaries.
- Schema fields:
id,challengeNumber,title,date,description,javascript,python, and additional metadata columns. - Date storage: The
datecolumn stores timestamps at UTC midnight, enabling precise date-range queries without time-of-day complexity. - Time zone enforcement: All "today" calculations use US Central time via
getNowUsCentral(), ensuring a consistent global release schedule regardless of the user's locale.
Challenges are only considered visible when their stored date is less than or equal to the current UTC midnight derived from US Central time. This logic prevents premature access to future challenges while allowing users to browse historic entries.
API Layer and Endpoint Design
The server-side implementation resides in api/src/daily-coding-challenge/routes/daily-coding-challenge.ts and exposes five read-only Fastify routes. Each endpoint handles specific query patterns while enforcing the future-date restriction.
| Endpoint | Purpose | Key Logic |
|---|---|---|
GET /daily-coding-challenge/date/:date |
Fetch specific date | Parses YYYY-MM-DD via dateStringToUtcMidnight(); returns 400 for invalid formats, 404 for missing or future dates |
GET /daily-coding-challenge/today |
Current day's challenge | Computes today = getUtcMidnight(getNowUsCentral()); returns 404 if no record exists |
GET /daily-coding-challenge/month/:month |
Monthly archive | Validates YYYY-MM format, builds UTC bounds, restricts to lte: today |
GET /daily-coding-challenge/all |
Complete history | Returns all challenges up to today, ordered descending by date |
GET /daily-coding-challenge/newest |
Latest available | findFirst ordered by date DESC, selecting only the { date } field |
All routes utilize Fastify's logger for request tracing and return standardized error shapes: { type: 'error', message: '...' }. The dateStringToUtcMidnight() utility strictly validates input formats, ensuring that malformed date parameters never reach the database layer.
Frontend Implementation and Validation
The client-side entry point is client/src/client-only-routes/show-daily-coding-challenge.tsx, a React component that orchestrates data fetching, schema validation, and UI rendering.
Fetching and Validation Flow
- Route matching: The dynamic route
/learn/daily-coding-challenge/date/:datemounts theShowDailyCodingChallengecomponent. - API request: The
fetchChallengefunction callsGET ${apiLocation}/daily-coding-challenge/date/${date}. - Schema validation: Responses pass through
validateDailyCodingChallengeSchema, defined inclient/src/utils/daily-coding-challenge-validator.ts. This Joi-based validator enforces two schemas:challengeDataFromDbSchema: Validates top-level fields (id,challengeNumber,title,date,description)challengeLanguageDataSchema: Validates nestedtestsandchallengeFilesarrays for both JavaScript and Python implementations
- Data transformation: The
formatChallengeDatafunction converts the API response into a structure compatible withShowClassic, injecting required UI fields likesuperBlock,block,instructions, anddemoType. - Language persistence: The component maintains language state (JavaScript vs. Python) via the
dailyCodingChallengeLanguagestore key, passing it as props toShowClassic.
If validation fails or the API returns a missing challenge, the component renders <DailyCodingChallengeNotFound />. During loading states, it displays <Loader />.
Navigation and Redirection
Legacy routes (/learn/daily-coding-challenge) redirect to the archive view via client/src/components/redirect-daily-challenge-archive.tsx. The archive page consumes the /all endpoint to display a browsable history of past challenges.
Practical Code Examples
Server-Side Date Validation and Retrieval
This excerpt from api/src/daily-coding-challenge/routes/daily-coding-challenge.ts demonstrates the strict date parsing and future-date prevention:
const { date } = req.params;
const parsedDate = dateStringToUtcMidnight(date);
if (!parsedDate) {
return reply.status(400).send({
type: 'error',
message: 'Invalid date format. Please use YYYY-MM-DD.'
});
}
const challenge = await fastify.prisma.dailyCodingChallenges.findFirst({
where: { date: parsedDate }
});
if (!challenge || challenge.date > getUtcMidnight(getNowUsCentral())) {
return reply.status(404).send({
type: 'error',
message: 'Challenge not found.'
});
}
return reply.send({ ...challenge, date: challenge.date.toISOString() });
Client-Side Fetch and Joi Validation
From client/src/client-only-routes/show-daily-coding-challenge.tsx, the validation workflow ensures type safety before state updates:
const fetchChallenge = async (date: string) => {
const response = await fetch(
`${apiLocation}/daily-coding-challenge/date/${date}`
);
const challengeData = await response.json();
const { error } = validateDailyCodingChallengeSchema(
challengeData as DailyCodingChallengeFromDb
);
if (error) throw new Error(`Validation failed: ${error.message}`);
const formatted = formatChallengeData(challengeData as DailyCodingChallengeFromDb);
setChallengeProps(formatted);
setChallengeFound(true);
};
Rendering with Language Support
The component delegates final rendering to ShowClassic, passing bilingual challenge data:
return (
<ShowClassic
isDailyCodingChallenge={true}
dailyCodingChallengeLanguage={dailyCodingChallengeLanguage}
setDailyCodingChallengeLanguage={setDailyCodingChallengeLanguage}
{...challengeProps[dailyCodingChallengeLanguage]}
/>
);
Summary
- Database Layer: Prisma manages the
dailyCodingChallengestable with UTC midnight timestamps and strict date indexing. - API Security: Fastify routes in
daily-coding-challenge.tsprevent access to future dates usinggetNowUsCentral()and return consistent error payloads. - Validation: The client uses Joi schemas in
daily-coding-challenge-validator.tsto guarantee API response shapes before rendering. - UI Reuse:
ShowDailyCodingChallengetransforms API data forShowClassic, enabling JavaScript/Python toggles without duplicating editor logic. - Testing: The feature includes unit tests in
daily-coding-challenge.test.tsand end-to-end coverage ine2e/daily-coding-challenge.spec.ts.
Frequently Asked Questions
How does freeCodeCamp prevent users from accessing future daily coding challenges?
The API compares the requested challenge's date field against getUtcMidnight(getNowUsCentral()) in api/src/daily-coding-challenge/routes/daily-coding-challenge.ts. If the challenge date exceeds the current US Central midnight timestamp, the server returns a 404 response regardless of whether the record exists in the database.
What validation library secures the daily coding challenge API responses?
The frontend uses Joi (via client/src/utils/daily-coding-challenge-validator.ts) to validate all incoming payloads against challengeDataFromDbSchema and challengeLanguageDataSchema. This ensures that tests, challengeFiles, and metadata fields conform to expected types before the React component updates its state.
Can users browse previous daily coding challenges?
Yes. The /daily-coding-challenge/all endpoint returns every published challenge up to the current date, ordered from newest to oldest. The archive view at /learn/daily-coding-challenge/archive consumes this endpoint to provide a browsable history, while individual dates remain accessible via /learn/daily-coding-challenge/date/:date.
How does the feature support multiple programming languages?
Each database record stores separate javascript and python objects containing language-specific challengeFiles and tests. The ShowDailyCodingChallenge component maintains a dailyCodingChallengeLanguage state (persisted to the client store) and passes the corresponding language data to ShowClassic, allowing seamless toggling between JavaScript and Python implementations without reloading the challenge metadata.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →