217 lines
7.4 KiB
Markdown
217 lines
7.4 KiB
Markdown
# Service Center Migration Plan
|
||
|
||
## Overview
|
||
|
||
This document describes a **step-by-step plan** to migrate from the old `modules/services` (Services hub) to the new `modules/serviceCenter`. The migration is **incremental**—one feature at a time—with UI-driven testing after each step.
|
||
|
||
**Recommended first feature: Chatbot** — it has a clear UI, limited service dependencies, and is already partially using the service center (AI, generation, billing).
|
||
|
||
---
|
||
|
||
## Architecture Summary
|
||
|
||
### Current State
|
||
|
||
| Component | Location | Notes |
|
||
|-----------|----------|-------|
|
||
| **Service Center** | `modules/serviceCenter/` | New: registry, resolver, context-based DI |
|
||
| **Services Hub** | `modules/services/` | Legacy: `getInterface()` → `Services` instance |
|
||
| **Chatbot** | `modules/features/chatbot/` | Uses `getServices()` → `.chat`, `.ai` |
|
||
|
||
### Service Center vs Legacy Services
|
||
|
||
| Aspect | Service Center | Legacy Services |
|
||
|--------|----------------|-----------------|
|
||
| **Constructor** | `(context: ServiceCenterContext, get_service)` | `(services: Services)` — receives hub |
|
||
| **Context** | Minimal: user, mandate_id, feature_instance_id, workflow | Full hub with all interfaces |
|
||
| **Dependencies** | Injected via `get_service("key")` | Via `self.services.<attr>` |
|
||
| **RBAC** | Per-service `objectKey` in registry | Shared via hub |
|
||
| **Pre-warm** | `preWarm()` at app startup | Loaded on first use |
|
||
|
||
### Services Already Using Service Center (in Services class)
|
||
|
||
The `Services` class in `modules/services/__init__.py` already uses `getService()` for:
|
||
|
||
- `messaging`
|
||
- `ai`
|
||
- `generation`
|
||
- `billing`
|
||
|
||
### Services Still Using Legacy Direct Imports
|
||
|
||
- `chat` ← **Target for Phase 1**
|
||
- `sharepoint`
|
||
- `ticket`
|
||
- `utils`
|
||
- `security`
|
||
- `streaming`
|
||
- `extraction`
|
||
- `web`
|
||
|
||
---
|
||
|
||
## Phase 1: Migrate Chatbot to Use Service Center for Chat
|
||
|
||
**Goal:** Switch the Chatbot feature to get the Chat service from Service Center instead of the legacy hub. This validates the full flow with minimal risk.
|
||
|
||
### Step 1.1: Switch Services Class to Use Service Center for Chat
|
||
|
||
**File:** `modules/services/__init__.py`
|
||
|
||
**Change:** Replace the direct ChatService import with `getService("chat", ...)`.
|
||
|
||
```python
|
||
# BEFORE (line ~126-127):
|
||
from .serviceChat.mainServiceChat import ChatService
|
||
self.chat = PublicService(ChatService(self))
|
||
|
||
# AFTER:
|
||
self.chat = PublicService(getService("chat", _ctx, legacy_hub=self))
|
||
```
|
||
|
||
The `_ctx` (ServiceCenterContext) is already created for messaging/ai/generation. Add `workflow=self.workflow` to the context if not already present (it should be—check the existing `_ctx` creation around line 109–116).
|
||
|
||
**Verification:**
|
||
1. Ensure `ServiceCenterContext` includes `workflow` when Services has one (chatbot often passes `workflow=None` initially).
|
||
2. The service center ChatService gets `interfaceDbComponent` from `getInterface(context.user, mandateId=context.mandate_id)` — same as legacy. The chatbot calls `getFileInfo(fileId)` which only needs `interfaceDbComponent`, not workflow.
|
||
|
||
### Step 1.2: Ensure Service Center Context Has Workflow
|
||
|
||
**File:** `modules/services/__init__.py`
|
||
|
||
Verify the existing context creation:
|
||
|
||
```python
|
||
_ctx = ServiceCenterContext(
|
||
user=self.user,
|
||
mandate_id=self.mandateId,
|
||
feature_instance_id=self.featureInstanceId,
|
||
workflow=self.workflow,
|
||
)
|
||
```
|
||
|
||
If `workflow` is missing, add it. The ChatService uses `_context.workflow` for methods like `getChatDocumentsFromDocumentList`; for `getFileInfo` it is not needed.
|
||
|
||
### Step 1.3: Run Unit Tests
|
||
|
||
```powershell
|
||
cd c:\Users\IdaDittrich\Documents\01_Code\gateway
|
||
pytest tests/unit/serviceCenter/test_service_center_imports.py -v
|
||
python tests/scripts/smoke_test_service_center.py
|
||
```
|
||
|
||
### Step 1.4: Manual UI Test — Chatbot with File Upload
|
||
|
||
1. **Start the gateway:**
|
||
```powershell
|
||
cd c:\Users\IdaDittrich\Documents\01_Code\gateway
|
||
uvicorn app:app --reload --host 0.0.0.0 --port 8000
|
||
```
|
||
|
||
2. **Start the frontend** (if using frontend_nyla):
|
||
```powershell
|
||
cd c:\Users\IdaDittrich\Documents\01_Code\frontend_nyla
|
||
npm run dev
|
||
```
|
||
|
||
3. **Log in** as a user with access to the Chatbot feature.
|
||
|
||
4. **Open a Chatbot instance** (navigate to the chatbot feature, select or create an instance).
|
||
|
||
5. **Create a new conversation** — click "New conversation" or equivalent.
|
||
|
||
6. **Attach a file** — upload a PDF or document before sending.
|
||
|
||
7. **Send a message** — e.g. "Summarize this document."
|
||
|
||
8. **Verify:**
|
||
- No 500 errors in gateway logs
|
||
- File is processed (chat service’s `getFileInfo` is used when creating `ChatbotDocument`s)
|
||
- AI response streams back correctly (AI service already from service center)
|
||
|
||
### Step 1.5: Rollback if Needed
|
||
|
||
If something breaks, revert the change in `modules/services/__init__.py`:
|
||
|
||
```python
|
||
from .serviceChat.mainServiceChat import ChatService
|
||
self.chat = PublicService(ChatService(self))
|
||
```
|
||
|
||
---
|
||
|
||
## Phase 2 (Future): Migrate Extraction for Chatbot
|
||
|
||
The chatbot may use extraction when processing documents. After Phase 1 is stable:
|
||
|
||
1. Switch `Services` to use `getService("extraction", _ctx, legacy_hub=self)` instead of direct import.
|
||
2. Ensure `ExtractionService` in service center has the same interface as the legacy one.
|
||
3. Re-test chatbot with document-heavy prompts.
|
||
|
||
---
|
||
|
||
## Phase 3 (Future): Migrate Remaining Services
|
||
|
||
| Service | Used By | Priority |
|
||
|---------|---------|----------|
|
||
| utils | Chat, Extraction, AI, Web, Generation | High (core) |
|
||
| security | Sharepoint | Medium |
|
||
| streaming | Workflows, Chatbot SSE | Medium |
|
||
| sharepoint | Sharepoint workflows | Medium |
|
||
| ticket | Ticket system | Low |
|
||
| web | Web research workflows | Medium |
|
||
|
||
---
|
||
|
||
## Service Center Bootstrap (Already Done)
|
||
|
||
The app already:
|
||
- Calls `preWarm()` at startup (`app.py` lifespan)
|
||
- Has `registerServiceObjects()` available for RBAC catalog (call from bootstrap if needed)
|
||
|
||
### Optional: Register Service RBAC Objects
|
||
|
||
If you want service-level RBAC (e.g. `can_access_service()`), call during bootstrap:
|
||
|
||
```python
|
||
# In app.py lifespan or interfaceBootstrap
|
||
from modules.serviceCenter import registerServiceObjects
|
||
from modules.security.rbacCatalog import getCatalogService
|
||
catalogService = getCatalogService()
|
||
registerServiceObjects(catalogService)
|
||
```
|
||
|
||
---
|
||
|
||
## Testing Checklist (Chatbot Phase 1)
|
||
|
||
- [ ] Unit tests pass: `pytest tests/unit/serviceCenter/ -v`
|
||
- [ ] Smoke test passes: `python tests/scripts/smoke_test_service_center.py`
|
||
- [ ] Gateway starts without import errors
|
||
- [ ] Chatbot UI loads
|
||
- [ ] New conversation creates successfully
|
||
- [ ] Message without file sends and gets AI response
|
||
- [ ] Message with file attachment sends and gets AI response
|
||
- [ ] No errors in gateway logs during the above flows
|
||
|
||
---
|
||
|
||
## File Summary for Phase 1
|
||
|
||
| File | Action |
|
||
|------|--------|
|
||
| `modules/services/__init__.py` | Replace `ChatService` import with `getService("chat", _ctx, legacy_hub=self)` |
|
||
| (No other changes) | Service center ChatService and resolver already support legacy fallback |
|
||
|
||
---
|
||
|
||
## FAQ
|
||
|
||
**Q: Why start with Chat instead of Utils?**
|
||
A: Chat has a clear UI path (chatbot) and only a few call sites. Utils is used everywhere; migrating it later reduces risk.
|
||
|
||
**Q: What if `getService("chat", ctx)` fails?**
|
||
A: The resolver passes `legacy_hub=self`, so it falls back to the legacy `Services.chat` if the service center module fails to load. You get graceful degradation.
|
||
|
||
**Q: Can I test without the frontend?**
|
||
A: Yes. Use the API directly, e.g. `POST /api/chatbot/{instanceId}/start/stream` with a valid `UserInputRequest` (with `listFileId` for file upload).
|