chore(repo): restructure as monorepo with server and client workspaces

- move NestJS app into server/ subdirectory
- add client/ React+TypeScript (Vite) app with Hello World
- update docker-compose to build and run both services
- add root package.json declaring npm workspaces
- update .gitignore to cover node_modules and dist at all depths
This commit is contained in:
2026-04-08 21:28:01 +03:00
parent afc4627353
commit 5cc16725fb
88 changed files with 12637 additions and 405 deletions
@@ -0,0 +1,53 @@
import { Injectable } from "@nestjs/common";
import { Interval } from "@nestjs/schedule";
import { ConfigService } from "@nestjs/config";
import { AppConfig } from "../config/app.config";
import { TraceLogger } from "../common/trace-logger";
import { SessionService } from "./session.service";
import { SessionContextService } from "./session-context.service";
/**
* Periodically:
* 1. Closes sessions that have been idle for longer than SESSION_IDLE_TIMEOUT_MINUTES.
* 2. Deletes closed sessions whose updatedAt is older than SESSION_DELETE_CLOSED_DAYS.
*/
@Injectable()
export class SessionSchedulerService {
private readonly logger = new TraceLogger(SessionSchedulerService.name);
constructor(
private readonly sessionService: SessionService,
private readonly sessionContextService: SessionContextService,
private readonly config: ConfigService<AppConfig, true>,
) {}
@Interval(60_000)
async runScheduler(): Promise<void> {
await this.closeExpired();
await this.deleteOldClosed();
}
private async closeExpired(): Promise<void> {
const idleMinutes = this.config.get("SESSION_IDLE_TIMEOUT_MINUTES");
const cutoff = new Date(Date.now() - idleMinutes * 60_000);
const expired = await this.sessionService.findExpiredOpen(cutoff);
for (const session of expired) {
await this.sessionContextService.close(session.sessionName);
this.logger.log(
`Session "${session.sessionName}" closed (idle > ${idleMinutes} min)`,
);
}
}
private async deleteOldClosed(): Promise<void> {
const days = this.config.get("SESSION_DELETE_CLOSED_DAYS");
const cutoff = new Date(Date.now() - days * 86_400_000);
const old = await this.sessionService.findOldClosed(cutoff);
for (const session of old) {
await this.sessionService.remove(session.id);
this.logger.log(
`Session "${session.sessionName}" deleted (closed > ${days} days ago)`,
);
}
}
}