feat(tasks): markdown export projection
A disposable Markdown view of the board, grouped by status with checkboxes and claimants — rendered from the event log, never a source of truth. TaskMarkdown.render (pure) backs GET /tasks/export[?project=]. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -11,14 +11,17 @@ import com.correx.core.events.types.TaskNoteAuthor
|
||||
import com.correx.core.events.types.TaskTargetKind
|
||||
import com.correx.core.tasks.Task
|
||||
import com.correx.core.tasks.TaskContextAssembler
|
||||
import com.correx.core.tasks.TaskMarkdown
|
||||
import com.correx.core.tasks.TaskSearch
|
||||
import com.correx.core.tasks.TaskService
|
||||
import com.correx.core.tasks.TaskStatus
|
||||
import com.correx.core.tasks.TaskTargetKinds
|
||||
import com.correx.core.utils.TypeId
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import io.ktor.server.request.receive
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.response.respondText
|
||||
import io.ktor.server.routing.Route
|
||||
import io.ktor.server.routing.RoutingContext
|
||||
import io.ktor.server.routing.delete
|
||||
@@ -150,6 +153,12 @@ private fun Route.taskCollectionRoutes(service: TaskService) {
|
||||
)
|
||||
call.respond(HttpStatusCode.Created, task.toResponse())
|
||||
}
|
||||
// Disposable Markdown projection of the board (whole board, or one project with ?project=).
|
||||
get("/export") {
|
||||
val project = call.request.queryParameters["project"]
|
||||
val tasks = if (project != null) service.list(ProjectId(project)) else service.listAll()
|
||||
call.respondText(TaskMarkdown.render(tasks), ContentType.Text.Plain)
|
||||
}
|
||||
}
|
||||
|
||||
// Git-driven status: a commit mention advances a task to IN_PROGRESS, a closing keyword
|
||||
|
||||
@@ -227,6 +227,21 @@ class TaskRoutesTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GET tasks export renders the board as markdown`(@TempDir tempDir: Path) {
|
||||
testApplication {
|
||||
application { configureServer(buildModule(tempDir)) }
|
||||
val client = createClient {}
|
||||
client.createTask() // demo-1
|
||||
|
||||
val res = client.get("/tasks/export")
|
||||
assertEquals(HttpStatusCode.OK, res.status)
|
||||
val md = res.bodyAsText()
|
||||
assertTrue(md.startsWith("# Tasks"))
|
||||
assertTrue(md.contains("**demo-1**"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `context bundle is served for a known task`(@TempDir tempDir: Path) {
|
||||
testApplication {
|
||||
|
||||
Reference in New Issue
Block a user