Untitled

 avatar
unknown
plain_text
10 days ago
7.8 kB
6
Indexable
# System Design - Analiza Potrzeb Klienta (APK)

## 1. Model Bazodanowy

### Tabele

#### QuestionGroup
```sql
CREATE TABLE question_group (
    id BIGINT PRIMARY KEY,
    code VARCHAR(50) NOT NULL, -- np. MAIN_RISKS, ADDITIONAL_RISKS
    active BOOLEAN DEFAULT true
);
```

#### Question
```sql
CREATE TABLE question (
    id BIGINT PRIMARY KEY,
    group_id BIGINT REFERENCES question_group(id),
    question_order INT NOT NULL,
    dependent_on_question_id BIGINT REFERENCES question(id),
    dependent_on_answer_id BIGINT REFERENCES answer(id),
    active BOOLEAN DEFAULT true
);
```

#### QuestionContent
```sql
CREATE TABLE question_content (
    id BIGINT PRIMARY KEY,
    question_id BIGINT REFERENCES question(id),
    language_code VARCHAR(5), -- np. pl_PL, en_GB
    content TEXT NOT NULL
);
```

#### Answer
```sql
CREATE TABLE answer (
    id BIGINT PRIMARY KEY,
    question_id BIGINT REFERENCES question(id),
    answer_order INT NOT NULL,
    code VARCHAR(50) NOT NULL,
    active BOOLEAN DEFAULT true
);
```

#### AnswerContent
```sql
CREATE TABLE answer_content (
    id BIGINT PRIMARY KEY,
    answer_id BIGINT REFERENCES answer(id),
    language_code VARCHAR(5),
    content TEXT NOT NULL
);
```

#### CustomerQuestionnaire
```sql
CREATE TABLE customer_questionnaire (
    id BIGINT PRIMARY KEY,
    customer_id BIGINT NOT NULL,
    quote_id BIGINT NOT NULL,
    group_id BIGINT REFERENCES question_group(id),
    status VARCHAR(20) NOT NULL, -- IN_PROGRESS, COMPLETED
    created_at TIMESTAMP NOT NULL,
    completed_at TIMESTAMP
);
```

#### CustomerAnswer
```sql
CREATE TABLE customer_answer (
    id BIGINT PRIMARY KEY,
    questionnaire_id BIGINT REFERENCES customer_questionnaire(id),
    question_id BIGINT REFERENCES question(id),
    answer_id BIGINT REFERENCES answer(id),
    answered_at TIMESTAMP NOT NULL
);
```

## 2. API Endpoints

### Backend (Java Spring Boot)

#### 2.1 Inicjalizacja procesu APK
```
POST /api/v1/apk/questionnaire
Request:
{
    "customerId": long,
    "quoteId": long,
    "groupCode": string // MAIN_RISKS lub ADDITIONAL_RISKS
}

Response:
{
    "questionnaireId": long,
    "firstQuestion": {
        "id": long,
        "order": int,
        "content": string,
        "answers": [
            {
                "id": long,
                "content": string
            }
        ]
    }
}
```

#### 2.2 Zapisanie odpowiedzi i pobranie kolejnego pytania
```
POST /api/v1/apk/questionnaire/{questionnaireId}/answer
Request:
{
    "questionId": long,
    "answerId": long,
    "isChange": boolean  // flaga określająca czy to zmiana odpowiedzi
}

Response:
{
    "status": "IN_PROGRESS" | "COMPLETED",
    "nextQuestion": {
        "id": long,
        "order": int,
        "content": string,
        "answers": [
            {
                "id": long,
                "content": string
            }
        ]
    } | null,
    "recommendation": {
        "packageCode": string,
        "description": string
    } | null,
    "removedQuestionIds": [long],  // lista ID pytań, których odpowiedzi zostały usunięte
    "resetToQuestionOrder": int | null  // informacja do którego pytania wrócić po zmianie
}
```

#### 2.3 Pobranie aktualnego statusu kwestionariusza
```
GET /api/v1/apk/questionnaire/{questionnaireId}
Response:
{
    "status": "IN_PROGRESS" | "COMPLETED",
    "answeredQuestions": [
        {
            "questionId": long,
            "questionContent": string,
            "questionOrder": int,
            "answerId": long,
            "answerContent": string,
            "answeredAt": timestamp
        }
    ],
    "currentQuestion": {
        "id": long,
        "order": int,
        "content": string,
        "answers": [...]
    } | null,
    "recommendation": {
        "packageCode": string,
        "description": string
    } | null
}
```

### Frontend (Angular)

#### Serwisy

