Develop and maintain Convex backend functions including queries, mutations, and actions. Use when working with database operations, authentication, game management, scoring logic, and real-time data updates in the dev-quiz-battle app.
This skill covers building and maintaining Convex backend functions for the dev-quiz-battle application.
The Convex backend is located in the convex/ directory with:
queries/ - Read-only functions (games, users, answers, leaderboard)mutations/ - Write operations (creating games, submitting answers, updating user scores)actions/ - Long-running operations (AI question generation)schema.ts - Database schema definitionauth.ts - Authentication configurationQueries fetch data from the database without modifying it. Common patterns:
import { query } from "convex/server";
import { v } from "convex/values";
export const getGameData = query({
args: { gameCode: v.string() },
handler: async (ctx, args) => {
const game = await ctx.db
.query("games")
.filter((q) => q.eq(q.field("code"), args.gameCode))
.first();
return game;
},
});
Mutations modify the database state. Always validate input:
import { mutation } from "convex/server";
import { v } from "convex/values";
export const createGame = mutation({
args: { creatorId: v.id("users"), language: v.string() },
handler: async (ctx, args) => {
const gameId = await ctx.db.insert("games", {
creatorId: args.creatorId,
language: args.language,
code: generateUniqueCode(),
status: "waiting",
createdAt: Date.now(),
});
return gameId;
},
});
Actions handle async operations like API calls:
import { action } from "convex/server";
import { v } from "convex/values";
export const generateQuestion = action({
args: { language: v.string(), difficulty: v.string() },
handler: async (ctx, args) => {
// Call external API or perform async work
const response = await fetch("https://api.example.com/questions");
return response.json();
},
});
Access the authenticated user:
const identity = await ctx.auth.getUserIdentity();
if (!identity) {
throw new Error("Not authenticated");
}
const userId = identity.subject;
Always validate arguments using Convex validators: