Documentation Index Fetch the complete documentation index at: https://mintlify.com/levinbaenninger/quest-hunter/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The Quests API provides endpoints for retrieving quest information, tracking quest progress, and managing quest completion. All endpoints require authentication.
Queries
get
Retrieves a single quest by ID.
import { api } from "@/convex/_generated/api" ;
import { useQuery } from "convex/react" ;
const quest = useQuery ( api . quests . get , { questId });
The unique identifier of the quest to retrieve
The quest object with all fields
Quest Object Structure:
Detailed quest description
Estimated time to complete in minutes
difficulty
'einfach' | 'mittel' | 'schwer'
Quest difficulty level (easy, medium, hard in German)
Experience points awarded for completion
category
'abenteuer' | 'geschichte' | 'kultur' | 'natur' | 'essen' | 'trinken'
Quest category (adventure, history, culture, nature, food, drinks in German)
URL to the quest’s cover image
Errors:
“Quest not found” - The specified quest ID doesn’t exist
“Not authenticated” - User is not logged in
listRecommended
Returns all quests that the user hasn’t completed yet.
import { api } from "@/convex/_generated/api" ;
import { useQuery } from "convex/react" ;
const recommendedQuests = useQuery ( api . quests . listRecommended );
Array of quests the user hasn’t completed
Example Response:
[
{
_id: "quest123" ,
name: "Historical Berlin" ,
description: "Explore the rich history of Berlin" ,
estimatedTime: 120 ,
difficulty: "mittel" ,
xp: 100 ,
category: "geschichte" ,
imageUrl: "https://..."
},
// ... more quests
]
Errors:
“Not authenticated” - User is not logged in
listNew
Returns quests created within the last 7 days that the user hasn’t completed.
import { api } from "@/convex/_generated/api" ;
import { useQuery } from "convex/react" ;
const newQuests = useQuery ( api . quests . listNew );
Array of new quests (created in the last 7 days) that the user hasn’t completed
Implementation:
const SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000 ;
const cutoff = Date . now () - SEVEN_DAYS_MS ;
return allQuests . filter (
( quest ) =>
quest . _creationTime >= cutoff && ! completedQuestIds . has ( quest . _id ),
);
Errors:
“Not authenticated” - User is not logged in
listFinished
Returns all quests the user has completed.
import { api } from "@/convex/_generated/api" ;
import { useQuery } from "convex/react" ;
const finishedQuests = useQuery ( api . quests . listFinished );
Array of quests the user has completed
Errors:
“Not authenticated” - User is not logged in
listInProgress
Returns quest IDs for all quests the user has started but not completed.
import { api } from "@/convex/_generated/api" ;
import { useQuery } from "convex/react" ;
const inProgressQuestIds = useQuery ( api . quests . listInProgress );
Array of quest IDs currently in progress
Example Response:
[ "quest123" , "quest456" , "quest789" ]
Implementation:
const userQuests = await ctx . db
. query ( "userQuests" )
. withIndex ( "by_user" , ( q ) => q . eq ( "userId" , user . _id ))
. filter (( q ) => q . eq ( q . field ( "completedAt" ), undefined ))
. collect ();
return userQuests . map (( uq ) => uq . questId );
Errors:
“Not authenticated” - User is not logged in
getStatus
Retrieves the user’s progress status for a specific quest.
import { api } from "@/convex/_generated/api" ;
import { useQuery } from "convex/react" ;
const questStatus = useQuery ( api . quests . getStatus , { questId });
The quest ID to check status for
The user’s quest progress, or null if not started
UserQuest Object:
Unique user quest record identifier
Unix timestamp when the quest was started
Unix timestamp when the quest was completed (undefined if in progress)
Example Response:
{
_id : "userQuest123" ,
userId : "user456" ,
questId : "quest789" ,
startedAt : 1709481600000 ,
completedAt : undefined // or timestamp if completed
}
Errors:
“Not authenticated” - User is not logged in
Mutations
start
Starts a quest for the current user.
import { api } from "@/convex/_generated/api" ;
import { useMutation } from "convex/react" ;
const startQuest = useMutation ( api . quests . start );
await startQuest ({ questId });
The ID of the quest to start
The ID of the newly created user quest record
Implementation:
return await ctx . db . insert ( "userQuests" , {
userId: user . _id ,
questId ,
startedAt: Date . now (),
});
Errors:
“Quest not found” - The specified quest ID doesn’t exist
“Quest already in progress” - User has already started this quest
“Quest already completed” - User has already completed this quest
“Not authenticated” - User is not logged in
complete
Marks a quest as completed for the current user. Validates that all locations have been visited.
import { api } from "@/convex/_generated/api" ;
import { useMutation } from "convex/react" ;
const completeQuest = useMutation ( api . quests . complete );
await completeQuest ({ questId });
The ID of the quest to complete
Validation Logic:
The mutation performs comprehensive validation:
Checks if the quest has been started
Checks if the quest is already completed
Retrieves all locations for the quest
Retrieves all user-completed locations
Verifies that every required location has been visited
const requiredIds = new Set ( questLocations . map (( l ) => l . _id ));
const completedIds = new Set ( completedLocations . map (( cl ) => cl . locationId ));
if ([ ... requiredIds ]. some (( id ) => ! completedIds . has ( id )))
throw new ConvexError ( "Quest not finished" );
Errors:
“Quest not started” - User hasn’t started this quest yet
“Quest already completed” - User has already completed this quest
“Quest not finished” - Not all required locations have been visited
“Not authenticated” - User is not logged in
Example Usage:
React Component
Error Handling
import { api } from "@/convex/_generated/api" ;
import { useMutation , useQuery } from "convex/react" ;
function QuestCompletion ({ questId }) {
const completeQuest = useMutation ( api . quests . complete );
const locations = useQuery ( api . locations . listByQuest , { questId });
const completed = useQuery ( api . locations . listCompleted , { questId });
const allLocationsVisited =
locations ?. length === completed ?. length ;
const handleComplete = async () => {
try {
await completeQuest ({ questId });
// Show success message
} catch ( error ) {
// Handle errors: "Quest not finished", etc.
}
};
return (
< button
onClick = { handleComplete }
disabled = {! allLocationsVisited }
>
Complete Quest
</ button >
);
}