feat(projects): the repository reads a project and what is in it

Phase 6 of docs/project-feature.md. Six methods on `MantraRepository`, with
`DatabaseMantraRepository` behind them and `NO_OP` returning empty for previews.

The two contents queries return the versions rather than the join rows. No
screen wants a join row, and the DAO resolves it in one indexed query instead of
leaving an N+1 in a view model. Both inverses are here too -- which projects a
version is part of -- because an artifact's own screen is where "what is this
for" gets asked.

Nothing in `MantraDao`. That path -- `addDialect`, `addArtifactVersion`,
`rumorOf`, `submitToGroup` -- is the old submit flow, reached now only from its
own test, and every entity a member creates is proposed for signing instead. An
`addProject` there would be a second way to create a project that bypasses the
quorum, which is the thing this feature is for.

No query by creator or owner. Both are columns and a screen that wants them has
the row; `getProjectsOwnedBy` would be a query with one caller and an index to
go with it, and a room's project list is short. Add it when a screen asks.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kgothatso Ngako
2026-10-02 19:30:18 +02:00
parent 5fac2fc7b7
commit 9bd4216867
2 changed files with 76 additions and 0 deletions

View File

@@ -9,6 +9,7 @@ import press.mantra.compose.database.model.MantraArtifactVersion
import press.mantra.compose.database.model.MantraChapter
import press.mantra.compose.database.model.MantraChunk
import press.mantra.compose.database.model.MantraDialect
import press.mantra.compose.database.model.MantraProject
import press.mantra.compose.database.model.MantraTranslationArtifactVersion
import press.mantra.compose.database.model.MantraTranslationChapter
import press.mantra.compose.database.model.MantraTranslationChunk
@@ -41,6 +42,35 @@ class DatabaseMantraRepository(
override suspend fun getChaptersForArtifactVersion(artifactVersionId: String): List<MantraChapter> =
database.mantraChapterDao().getChaptersByArtifactVersionId(artifactVersionId)
override suspend fun getProjects(chatRoomId: String): List<MantraProject> =
database.mantraProjectDao().getProjectsByChatRoomId(chatRoomId)
override suspend fun getProject(id: String): MantraProject? =
database.mantraProjectDao().getProjectById(id)
override suspend fun getProjectArtifactVersions(
projectId: String
): List<MantraArtifactVersion> =
database.mantraProjectArtifactVersionDao().getArtifactVersionsByProjectId(projectId)
override suspend fun getProjectTranslationArtifactVersions(
projectId: String
): List<MantraTranslationArtifactVersion> =
database.mantraProjectTranslationArtifactVersionDao()
.getTranslationArtifactVersionsByProjectId(projectId)
override suspend fun getProjectsForArtifactVersion(
artifactVersionId: String
): List<MantraProject> =
database.mantraProjectArtifactVersionDao()
.getProjectsByArtifactVersionId(artifactVersionId)
override suspend fun getProjectsForTranslationArtifactVersion(
translationArtifactVersionId: String
): List<MantraProject> =
database.mantraProjectTranslationArtifactVersionDao()
.getProjectsByTranslationArtifactVersionId(translationArtifactVersionId)
override suspend fun getChapter(id: String): MantraChapter? =
database.mantraChapterDao().getChapterById(id)

View File

@@ -6,6 +6,7 @@ import press.mantra.compose.database.model.MantraArtifactVersion
import press.mantra.compose.database.model.MantraChapter
import press.mantra.compose.database.model.MantraChunk
import press.mantra.compose.database.model.MantraDialect
import press.mantra.compose.database.model.MantraProject
import press.mantra.compose.database.model.MantraTranslationArtifactVersion
import press.mantra.compose.database.model.MantraTranslationChapter
import press.mantra.compose.database.model.MantraTranslationChunk
@@ -56,6 +57,31 @@ interface MantraRepository {
suspend fun getDialect(id: String): MantraDialect?
suspend fun getProjects(chatRoomId: String): List<MantraProject>
suspend fun getProject(id: String): MantraProject?
/**
* The source versions a project is translating from.
*
* The versions, not the join rows: no screen wants a join row, and resolving
* it here is one indexed query instead of an N+1 in a view model.
*/
suspend fun getProjectArtifactVersions(projectId: String): List<MantraArtifactVersion>
/** The translations a project is producing. */
suspend fun getProjectTranslationArtifactVersions(
projectId: String
): List<MantraTranslationArtifactVersion>
/** The inverse: which projects a source version is part of. */
suspend fun getProjectsForArtifactVersion(artifactVersionId: String): List<MantraProject>
/** The inverse again, for a translation. */
suspend fun getProjectsForTranslationArtifactVersion(
translationArtifactVersionId: String
): List<MantraProject>
suspend fun addArtifactVersion(
localChatRoom: LocalChatRoom,
artifactId: HexKey,
@@ -102,6 +128,26 @@ interface MantraRepository {
override suspend fun getDialect(id: String): MantraDialect? = null
override suspend fun getProjects(chatRoomId: String): List<MantraProject> = emptyList()
override suspend fun getProject(id: String): MantraProject? = null
override suspend fun getProjectArtifactVersions(
projectId: String
): List<MantraArtifactVersion> = emptyList()
override suspend fun getProjectTranslationArtifactVersions(
projectId: String
): List<MantraTranslationArtifactVersion> = emptyList()
override suspend fun getProjectsForArtifactVersion(
artifactVersionId: String
): List<MantraProject> = emptyList()
override suspend fun getProjectsForTranslationArtifactVersion(
translationArtifactVersionId: String
): List<MantraProject> = emptyList()
override suspend fun addArtifactVersion(
localChatRoom: LocalChatRoom,
artifactId: HexKey,