Skip to content

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

Merged
ilmoniemi merged 3 commits into
mainfrom
feature/2
May 11, 2026
Merged

feat(data): add Conversation, Session, Message data classes (#2)#28
ilmoniemi merged 3 commits into
mainfrom
feature/2

Conversation

@ilmoniemi
Copy link
Copy Markdown
Contributor

What

Creates the de.pyryco.mobile.data.model package with three foundational data classes and one enum:

  • Conversation — id, optional name, cwd, current session, session history, isPromoted flag, lastUsedAt timestamp
  • Session — id, conversationId, claudeSessionUuid, started/ended timestamps
  • Message — id, sessionId, role, content, timestamp, isStreaming
  • Role { User, Assistant, Tool } co-located in Message.kt

Wires kotlinx-datetime 0.6.2 via the version catalog (libs.kotlinx.datetime) so timestamps stay portable for a possible Compose Multiplatform walk-back — java.time.Instant would have locked the data layer to JVM/Android.

No ConversationRepository yet (next ticket), no persistence, no serialization annotations.

Issue

Closes #2

Testing

  • New unit-test files under app/src/test/java/de/pyryco/mobile/data/model/ — one per data class.
  • Each data class test asserts equals, hashCode, copy(...) overrides one field while preserving the rest, and copy() returns a new instance.
  • MessageTest additionally asserts Role.entries is exactly [User, Assistant, Tool] in declaration order.
  • ./gradlew test — passes.
  • ./gradlew lint — passes.
  • ./gradlew assembleDebug — passes.
  • ./gradlew connectedAndroidTest — not run; no device connected and this ticket has no instrumented tests.

Architecture compliance

  • File layout follows the spec: one class per file, Role co-located in Message.kt (tightly bound, three-line enum, no independent consumers).
  • Field names, types, and nullability copied verbatim from AC1.
  • kotlinx.datetime.Instant used throughout the data layer (CLAUDE.md "Don't" — keep data/ portable). No java.time.Instant import anywhere.
  • Dependency declared in gradle/libs.versions.toml and pulled into app/build.gradle.kts via libs.kotlinx.datetime. No raw coordinate in the build file.
  • No annotations on the data classes (Out of Scope: wire-protocol serialization deferred).
  • No require(...) / init { } blocks — scope is the schema only.

🤖 Generated with Claude Code

ilmoniemi and others added 2 commits May 11, 2026 12:10
Introduce the de.pyryco.mobile.data.model package with Conversation,
Session, Message and the Role enum, plus paired equality / hashCode /
copy unit tests. Wires kotlinx-datetime 0.6.2 through the version
catalog so the data layer stays portable for a possible Compose
Multiplatform walk-back.

Closes #2

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@ilmoniemi
Copy link
Copy Markdown
Contributor Author

Code Review: #2

Decision: PASS

Findings

No MUST FIX, SHOULD FIX, or NIT findings.

Verified against the spec at docs/specs/architecture/2-conversation-session-message-data-classes.md:

  • Conversation, Session, Message, Role declared in de.pyryco.mobile.data.model with field names/types/nullability matching the AC1 spec block verbatim
  • kotlinx.datetime.Instant used (CLAUDE.md "Don't" — data layer must stay portable for Compose Multiplatform walk-back); no java.time.Instant leak
  • No @Serializable / @JsonClass annotations (Out of Scope respected)
  • No init { } / require(...) blocks (no AC mandated validation; correctly avoided scope creep)
  • kotlinx-datetime 0.6.2 wired through gradle/libs.versions.toml only — no raw coordinate in app/build.gradle.kts, correct catalog accessor libs.kotlinx.datetime
  • File layout matches spec: Role co-located in Message.kt, otherwise one-class-per-file
  • Tests use JUnit 4 idiom matching ExampleUnitTest.kt; three test methods per data class plus role_has_exactly_user_assistant_tool in MessageTest.kt
  • Role.entries.toList() used (spec explicitly permits as the Kotlin 1.9+ replacement for values())
  • Instant.fromEpochSeconds(0) used for deterministic fixtures; no Clock.System.now()

Local verification: ./gradlew test and ./gradlew assembleDebug both BUILD SUCCESSFUL on feature/2.

Summary

Textbook spec-following implementation of foundational data types. No consumers yet, so blast-radius is nil. Ready to merge; the next ticket (ConversationRepository interface + FakeConversationRepository) can build on this schema unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@ilmoniemi ilmoniemi merged commit dd85d1f into main May 11, 2026
@ilmoniemi ilmoniemi deleted the feature/2 branch May 11, 2026 09:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant