mirror of
https://github.com/jjbrunton/Sauci.git
synced 2026-11-02 10:19:43 +00:00
feat(backend): add standalone data plane
Replace the Supabase application data plane with the Node/PostgreSQL API, migrate mobile, admin, web, and MCP callers, add controlled cutover tooling, and define hardened Dokploy infrastructure.
This commit is contained in:
1 parent
01bb8225ae
commit
006761d3b0
294 files changed
+16259
-6138
No files matched your search
@@ -0,0 +1,46 @@
|
||||
import type { ApiErrorResponse } from '@sauci/shared';
|
||||
import type { Hono } from 'hono';
|
||||
import { z } from 'zod';
|
||||
import type { AuthIdentity } from '../../auth.js';
|
||||
import { PacksDomainError, type PacksRepository } from './repository.js';
|
||||
|
||||
type PacksApp = Hono<{ Variables: { identity: AuthIdentity } }>;
|
||||
|
||||
const uuidSchema = z.string().uuid();
|
||||
const toggleSchema = z.object({ enabled: z.boolean() }).strict();
|
||||
|
||||
function error(code: string, message: string): ApiErrorResponse {
|
||||
return { error: { code, message } };
|
||||
}
|
||||
|
||||
export function registerPackRoutes(app: PacksApp, repository: PacksRepository): void {
|
||||
app.get('/v1/packs', async (c) => {
|
||||
const showAll = c.req.query('showAllIntensities') === 'true';
|
||||
return c.json(await repository.getCatalog(c.get('identity').id, showAll));
|
||||
});
|
||||
|
||||
app.get('/v1/me/enabled-packs', async (c) =>
|
||||
c.json(await repository.getEnabledPacks(c.get('identity').id)));
|
||||
|
||||
app.put('/v1/me/enabled-packs/:packId', async (c) => {
|
||||
const packId = uuidSchema.safeParse(c.req.param('packId'));
|
||||
if (!packId.success) return c.json(error('invalid_pack_id', 'Pack ID must be a UUID'), 400);
|
||||
const body = toggleSchema.safeParse(await c.req.json().catch(() => null));
|
||||
if (!body.success) return c.json(error('invalid_request', 'enabled must be a boolean'), 400);
|
||||
try {
|
||||
return c.json(await repository.setPackEnabled(c.get('identity').id, packId.data, body.data.enabled));
|
||||
} catch (cause) {
|
||||
if (cause instanceof PacksDomainError && cause.code === 'no_couple') {
|
||||
return c.json(error('no_couple', 'Join a couple before changing packs'), 409);
|
||||
}
|
||||
if (cause instanceof PacksDomainError && cause.code === 'pack_not_found') {
|
||||
return c.json(error('pack_not_found', 'Pack was not found'), 404);
|
||||
}
|
||||
throw cause;
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/v1/me/pack-progress', async (c) =>
|
||||
c.json(await repository.getPackProgress(c.get('identity').id)));
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user