Skip to content

feat(data): add Conversation, Session, Message data classes #2

@ilmoniemi

Description

@ilmoniemi

User Story

As a mobile-app engineer, I want the core Conversation / Session / Message data classes defined so that subsequent tickets (repository interface, fake repository, UI state) have a typed schema to build against.

Context

Foundational Phase 1 scaffolding. Mirrors the schema that pyrycode CLI's conversations.json (Phase 3) and Discord-side (Phase 2) will share — same entity shape across all consumers. The data/ package does not yet exist in the repo; this ticket creates it.

Per repo CLAUDE.md (Don't section): the data layer must stay portable (Compose Multiplatform is a walk-back trigger). See Technical Notes.

Spec

// app/src/main/java/de/pyryco/mobile/data/model/

data class Conversation(
    val id: String,
    val name: String?,             // null for discussions; user-set for channels
    val cwd: String,
    val currentSessionId: String,
    val sessionHistory: List<String>,
    val isPromoted: Boolean,       // false = discussion, true = channel
    val lastUsedAt: Instant,
)

data class Session(
    val id: String,
    val conversationId: String,
    val claudeSessionUuid: String,
    val startedAt: Instant,
    val endedAt: Instant?,
)

data class Message(
    val id: String,
    val sessionId: String,
    val role: Role,
    val content: String,
    val timestamp: Instant,
    val isStreaming: Boolean,
)

enum class Role { User, Assistant, Tool }

Acceptance Criteria

  • Conversation, Session, Message, and Role are declared in package de.pyryco.mobile.data.model with the exact field names, types, and nullability shown in the Spec.
  • A unit test for each of the three data class types asserts that two instances with identical fields are equals, that hashCode matches, and that copy() produces a new instance with the requested field overridden and all others preserved.
  • A unit test asserts that Role has exactly the values User, Assistant, Tool (e.g. via Role.values().toList()).
  • ./gradlew assembleDebug passes.
  • ./gradlew test passes.

Technical Notes

  • Use kotlinx.datetime.Instant, not java.time.Instant — CLAUDE.md requires the data layer to remain portable for a potential Compose Multiplatform walk-back. The version catalog (gradle/libs.versions.toml) does not yet declare kotlinx-datetime; the architect should add it.
  • File layout (one-class-per-file vs. co-locating Role in Message.kt) is an architect call — the AC fixes the package and the type shapes, not the file count.

Out of Scope

  • ConversationRepository interface and FakeConversationRepository (next ticket).
  • Persistence (DataStore / Room).
  • Serialization for the Phase 4 wire protocol — these types stay annotation-free for now.

Size Estimate

XS — ~40 lines of production code (4 small declarations in one package), plus paired unit tests. No cross-package coordination; no consumers wired in this ticket.

Metadata

Metadata

Assignees

No one assigned

    Labels

    size:xs<30 lines production code; trivial change

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions