Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .agent/task-state.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"28": {
"issue": 28,
"branch": "feat/28-eva-mobile-client",
"state": "In Progress",
"updated_at": 1793875471,
"evidence_summary": "Evidence accepted: active task branch verified."
}
}
5 changes: 4 additions & 1 deletion .agents/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@
- **Sweet-Spot Cohesion & Modularity**:
- Keep files cohesive; extract independent timers, custom painters, and multi-step modals into dedicated widget files while keeping local layout together.
- See [.agents/rules/cohesion-and-modularity.md](file:///home/mashupsoat/Project/eva-ecosystem/.agents/rules/cohesion-and-modularity.md) for natural separation criteria.
- **Component Reuse & Single Source of Truth**:
- Before creating new UI elements or duplicate styling, always verify and reuse existing widgets in `apps/eva_mobile/lib/widgets/` (e.g. `AppBackButton`, `GlassCard`, `AppSnackBar`) or feature widgets. Never declare manual inline back buttons across screens.
- **Hierarchical Workspace Scopes**:
- Flutter Mobile: Follow [apps/eva_mobile/AGENTS.md](file:///home/mashupsoat/Project/eva-ecosystem/apps/eva_mobile/AGENTS.md) (Clean Architecture, Riverpod DI, Pure Dart models).
- Backend API: Follow [apps/backend/AGENTS.md](file:///home/mashupsoat/Project/eva-ecosystem/apps/backend/AGENTS.md) (FastAPI routes, Pydantic schemas, Alembic migrations, FastMCP).
- Backend API: Follow [apps/backend/AGENTS.md](file:///home/mashupsoat/Project/eva-ecosystem/apps/backend/AGENTS.md) and [.agents/rules/backend-clean-architecture.md](file:///home/mashupsoat/Project/eva-ecosystem/.agents/rules/backend-clean-architecture.md) (Thin routes 3-5 lines, modular services/schemas, centralized DI, Alembic migrations).
- AI & Orchestration: Follow [packages/ai/AGENTS.md](file:///home/mashupsoat/Project/eva-ecosystem/packages/ai/AGENTS.md) (Abstract Base Classes, LLM/TTS factories, graceful fallbacks).
- **Available Skills**:
- `monorepo-ops`: Docker dev/prod, Alembic migrations, database resets, and backend service runner.
Expand All @@ -61,6 +63,7 @@
## 5. Supervised Autonomous Development Coordination Policies

- **Human-Owned Tasks**: Every task has a single human developer owner. AI agents code only on the task selected by the developer and must never auto-claim or auto-assign tasks.
- **Issue Mutation Review Gate**: The AI agent must never create, edit, close, or delete GitHub Issues autonomously. All additions, updates, or deletions must be presented to the developer (via draft/dry-run) and receive explicit review and approval before execution.
- **Identity Preflight Mandatory**: Before modifying code or updating task status, verify local identity via `python3 scripts/agentic/doctor.py`. If identity is missing, prompt developer to run `python3 scripts/agentic/bootstrap.py`.
- **Session Context Reconciliation**: At the beginning of a session, inspect active context via `python3 scripts/agentic/tasks.py` to reconcile local and remote state.
- **Strict Branch & Worktree Naming**: All branches must follow `{type}/{issue-number}-{short-kebab-slug}` where type is one of `feat`, `fix`, `refactor`, `docs`, `test`, `chore`. Personal branches (`dev/{name}`) are prohibited.
Expand Down
15 changes: 8 additions & 7 deletions .agents/rules/abstraction-and-mock-prod.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,17 +122,18 @@ class LLMFactory:
```

### 2.3 Dependency Injection di FastAPI Endpoints
Endpoint di `apps/backend/api/app/api/routes` **DILARANG KERAS** menginisialisasi provider atau service konkret secara manual di dalam handler fungsi. Gunakan `Depends()`:
Endpoint di `apps/backend/api/app/api/routes` **DILARANG KERAS** menginisialisasi provider atau service konkret secara manual di dalam handler fungsi, dan dilarang mengorkestrasi provider AI/DB langsung di dalam router. Router wajib menginjeksi Domain Service via `Depends()`:
```python
# ✅ BENAR: Menggunakan Dependency Injection
@router.post("/chat/completions")
# ✅ BENAR: Menggunakan Domain Service Injection & Pydantic response_model
@router.post("/chat/completions", response_model=ChatCompletionResponse)
async def chat_completion(
payload: ChatRequest,
llm: BaseLLMProvider = Depends(get_llm_provider),
db: AsyncSession = Depends(get_db_session)
):
return await llm.generate_response(payload.message)
service: ConversationService = Depends(get_conversation_service),
) -> ChatCompletionResponse:
"""Delegasikan prompt generation dan DB logging ke service domain."""
return await service.generate_chat_reply(payload)
```
> **Catatan Arsitektur:** Provider konkret (`BaseLLMProvider`) diinjeksi ke dalam `ConversationService` melalui factory di `app/api/dependencies.py`, bukan di dalam router handler.

---

Expand Down
1 change: 1 addition & 0 deletions .agents/rules/agentic-workflow-constraints.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This document establishes non-negotiable architectural boundaries and safety con

- **Human Accountability**: Every task has a single human developer owner. The AI agent acts as a supervised pair programmer, not an unconstrained autonomous actor.
- **No Unsolicited Work**: The agent must never initiate unassigned tasks, switch tasks, or create speculative branches without explicit human developer instruction.
- **Issue Mutation Review Gate**: The agent must never autonomously create, edit, close, or delete GitHub Issues without presenting the proposal (draft/dry-run) to the developer and obtaining explicit review and approval first.
- **Crash Invariant**: If the agent process terminates or crashes, **no automated state transition or recovery occurs**. The task remains in its last verified state until the developer resumes the session.
- **No Autonomous Handoff (Phase 1)**: Cross-developer delegation, auto-claim bots, and autonomous cross-agent orchestrators are strictly out of scope.

Expand Down
171 changes: 171 additions & 0 deletions .agents/rules/backend-clean-architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
---
trigger: model_decision
description: Aturan dan standar Clean Architecture, Thin Routers (3-5 baris), modular services (app/services/{module}/), dan schemas (app/schemas/{module}/) untuk backend FastAPI di apps/backend.
---

# FastAPI Clean Architecture & Modular Backend Standards

> **Scope:** `apps/backend/api/**`, `apps/backend/workers/**`, `apps/backend/mcp/**`
> **Tujuan:** Menjamin kode backend selalu menerapkan prinsip *Clean Architecture*, *Single Responsibility Principle* (SRP), *Dependency Injection* (DI), dan pemisahan modular berbasis domain agar setiap route handler sangat bersih (3–5 baris) dan tidak ada lagi *fat controllers* atau duplikasi kode.

---

## 1. Struktur Organisasi Modul (`services/` & `schemas/`)

Seluruh domain bisnis di `apps/backend/api/app` **wajib** dikelompokkan ke dalam paket folder modular:

```text
apps/backend/api/app/
├── api/
│ ├── dependencies.py # Centralized DI (get_current_user, get_db, service factories)
│ └── routes/ # Thin Route Handlers (3-5 baris per endpoint)
│ ├── auth.py
│ ├── user.py
│ ├── diaries.py
│ ├── recommendations.py
│ ├── conversations.py
│ ├── call.py
│ ├── dass.py
│ ├── analytics.py
│ └── health.py
├── schemas/ # Strict Pydantic Contracts per Modul
│ └── {module}/
│ ├── __init__.py # Barrel export seluruh model request & response
│ ├── requests.py # Request body & query parameters
│ └── responses.py # Response models (DTO)
├── services/ # Domain Logic & Database Orchestration per Modul
│ └── {module}/
│ ├── __init__.py # Barrel export service classes
│ ├── {name}_service.py # Implementasi domain service
│ └── ... # Sub-komponen pendukung jika modul berat (heavyweight)
└── models/ # SQLAlchemy Entities (Pure data models & relationships)
```

### Aturan Paket & Barrel Export (`__init__.py`):
1. Setiap subfolder di `app/schemas/{module}/` **wajib** memiliki `__init__.py` yang me-re-export semua class request dan response publik.
2. Setiap subfolder di `app/services/{module}/` **wajib** memiliki `__init__.py` yang me-re-export class service publik.
3. Import di level router harus bersih dan ringkas:
```python
from app.schemas.auth import LoginRequest, TokenResponse
from app.services.auth import AuthService
```

---

## 2. Invariant Thin Router (Maksimal 3–5 Baris per Endpoint)

Router FastAPI (`app/api/routes/*.py`) bertindak murni sebagai **HTTP Transport Controller**.

### ❌ Dilarang Keras di Router Handler:
1. **Dilarang Inline SQL**: Tidak boleh ada query SQLAlchemy (`select()`, `db.execute()`, `db.commit()`, `db.add()`) di dalam router. Seluruh interaksi database wajib di dalam class service.
2. **Dilarang Inline Business Logic / Calculations**: Kalkulasi persentase emosi, DASS scoring, pemrosesan teks, dan validasi krisis dilarang ditulis di router.
3. **Dilarang Raw Dictionary Returns**: Dilarang mengembalikan `dict[str, Any]` tanpa `response_model`. Seluruh endpoint HTTP REST wajib mendeklarasikan `response_model=...` menggunakan Pydantic schema dari `app/schemas/{module}/` (Kecuali streaming SSE yang mengembalikan `StreamingResponse` dan endpoint `@router.websocket`).
4. **Dilarang Menduplikasi `_get_current_user`**: Dilarang membuat fungsi privat `_get_current_user` di dalam file router. Seluruh autentikasi wajib mengimpor `get_current_user` dari `app.api.dependencies`.
5. **Dilarang Instansiasi Manual**: Dilarang memanggil `AsyncSessionLocal()`, `LLMFactory.get_provider()`, atau class service secara manual di dalam router. Gunakan FastAPI `Depends()`.

### ✅ Contoh Standar Thin Route (3–5 Baris):

```python
@router.post("/login", response_model=TokenResponse)
async def login(
payload: LoginRequest,
service: AuthService = Depends(get_auth_service),
) -> TokenResponse:
"""Otentikasi pengguna dan terbitkan akses token."""
return await service.login(payload)

@router.post("", response_model=DiaryEntryResponse, status_code=status.HTTP_201_CREATED)
async def create_diary(
payload: CreateDiaryRequest,
user: User = Depends(get_current_user),
service: DiaryService = Depends(get_diary_service),
) -> DiaryEntryResponse:
"""Simpan refleksi harian pengguna."""
return await service.create_entry(user_id=user.id, payload=payload)
```

### ✅ Contoh Standar Thin WebSocket Route:

```python
@router.websocket("/ws/{session_id}")
async def websocket_call_endpoint(
websocket: WebSocket,
session_id: str,
token: str | None = None,
voice_mode: str | None = None,
) -> None:
"""Delegasikan seluruh handshake, receive loop, turn handling, dan cleanup ke CallSessionManager."""
await call_session_manager.handle_connection(
websocket=websocket,
session_id=session_id,
token=token,
voice_mode=voice_mode,
)
```

---

## 3. Centralized Dependency Injection (`app/api/dependencies.py`)

Seluruh dependency provider dipusatkan di `app/api/dependencies.py`:

```python
# 1. Database & Security Providers
async def get_db_session() -> AsyncGenerator[AsyncSession, None]: ...
async def get_current_user(...) -> User: ...

# 2. Service Factory Providers
async def get_auth_service(db: AsyncSession = Depends(get_db_session)) -> AuthService:
return AuthService(db)

async def get_user_service(db: AsyncSession = Depends(get_db_session)) -> UserService:
return UserService(db)

async def get_diary_service(db: AsyncSession = Depends(get_db_session)) -> DiaryService:
return DiaryService(db)
```

---

## 4. Pemisahan Modul Berat (*Heavyweight Modules*)

Untuk domain yang memiliki kompleksitas tinggi dan multi-komponen, wajib dipecah menjadi sub-service kolaborator di dalam folder modulnya:

### A. Modul Panggilan Suara & Real-time (`app/services/call/`)
- `session_manager.py`: Mengelola lifecycle WebSocket (`handle_connection`), state call (`idle`, `speaking`, `interrupted`), dan barge-in.
- `persistence.py`: Menangani penyimpanan sesi percakapan, transkrip turn, dan message duration ke database.
- `stream_buffer.py`: Mengelola buffer byte raw mic audio incoming.
- `turn_aggregator.py`: Mengagregasi turn pengguna dan deteksi completion.
- `turn_detector.py`: Evaluasi acoustic energy (RMS) dan sentence completion.

### B. Modul Deteksi Emosi (`app/services/emotion/`)
- `ml_detector.py`: Inferensi machine learning klasifikasi emosi suara/teks.
- `analyzer.py`: Heuristik fallback dan mapper bobot 7-emosi ke UI.

### C. Modul Percakapan & Diary (`app/services/conversation/` & `app/services/diary/`)
- Pisahkan operasi streaming SSE (misal ringkasan LLM token-by-token) ke dalam `summary_stream_service.py`.
- Pisahkan sintesis AI harian ke dalam `diary_generator.py` dan CRUD database ke dalam `diary_service.py`.

---

## 5. Kontrak Data Pydantic (Request & Response)

1. Semua data yang keluar dari API wajib melalui model Pydantic di `app/schemas/{module}/responses.py`.
2. Model Pydantic wajib mengaktifkan `from_attributes = True` jika membaca langsung dari model SQLAlchemy ORM:
```python
class ConfigDict:
from_attributes = True
```
3. Naming convention:
- Request models berakhiran `Request` (contoh: `CreateDiaryRequest`, `RegisterRequest`).
- Response models berakhiran `Response` atau `Item` (contoh: `DiaryEntryResponse`, `TokenResponse`, `MessageItem`).
- Query filter models berakhiran `Filter` atau `Params` (contoh: `ConversationQueryParams`).

---

## 6. Protokol Verifikasi & Anti-Regression

Sebelum menyatakan pekerjaan refaktor atau pembuatan API baru selesai:
1. Jalankan `make test-backend` untuk memastikan semua endpoint lolos uji integritas.
2. Pastikan tidak ada `dict[str, Any]` yang tersisa sebagai tipe return di fungsi router.
3. Jalankan `make lint` dan `make format` untuk menjamin kerapian kode sesuai standar Ruff.
26 changes: 21 additions & 5 deletions .agents/rules/cohesion-and-modularity.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,31 @@ Panduan ini mengatur standar modularitas kode pada monorepo Eva AI menggunakan p

1. **Pemisahan I/O & Realtime dari Persistensi**:
Service yang menangani koneksi real-time (WebSockets, STT/TTS streaming) tidak boleh mencampur transaksi SQL langsung di dalam perulangan event. Delegasikan operasi database ke *Persistence Collaborator*.
2. **Peran Router yang Ramping**:
Router FastAPI (`app/api/routes/`) hanya bertugas memvalidasi schema HTTP request, memanggil domain service, dan mengembalikan DTO. Dilarang menaruh query SQL mentah kompleks di dalam router handler.
3. **Cohesive Domain Services**:
Bila sebuah service mulai mengelola lebih dari 3 entitas database atau mencampur komputasi teks dengan operasi I/O, pecah menjadi service kolaborator yang terfokus.
2. **Peran Router yang Ramping (Thin Controllers)**:
Router FastAPI (`app/api/routes/`) wajib ramping (3–5 baris per handler), hanya bertugas memvalidasi schema HTTP request, memanggil domain service via `Depends()`, dan mengembalikan Pydantic `response_model`. Dilarang menaruh query SQL mentah kompleks atau kalkulasi bisnis di dalam router handler.
3. **Cohesive Domain Services & Modular Packaging**:
Bila sebuah domain memiliki beberapa sub-komponen berat (seperti panggilan suara, deteksi emosi, orkestrasi AI), kumpulkan ke dalam direktori paket `app/services/{module}/nama_service.py` dan `app/schemas/{module}/` dengan barrel export `__init__.py`, alih-alih menumpuk file flat di root folder `services/`.
Lihat panduan lengkap di [.agents/rules/backend-clean-architecture.md](file:///home/mashupsoat/Project/eva-ecosystem/.agents/rules/backend-clean-architecture.md).

---

## 4. Checklist Saat Merancang atau Merefaktor Komponen
## 4. Prinsip Component Reuse & Single Source of Truth

Sebelum menulis elemen UI baru atau menduplikasi styling secara *inline* di dalam sebuah screen:
1. **Wajib Memeriksa Komponen Reusable yang Sudah Ada**:
- Periksa direktori komponen global `apps/eva_mobile/lib/widgets/` (misalnya `AppBackButton`, `GlassCard`, `AppSnackBar`, `CustomButton`, `CustomTextField`, `SkeletonShimmer`, `StaggeredEntrance`).
- Periksa komponen tingkat fitur di `apps/eva_mobile/lib/features/<feature>/presentation/widgets/`.
2. **Dilarang Menulis Ulang Komponen Standar Secara Inline**:
- Jangan membuat tombol *back* manual (`IconButton(icon: Icon(Icons.arrow_back...))` atau `Container(...)` bulat) secara terpisah di setiap screen. Selalu gunakan `AppBackButton`.
- Jangan membuat dialog / card / snack bar secara *ad-hoc* jika sudah tersedia komponen terstandarisasi.
3. **Ekstraksi Jika Dipakai di Lebih Dari 1 Tempat**:
- Jika sebuah komponen UI memiliki pola visual atau fungsi umum yang dibutuhkan oleh $\ge 2$ layar, ekstraksi menjadi reusable widget di `lib/widgets/` alih-alih menduplikasinya.

---

## 5. Checklist Saat Merancang atau Merefaktor Komponen

- [ ] Apakah sudah memeriksa `apps/eva_mobile/lib/widgets/` untuk memastikan belum ada komponen yang melayani kebutuhan serupa (misal `AppBackButton`, `GlassCard`)? $\rightarrow$ *Wajib gunakan komponen yang sudah ada jika tersedia*
- [ ] Apakah sub-widget ini memiliki `Timer` atau `AnimationController` sendiri yang bisa berjalan independen dari layarnya? $\rightarrow$ *Ekstraksi ke widgets/*
- [ ] Apakah ada class `CustomPainter` yang ditulis di bawah screen? $\rightarrow$ *Ekstraksi ke widgets/*
- [ ] Apakah modal bottom sheet ini cukup panjang dan memiliki alur interaksinya sendiri? $\rightarrow$ *Ekstraksi ke widgets/*
Expand Down
1 change: 1 addition & 0 deletions .agents/rules/github-coordination.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Backlog ───> Ready ───> In Progress ───> In Review ─
```

- **Human-Owned Tasks**: Every task has a single human developer owner. AI agents code only on the task selected by the developer and must never auto-claim or auto-assign tasks.
- **Developer Review Gate for Issue Lifecycle**: Adding, editing, closing, or deleting GitHub issues requires prior review and explicit confirmation by the human developer. The AI agent must present the draft/dry-run and await approval before modifying GitHub state.
- **Evidence-Based Progress Updates**: Task transitions require concrete evidence:
- `Ready ➔ In Progress`: Active task branch matching `{type}/{issue}-{slug}`.
- `In Progress ➔ Blocked`: Explicit blocker reason (minimum 3 characters).
Expand Down
Loading
Loading