init: scaffold complet Sakuin — backend NestJS + frontend SvelteKit + CI/CD + deploy VPS
All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 29s

Backend: 5 modules (auth, user, work, list, health), AniList GraphQL proxy,
SuperOAuth PKCE introspection, XP system, migrations TypeORM.
Frontend: SvelteKit adapter-node, PWA manifest, dark theme, pages home/search/list/profile/callback.
Infra: CI/CD Gitea vps-runner, Apache vhost SSL, pm2 sakuin-backend + sakuin-frontend, port 4002.
License: BSL 1.1 (Apache 2.0 en 2028).
This commit is contained in:
2026-03-25 01:43:32 +01:00
commit f1cff74d83
56 changed files with 9891 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
Query,
Req,
UseGuards,
ParseIntPipe,
} from '@nestjs/common';
import { ListService } from './list.service';
import { ListStatus } from './user-work.entity';
import { AuthGuard } from '../auth/auth.guard';
import { UserService } from '../user/user.service';
@Controller('api/list')
@UseGuards(AuthGuard)
export class ListController {
constructor(
private readonly listService: ListService,
private readonly userService: UserService,
) {}
@Get()
async getList(@Req() req: any, @Query('status') status?: ListStatus) {
const user = await this.userService.findOrCreate({
id: req.user.id,
nickname: req.user.nickname,
avatar: req.user.avatar,
});
return this.listService.getUserList(user.id, status);
}
@Post()
async addToList(
@Req() req: any,
@Body() body: { anilistId: number; status: ListStatus },
) {
const user = await this.userService.findOrCreate({
id: req.user.id,
nickname: req.user.nickname,
avatar: req.user.avatar,
});
return this.listService.addToList(user.id, body.anilistId, body.status);
}
@Put(':id/progress')
async updateProgress(
@Req() req: any,
@Param('id', ParseIntPipe) id: number,
@Body() body: { progress: number },
) {
const user = await this.userService.findOrCreate({
id: req.user.id,
nickname: req.user.nickname,
avatar: req.user.avatar,
});
return this.listService.updateProgress(user.id, id, body.progress);
}
@Put(':id/status')
async updateStatus(
@Req() req: any,
@Param('id', ParseIntPipe) id: number,
@Body() body: { status: ListStatus },
) {
const user = await this.userService.findOrCreate({
id: req.user.id,
nickname: req.user.nickname,
avatar: req.user.avatar,
});
return this.listService.updateStatus(user.id, id, body.status);
}
@Put(':id/score')
async setScore(
@Req() req: any,
@Param('id', ParseIntPipe) id: number,
@Body() body: { score: number },
) {
const user = await this.userService.findOrCreate({
id: req.user.id,
nickname: req.user.nickname,
avatar: req.user.avatar,
});
return this.listService.setScore(user.id, id, body.score);
}
@Delete(':id')
async remove(
@Req() req: any,
@Param('id', ParseIntPipe) id: number,
) {
const user = await this.userService.findOrCreate({
id: req.user.id,
nickname: req.user.nickname,
avatar: req.user.avatar,
});
await this.listService.removeFromList(user.id, id);
return { deleted: true };
}
}