Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
145
planned
1,361
shipped

Motir · Work items

MOTIR-159Done

3.1.3 Board repositories — `boardRepository` / `boardColumnRepository` / `boardColumnStatusRepository`

Estimate: 16m · Depends on: 3.1.1

The data-access leaf layer for boards — three repositories, each a set of single-Prisma-op methods, write methods requiring tx: Prisma.TransactionClient (CLAUDE.md). Named by primary entity, not call site.

boardRepositoryfindByProject(projectId, workspaceId, tx?)Board[] (ordered by createdAt; v1 returns the single default board), findDefaultForProject(projectId, workspaceId, tx?)Board | null (the project's board for the v1 single-board case), findById(boardId, workspaceId, tx?)Board | null, create(data, tx)Board.

boardColumnRepositoryfindByBoard(boardId, workspaceId, tx?)BoardColumn[] (ordered by position asc), findById(columnId, workspaceId, tx?)BoardColumn | null, create(data, tx)BoardColumn, update(columnId, data, tx)BoardColumn (for the WIP/rename writes a later story uses). Batched findByBoards(boardIds[], workspaceId, tx?) for no-N+1 reads, mirroring workflowsRepository.findStatusesByProjects.

boardColumnStatusRepositoryfindByBoard(boardId, workspaceId, tx?)BoardColumnStatus[] (the full mapping for the projection to bucket statuses → columns), create(data, tx)BoardColumnStatus, deleteByColumn(columnId, tx) and deleteByStatus(boardId, statusId, tx) (re-map writes a later admin story uses). findByColumn(columnId, workspaceId, tx?) for a single column’s statuses.

Rules: each method is ONE Prisma call (no composition — that’s the service); reads used only by read paths may use the db singleton; writes require tx; every method takes workspaceId and scopes by it at the app layer (finding #26) on top of RLS. No DTO mapping here (services map). No business logic.

Acceptance criteria

  • Three repositories exported as export const <name>Repository = { ... }, each method a single Prisma op.
  • All write methods (create / update / delete*) take a required tx: Prisma.TransactionClient; pure reads may use db.
  • Every method takes + filters by workspaceId (app-layer gate atop RLS, finding #26).
  • Batched findByBoards exists for the projection’s no-N+1 read; no repository method calls another repository.
  • Vitest (real Postgres) covers the reads + a representative write under a transaction, asserting workspace scoping.

Context refs

  • lib/repositories/workflowsRepository.ts — the exact shape (single-op, required-tx writes, batched reads) this mirrors
  • lib/repositories/workItemRepository.ts — read-path / filter conventions
  • motir-core/CLAUDE.md — Repository layer rules (single op, required tx, entity-named, leaves)