Add initial project structure with Maven, Quarkus, and React setup
- Created .gitignore to exclude build artifacts and IDE files. - Added pom.xml for Maven project configuration, including dependencies for Quarkus, OpenAPI, and testing. - Introduced project documentation outlining development workflow, architecture, and coding standards. - Implemented core business logic with services for authentication, scenario management, story lifecycle, and user management. - Established security context for JWT-based authentication. - Generated API specifications and client code for frontend integration. - Set up initial database entities and repositories for user, scenario, and story management.
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
## StoryTeller Development Workflow
|
||||
|
||||
### Stack and Layout
|
||||
|
||||
- **Backend**: Quarkus 3.31.2 (Java 21, Maven).
|
||||
- **Frontend**: React 18 + TypeScript + Vite in `src/main/web`.
|
||||
- **Database**: PostgreSQL with Liquibase migrations.
|
||||
- **Auth**: SmallRye JWT with RSA key signing; BCrypt password hashing.
|
||||
- **API Contract**: OpenAPI 3.0.3 at `src/main/resources/openapi/story-teller-api.yaml`.
|
||||
- **Generated Code**:
|
||||
- Java interfaces/models: `target/generated-sources/openapi/java/src/gen/java/`
|
||||
- TypeScript client: `src/main/web/src/api/generated/`
|
||||
|
||||
### Local Setup
|
||||
|
||||
1. **Prerequisites**: JDK 21, Maven 3.9+, PostgreSQL, Node.js 22 (managed by frontend-maven-plugin).
|
||||
2. **Database**: Create a PostgreSQL database:
|
||||
```sql
|
||||
CREATE DATABASE storyteller;
|
||||
CREATE USER storyteller WITH PASSWORD 'storyteller';
|
||||
GRANT ALL PRIVILEGES ON DATABASE storyteller TO storyteller;
|
||||
```
|
||||
3. **Build everything**: `mvn package` (generates API code, compiles Java, builds frontend, runs tests).
|
||||
4. **Run in dev mode**: `mvn quarkus:dev` (hot reload, frontend proxy at http://localhost:5173).
|
||||
5. **Frontend dev**: `cd src/main/web && npm run dev` (standalone Vite dev server, proxies `/api` to Quarkus).
|
||||
|
||||
### Default Admin Account
|
||||
|
||||
After first startup, Liquibase seeds an admin user:
|
||||
- **Username**: `admin`
|
||||
- **Password**: `admin`
|
||||
|
||||
Change this immediately in non-development environments.
|
||||
|
||||
### OpenAPI-First Rules
|
||||
|
||||
- The OpenAPI YAML is the **single source of truth** for backend and frontend API contracts.
|
||||
- **Never edit generated files** in `target/generated-sources/` or `src/main/web/src/api/generated/`.
|
||||
- To change the API:
|
||||
1. Edit `src/main/resources/openapi/story-teller-api.yaml`.
|
||||
2. Run `mvn generate-sources` to regenerate Java and TypeScript.
|
||||
3. Update service/resource implementations to match new interfaces.
|
||||
|
||||
### Common Commands
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `mvn generate-sources` | Regenerate Java+TS from OpenAPI |
|
||||
| `mvn compile` | Compile Java backend |
|
||||
| `mvn test` | Run unit tests |
|
||||
| `mvn package` | Full build: Java + frontend + tests |
|
||||
| `mvn quarkus:dev` | Dev mode with hot reload |
|
||||
| `cd src/main/web && npm run dev` | Frontend dev server |
|
||||
|
||||
### Architecture Overview
|
||||
|
||||
```
|
||||
de.neitzel.storyteller
|
||||
├── business/ # Business logic services
|
||||
├── common/
|
||||
│ └── security/ # JWT, password hashing, auth context
|
||||
├── data/
|
||||
│ ├── entity/ # JPA entities
|
||||
│ └── repository/ # Panache repositories
|
||||
└── fascade/
|
||||
├── api/ # Generated OpenAPI interfaces (DO NOT EDIT)
|
||||
├── model/ # Generated OpenAPI models (DO NOT EDIT)
|
||||
└── rest/ # REST resource implementations
|
||||
```
|
||||
|
||||
### Authentication Flow
|
||||
|
||||
1. Client sends `POST /api/auth/login` with username/password.
|
||||
2. Server verifies credentials, returns signed JWT with user claims.
|
||||
3. Client stores JWT in localStorage and sends it as `Authorization: Bearer <token>` on all subsequent requests.
|
||||
4. Quarkus SmallRye JWT validates the token on protected endpoints.
|
||||
5. `AuthContext` (request-scoped CDI bean) extracts user identity from the JWT.
|
||||
|
||||
### Authorization
|
||||
|
||||
- **Public**: `/api/auth/*`
|
||||
- **Admin-only**: `/api/users/*` (user management)
|
||||
- **Authenticated users**: `/api/scenarios/*`, `/api/stories/*` (with per-user ownership checks)
|
||||
|
||||
### Story Generation & Compaction
|
||||
|
||||
The AI step generation flow includes automatic context compaction:
|
||||
|
||||
1. Client sends a direction prompt.
|
||||
2. Server estimates context size (scene + characters + unmerged steps + direction).
|
||||
3. If it exceeds the limit (~12K chars), the oldest half of unmerged steps are compacted into the scene description.
|
||||
4. Steps are marked `addedToScene = true` after compaction.
|
||||
5. The AI generates the next step from the (possibly compacted) context.
|
||||
6. The response includes a `compacted` flag so the frontend can prompt the user to review the updated scene.
|
||||
|
||||
**Note**: The current AI adapter is a stub that generates placeholder text. Replace the `generateAiContinuation` and `compactScene` methods in `StoryService` with actual LLM integration.
|
||||
|
||||
### Testing
|
||||
|
||||
- Unit tests use JUnit 5 + Mockito in `src/test/java/`.
|
||||
- Tests cover auth, user service, scenario service, and story service.
|
||||
- Run with `mvn test`.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
- **JWT errors**: Ensure `privateKey.pem` and `publicKey.pem` exist in `src/main/resources/`.
|
||||
- **Generated code issues**: Run `mvn clean generate-sources` to rebuild from scratch.
|
||||
- **TypeScript errors**: Check that `src/main/web/node_modules` exists; run `npm install` in `src/main/web`.
|
||||
- **DB connection**: Verify PostgreSQL is running and the `storyteller` database/user exist.
|
||||
@@ -0,0 +1,364 @@
|
||||
## Story Teller – Application Specification
|
||||
|
||||
### 1. Overview
|
||||
|
||||
**Story Teller** is a web application where an AI collaboratively builds a story step by step with the user.
|
||||
|
||||
The user starts from a predefined scenario (starting scene and characters), gives directions about what should happen next, optionally edits the scene and characters, and the AI produces the next part of the story. The system manages scenes, story steps, and automatic context compaction when AI prompts become too large.
|
||||
|
||||
---
|
||||
|
||||
### 2. User Roles & Permissions
|
||||
|
||||
#### 2.1 Roles
|
||||
|
||||
- **Regular user**
|
||||
- Authenticate via simple login.
|
||||
- Manage own content:
|
||||
- Create, edit, delete **scenarios** (starting points).
|
||||
- Create, edit, delete **starting characters** associated with their scenarios.
|
||||
- Start new **stories** from scenarios they own.
|
||||
- Load existing stories they own and continue them.
|
||||
- Edit and merge steps, scenes, and characters within their own stories.
|
||||
- Delete their own stories.
|
||||
|
||||
- **Admin user**
|
||||
- All capabilities of regular users.
|
||||
- Additional capabilities:
|
||||
- Create new users.
|
||||
- View list of all users.
|
||||
- Edit user information (e.g., username, admin flag, active flag, password reset).
|
||||
- Delete users (with defined behavior for their content).
|
||||
|
||||
> Anonymous users are not supported; all access is via login.
|
||||
|
||||
---
|
||||
|
||||
### 3. Core Domain Model
|
||||
|
||||
#### 3.1 User
|
||||
|
||||
- **Fields**
|
||||
- `id`
|
||||
- `username` (unique)
|
||||
- `passwordHash`
|
||||
- `isAdmin` (boolean)
|
||||
- `active` (boolean)
|
||||
- `createdAt`
|
||||
- `updatedAt`
|
||||
|
||||
#### 3.2 Scenario (Starting Point)
|
||||
|
||||
- **Fields**
|
||||
- `id`
|
||||
- `ownerUserId`
|
||||
- `title`
|
||||
- `description` (overall scenario description)
|
||||
- `startingSceneDescription` (initial scene narrative text)
|
||||
- `startingCharacters` (list of `ScenarioCharacter`)
|
||||
- `createdAt`
|
||||
- `updatedAt`
|
||||
|
||||
- **ScenarioCharacter**
|
||||
- `id`
|
||||
- `scenarioId`
|
||||
- `name`
|
||||
- `role` (e.g., “protagonist”, “villain”, “guide”)
|
||||
- `description`
|
||||
|
||||
#### 3.3 Story
|
||||
|
||||
- **Fields**
|
||||
- `id`
|
||||
- `ownerUserId`
|
||||
- `scenarioId` (reference to starting scenario)
|
||||
- `title`
|
||||
- `currentSceneDescription` (full narrative of the current scene)
|
||||
- `currentSceneCharacters` (list of `StoryCharacter`)
|
||||
- `status` (e.g., `ACTIVE`, `ARCHIVED`, `DELETED`)
|
||||
- `createdAt`
|
||||
- `updatedAt`
|
||||
|
||||
- **StoryCharacter**
|
||||
- `id`
|
||||
- `storyId`
|
||||
- `name`
|
||||
- `role`
|
||||
- `description`
|
||||
- (Optional) `origin` (e.g., `FROM_SCENARIO`, `ADDED_IN_STORY`)
|
||||
|
||||
#### 3.4 StoryStep
|
||||
|
||||
- Represents a continuation segment in the story.
|
||||
|
||||
- **Fields**
|
||||
- `id`
|
||||
- `storyId`
|
||||
- `stepNumber` (monotonic integer starting from 1)
|
||||
- `content` (text for this step: AI-written and/or user-edited)
|
||||
- `addedToScene` (boolean; `true` if this step has been merged/compacted into the current scene)
|
||||
- `userDirection` (the user’s “what should happen next” text used for this step)
|
||||
- `createdAt`
|
||||
- (Optional) `aiPromptMetadata` (model name, parameters, etc.)
|
||||
|
||||
---
|
||||
|
||||
### 4. Functional Requirements
|
||||
|
||||
#### 4.1 Authentication & User Management
|
||||
|
||||
- **Login**
|
||||
- User provides username and password.
|
||||
- On success, user session is established (e.g., cookie or token-based).
|
||||
- On failure, an error message is displayed.
|
||||
|
||||
- **Admin user management**
|
||||
- **List users**
|
||||
- Paginated list with username, admin flag, active flag, and creation time.
|
||||
- **Create user**
|
||||
- Set username, initial password, and admin flag.
|
||||
- **Edit user**
|
||||
- Change password (reset).
|
||||
- Toggle `isAdmin`.
|
||||
- Toggle `active`.
|
||||
- **Delete user**
|
||||
- Remove user with defined behavior for their content (e.g., soft delete or cascade; to be decided at implementation).
|
||||
|
||||
#### 4.2 Scenario & Starting Characters Management
|
||||
|
||||
- **Create scenario**
|
||||
- User defines:
|
||||
- Title.
|
||||
- Overall description (optional).
|
||||
- Starting scene description.
|
||||
- Initial set of starting characters (name, role, description).
|
||||
|
||||
- **Edit scenario**
|
||||
- Update title, descriptions, and characters:
|
||||
- Add, edit, remove `ScenarioCharacter`s.
|
||||
|
||||
- **Delete scenario**
|
||||
- User can delete their own scenarios.
|
||||
- Behavior if stories exist for this scenario (e.g., forbid deletion or only mark the scenario as inactive) is defined at implementation.
|
||||
|
||||
- **List scenarios**
|
||||
- Users see only scenarios they own.
|
||||
- Admins can see all scenarios.
|
||||
|
||||
#### 4.3 Story Lifecycle
|
||||
|
||||
- **Start new story from a scenario**
|
||||
- User selects a scenario.
|
||||
- System initializes a `Story`:
|
||||
- `currentSceneDescription` from `startingSceneDescription`.
|
||||
- `currentSceneCharacters` from `startingCharacters`.
|
||||
- No `StoryStep`s initially.
|
||||
- User can optionally set a custom story title.
|
||||
|
||||
- **Load existing story**
|
||||
- User sees a list of their stories (title, originating scenario, last updated).
|
||||
- Selecting a story shows:
|
||||
- Current scene.
|
||||
- Current scene characters.
|
||||
- Story step list with `stepNumber` and `addedToScene` flag.
|
||||
- Input area for “what should happen next”.
|
||||
|
||||
- **Delete story**
|
||||
- Users can delete their own stories.
|
||||
- Implementation can choose soft delete (recommended) or hard delete.
|
||||
|
||||
---
|
||||
|
||||
### 5. Story Interaction & AI Behavior
|
||||
|
||||
#### 5.1 User Actions Per Step
|
||||
|
||||
On an active story, the user can:
|
||||
|
||||
- **Enter a description of what should happen next**
|
||||
- Free text input for the direction of the next step.
|
||||
|
||||
- **Modify the current scene**
|
||||
- Direct text editing of `currentSceneDescription`.
|
||||
- Or AI-assisted edit:
|
||||
- User describes desired changes.
|
||||
- AI proposes modified scene text.
|
||||
- User can accept, reject, or further edit the proposal.
|
||||
|
||||
- **Modify current characters**
|
||||
- Directly:
|
||||
- Change name, role, or description of existing characters.
|
||||
- Remove characters.
|
||||
- Add new characters.
|
||||
- Or AI-assisted:
|
||||
- User describes desired character changes (e.g., “make the mentor more mysterious”).
|
||||
- AI proposes updates to character fields.
|
||||
- User confirms or edits these suggestions.
|
||||
|
||||
#### 5.2 Request Payload to AI (Normal Case)
|
||||
|
||||
When generating the next story step without compaction:
|
||||
|
||||
- **Request to AI must include:**
|
||||
- **Current scene**
|
||||
- `currentSceneDescription`.
|
||||
- `currentSceneCharacters` (list of name, role, description).
|
||||
- **User direction**
|
||||
- The user’s text describing what should happen next for this step.
|
||||
- **Unmerged steps**
|
||||
- All `StoryStep` entries where `addedToScene == false`.
|
||||
- Steps are sent in chronological order as additional context after the scene.
|
||||
|
||||
- **AI output**
|
||||
- Narrative text for the next part of the story (step content).
|
||||
|
||||
- **System actions**
|
||||
- Create a new `StoryStep` with:
|
||||
- `stepNumber = max(existing stepNumber) + 1`.
|
||||
- `content = AI response` (subsequently editable by user).
|
||||
- `addedToScene = false`.
|
||||
- `userDirection` stored for this step.
|
||||
|
||||
#### 5.3 Context Compaction Flow (When Prompt Too Large)
|
||||
|
||||
If the combined size of:
|
||||
- Current scene description,
|
||||
- Current characters,
|
||||
- All unmerged steps,
|
||||
- And the new user direction
|
||||
|
||||
exceeds the AI model’s context limits, the system performs a **compaction phase** before requesting a new step.
|
||||
|
||||
**Compaction phase (first AI call):**
|
||||
|
||||
- Send to the AI:
|
||||
- The current scene (description and characters).
|
||||
- A subset of the unmerged `StoryStep`s, typically the oldest half of them.
|
||||
- Ask the AI to:
|
||||
- Merge and compact this information into a new, coherent scene description.
|
||||
- Optionally adjust character descriptions to reflect changes implied by the merged steps.
|
||||
|
||||
**Update of domain state:**
|
||||
|
||||
- Replace `currentSceneDescription` with the compacted scene from the AI.
|
||||
- Update `currentSceneCharacters` if the AI returned updated characters.
|
||||
- Mark the merged `StoryStep`s as:
|
||||
- `addedToScene = true`.
|
||||
|
||||
**Repeated compaction (if needed):**
|
||||
|
||||
- If context is still too large, repeat the compaction step with the remaining unmerged steps until:
|
||||
- The full story history is representable by:
|
||||
- One current scene,
|
||||
- Current characters,
|
||||
- A small remaining set of unmerged steps.
|
||||
|
||||
**User review after compaction:**
|
||||
|
||||
- Show the **new current scene and characters** to the user.
|
||||
- Allow:
|
||||
- Direct editing of the compacted scene and characters.
|
||||
- AI-assisted modification (prompt–suggest–accept/edit loop).
|
||||
- Once the user is satisfied, they can:
|
||||
- Enter new “what should happen next” text.
|
||||
- Trigger the normal “generate next step” AI call, which uses the compacted scene plus remaining unmerged steps.
|
||||
|
||||
---
|
||||
|
||||
### 6. Frontend UX Requirements
|
||||
|
||||
#### 6.1 Login & Admin Screens
|
||||
|
||||
- **Login page**
|
||||
- Username and password fields.
|
||||
- Button to log in.
|
||||
- Display of error messages for invalid credentials.
|
||||
|
||||
- **Admin user management**
|
||||
- User list table showing:
|
||||
- Username.
|
||||
- Admin flag.
|
||||
- Active flag.
|
||||
- Actions:
|
||||
- Create user (form).
|
||||
- Edit user (change password, toggle admin/active).
|
||||
- Delete user.
|
||||
|
||||
#### 6.2 Scenario Management UI
|
||||
|
||||
- **Scenario list**
|
||||
- Displays scenarios owned by the logged-in user.
|
||||
- Actions:
|
||||
- Create scenario.
|
||||
- Edit scenario.
|
||||
- Delete scenario.
|
||||
|
||||
- **Scenario editor**
|
||||
- Fields:
|
||||
- Title.
|
||||
- Scenario description.
|
||||
- Starting scene description.
|
||||
- Character list:
|
||||
- For each character: name, role, description.
|
||||
- Add / edit / delete characters.
|
||||
|
||||
#### 6.3 Story Workspace UI
|
||||
|
||||
For a selected story, the workspace should provide:
|
||||
|
||||
- **Current scene panel**
|
||||
- Read-only by default with buttons:
|
||||
- “Edit Scene” (direct text edit).
|
||||
- “AI Edit Scene” (prompt-based suggestion).
|
||||
|
||||
- **Characters panel**
|
||||
- List of characters with name, role, and description.
|
||||
- Actions:
|
||||
- Add character.
|
||||
- Edit character.
|
||||
- Remove character.
|
||||
- “AI Suggest Character Changes”.
|
||||
|
||||
- **Steps panel**
|
||||
- List of steps with:
|
||||
- Step number.
|
||||
- Short preview of `content`.
|
||||
- Badge or indicator for `addedToScene` vs not.
|
||||
- Clicking a step expands to show full `content`.
|
||||
|
||||
- **Next step input**
|
||||
- Text area: “What should happen next?”
|
||||
- Button: “Generate Next Step”.
|
||||
|
||||
- **Compaction UX**
|
||||
- When compaction is triggered:
|
||||
- Show progress indication.
|
||||
- After completion, present the updated current scene and characters.
|
||||
- Provide:
|
||||
- “Accept Scene” (continue).
|
||||
- “Edit Scene” (direct or AI-assisted).
|
||||
|
||||
---
|
||||
|
||||
### 7. Non-Functional Requirements (High-Level)
|
||||
|
||||
- **Persistence**
|
||||
- Use a relational database to store `User`, `Scenario`, `ScenarioCharacter`, `Story`, `StoryCharacter`, and `StoryStep`.
|
||||
|
||||
- **AI integration**
|
||||
- Backend component to:
|
||||
- Build AI prompts from current scene, characters, user direction, and steps.
|
||||
- Check approximate prompt size against model limits.
|
||||
- Trigger compaction workflow when limits are exceeded.
|
||||
|
||||
- **Security**
|
||||
- Authorization checks ensure:
|
||||
- Users only access and modify their own scenarios and stories.
|
||||
- Admin endpoints/actions are restricted to admin users.
|
||||
|
||||
- **Auditability**
|
||||
- Store:
|
||||
- `userDirection` and AI-generated `content` per `StoryStep`.
|
||||
- Optional metadata about AI calls for debugging and analysis.
|
||||
|
||||
This specification describes the intended behavior and structure of the Story Teller application across users, scenarios, stories, AI integration, and frontend UX.
|
||||
Reference in New Issue
Block a user