feat(#82): implement Personality Module

- Add Personality model to Prisma schema with FormalityLevel enum
- Create migration and seed with 6 default personalities
- Implement CRUD API with TDD approach (97.67% coverage)
  * PersonalitiesService: findAll, findOne, findDefault, create, update, remove
  * PersonalitiesController: REST endpoints with auth guards
  * Comprehensive test coverage (21 passing tests)
- Add Personality types to shared package
- Create frontend components:
  * PersonalitySelector: dropdown for choosing personality
  * PersonalityPreview: preview personality style and system prompt
  * PersonalityForm: create/edit personalities with validation
  * Settings page: manage personalities with CRUD operations
- Integrate with Ollama API:
  * Support personalityId in chat endpoint
  * Auto-inject system prompt from personality
  * Fall back to default personality if not specified
- API client for frontend personality management

All tests passing with 97.67% backend coverage (exceeds 85% requirement)
This commit is contained in:
Jason Woltje
2026-01-29 17:57:54 -06:00
parent 95833fb4ea
commit 5dd46c85af
43 changed files with 4782 additions and 2 deletions

View File

@@ -0,0 +1,77 @@
import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
Query,
UseGuards,
Req,
} from "@nestjs/common";
import { AuthGuard } from "../auth/guards/auth.guard";
import { PersonalitiesService } from "./personalities.service";
import { CreatePersonalityDto, UpdatePersonalityDto } from "./dto";
import { Personality } from "./entities/personality.entity";
@Controller("personalities")
@UseGuards(AuthGuard)
export class PersonalitiesController {
constructor(private readonly personalitiesService: PersonalitiesService) {}
/**
* Get all personalities for the current workspace
*/
@Get()
async findAll(
@Req() req: any,
@Query("isActive") isActive: boolean = true,
): Promise<Personality[]> {
return this.personalitiesService.findAll(req.workspaceId, isActive);
}
/**
* Get the default personality for the current workspace
*/
@Get("default")
async findDefault(@Req() req: any): Promise<Personality> {
return this.personalitiesService.findDefault(req.workspaceId);
}
/**
* Get a specific personality by ID
*/
@Get(":id")
async findOne(@Req() req: any, @Param("id") id: string): Promise<Personality> {
return this.personalitiesService.findOne(req.workspaceId, id);
}
/**
* Create a new personality
*/
@Post()
async create(@Req() req: any, @Body() dto: CreatePersonalityDto): Promise<Personality> {
return this.personalitiesService.create(req.workspaceId, dto);
}
/**
* Update an existing personality
*/
@Put(":id")
async update(
@Req() req: any,
@Param("id") id: string,
@Body() dto: UpdatePersonalityDto,
): Promise<Personality> {
return this.personalitiesService.update(req.workspaceId, id, dto);
}
/**
* Delete a personality
*/
@Delete(":id")
async remove(@Req() req: any, @Param("id") id: string): Promise<Personality> {
return this.personalitiesService.remove(req.workspaceId, id);
}
}