feat: settings — key/value store with CRUD API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Vantz Stockwell 2026-03-12 17:09:08 -04:00
parent 5762eb706e
commit 6fa8f6c5d8
3 changed files with 65 additions and 0 deletions

View File

@ -0,0 +1,19 @@
import { Controller, Get, Put, Body, UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { SettingsService } from './settings.service';
@UseGuards(JwtAuthGuard)
@Controller('settings')
export class SettingsController {
constructor(private settings: SettingsService) {}
@Get()
getAll() {
return this.settings.getAll();
}
@Put()
update(@Body() body: Record<string, string>) {
return this.settings.setMany(body);
}
}

View File

@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { SettingsService } from './settings.service';
import { SettingsController } from './settings.controller';
@Module({
providers: [SettingsService],
controllers: [SettingsController],
exports: [SettingsService],
})
export class SettingsModule {}

View File

@ -0,0 +1,36 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
@Injectable()
export class SettingsService {
constructor(private prisma: PrismaService) {}
async getAll(): Promise<Record<string, string>> {
const settings = await this.prisma.setting.findMany();
return Object.fromEntries(settings.map((s) => [s.key, s.value]));
}
async get(key: string): Promise<string | null> {
const setting = await this.prisma.setting.findUnique({ where: { key } });
return setting?.value ?? null;
}
async set(key: string, value: string) {
return this.prisma.setting.upsert({
where: { key },
update: { value },
create: { key, value },
});
}
async setMany(settings: Record<string, string>) {
const ops = Object.entries(settings).map(([key, value]) =>
this.prisma.setting.upsert({ where: { key }, update: { value }, create: { key, value } }),
);
return this.prisma.$transaction(ops);
}
async remove(key: string) {
return this.prisma.setting.delete({ where: { key } }).catch(() => null);
}
}