```typescript
// apk.service.ts
@Injectable({
    providedIn: 'root'
})
export class ApkService {
    constructor(private http: HttpClient) {}

    initializeQuestionnaire(
        customerId: number, 
        quoteId: number, 
        groupCode: string
    ): Observable<QuestionnaireInitResponse> {
        return this.http.post<QuestionnaireInitResponse>(
            '/api/v1/apk/questionnaire',
            { customerId, quoteId, groupCode }
        );
    }

    submitAnswer(
        questionnaireId: number,
        questionId: number,
        answerId: number,
        isChange: boolean = false
    ): Observable<AnswerResponse> {
        return this.http.post<AnswerResponse>(
            `/api/v1/apk/questionnaire/${questionnaireId}/answer`,
            { questionId, answerId, isChange }
        );
    }

    getQuestionnaireStatus(
        questionnaireId: number
    ): Observable<QuestionnaireStatus> {
        return this.http.get<QuestionnaireStatus>(
            `/api/v1/apk/questionnaire/${questionnaireId}`
        );
    }
}
```

## 3. Flow procesu

### 3.1 Standardowy flow

1. **Inicjalizacja**:
   - Frontend otrzymuje oferty ubezpieczeniowe
   - Jeśli oferta zawiera AC lub OC+AC:
     - Wywołuje endpoint inicjalizacji z `groupCode=MAIN_RISKS`
     - Wyświetla pierwsze pytanie z otrzymanej odpowiedzi

2. **Proces pytań głównych**:
   - Po każdej odpowiedzi użytkownika:
     - Frontend wywołuje endpoint submit answer z `isChange=false`
     - Jeśli otrzyma kolejne pytanie - wyświetla je
     - Jeśli otrzyma rekomendację - zapisuje ją i przechodzi do następnego kroku

3. **Inicjalizacja pytań dodatkowych**:
   - Frontend wywołuje endpoint inicjalizacji z `groupCode=ADDITIONAL_RISKS`
   - Proces analogiczny jak dla pytań głównych

### 3.2 Flow zmiany odpowiedzi

1. **Zmiana odpowiedzi**:
   - Użytkownik zmienia odpowiedź na wcześniejsze pytanie
   - Frontend wywołuje endpoint submit answer z `isChange=true`
   - Backend:
     - Aktualizuje odpowiedź w bazie danych
     - Usuwa wszystkie odpowiedzi na pytania o wyższym order
     - Sprawdza logikę biznesową dla nowej ścieżki

2. **Obsługa odpowiedzi przez Frontend**:
   - Po otrzymaniu odpowiedzi z `removedQuestionIds`:
     - Usuwa z lokalnego stanu odpowiedzi na wskazane pytania
     - Jeśli otrzymał `resetToQuestionOrder`:
       - Wraca do pytania o wskazanym order
       - Czyści wszystkie późniejsze odpowiedzi
     - Aktualizuje interfejs użytkownika
     - Czyści rekomendację jeśli proces wraca do wcześniejszego etapu

### 3.3 Flow przywracania sesji

1. **Powrót do procesu**:
   - Frontend wywołuje GET /api/v1/apk/questionnaire/{questionnaireId}
   - Na podstawie odpowiedzi:
     - Jeśli status "COMPLETED" - wyświetla podsumowanie i rekomendację
     - Jeśli status "IN_PROGRESS" - wyświetla currentQuestion
     - Wypełnia historię odpowiedzi na podstawie answeredQuestions

## 4. Rozszerzalność

System zaprojektowano z myślą o:
- Dodawaniu nowych pytań i odpowiedzi (przez strukturę tabel)
- Wsparciu wielu języków (przez tabele *Content)
- Możliwości uzależniania pytań od poprzednich odpowiedzi
- Łatwym dodawaniu nowych grup pytań
- Śledzeniu historii odpowiedzi klienta
- Obsłudze złożonych scenariuszy zmiany odpowiedzi

## 5. Podział odpowiedzialności

### Backend
- Przechowywanie definicji pytań i odpowiedzi
- Logika wyboru kolejnych pytań
- Wyliczanie rekomendacji
- Walidacja odpowiedzi
- Persystencja danych
- Zarządzanie procesem sekwencyjnym odpowiedzi
- Obsługa usuwania odpowiedzi na późniejsze pytania

### Frontend
- Prezentacja pytań i odpowiedzi
- Obsługa interakcji z użytkownikiem
- Zarządzanie stanem procesu
- Prezentacja rekomendacji
- Obsługa wielojęzyczności UI
- Zarządzanie nawigacją między pytaniami
- Obsługa resetu procesu po zmianie odpowiedzi
Leave a Comment