Set up Fastify + TypeScript + Drizzle ORM backend with: - Database schema (7 tables: users, categories, questions, knowledge_cards, user_progress, skill_tree, user_chapter_progress) - JWT auth middleware + admin token auth - Route structure for auth, quiz, progress, gamification, payment, and admin - Service stubs for Phase 1b implementation - Zod-validated env config, custom error classes
30 lines
837 B
TypeScript
30 lines
837 B
TypeScript
import { FastifyInstance } from 'fastify';
|
|
import fp from 'fastify-plugin';
|
|
import { UnauthorizedError, ForbiddenError } from '../utils/errors.js';
|
|
import { config } from '../utils/config.js';
|
|
|
|
async function adminAuthMiddleware(app: FastifyInstance): Promise<void> {
|
|
app.addHook('onRequest', async (request) => {
|
|
if (!request.url.startsWith('/v1/admin')) {
|
|
return;
|
|
}
|
|
|
|
// Skip admin login endpoint
|
|
if (request.url === '/v1/admin/auth') {
|
|
return;
|
|
}
|
|
|
|
const authHeader = request.headers.authorization;
|
|
if (!authHeader?.startsWith('Bearer ')) {
|
|
throw new UnauthorizedError('Missing admin token');
|
|
}
|
|
|
|
const token = authHeader.slice(7);
|
|
if (token !== config.ADMIN_TOKEN) {
|
|
throw new ForbiddenError('Invalid admin token');
|
|
}
|
|
});
|
|
}
|
|
|
|
export default fp(adminAuthMiddleware);
|