Dependencies
make serve # Build & run on http://localhost:4005| Shared Code | Purpose |
|---|---|
| types.mbt | Board, Column, Card, MoveCardRequest structs with JSON derive |
| routes.mbt | API path constants and builders (api_board, api_card(id), etc.) |
| validation.mbt | Input validation (validate_card_title, validate_color, limits) |
| logic.mbt | Positioning algorithms (compute_insert_position, compute_move_position, renumber_positions, cards_in_column, sort_by_position, color_to_css) |
| Method | Path | Description |
|---|---|---|
| GET | /api/board | Full board (columns + cards) |
| POST | /api/columns | Create column {"title": "..."} |
| GET | /api/columns/:id | Get a single column |
| POST | /api/columns/:id | Rename column {"title": "..."} |
| POST | /api/columns/:id/move | Move column {"new_position": N} |
| DELETE | /api/columns/:id | Delete column and its cards |
| POST | /api/cards | Create card {"column_id": N, "title": "...", "description": "...", "color": "..."} |
| POST | /api/cards/:id | Update card {"title": "...", "description": "...", "color": "..."} |
| POST | /api/cards/:id/move | Move card {"target_column_id": N, "new_position": N} |
| DELETE | /api/cards/:id | Delete card |
kanban/
├── moon.mod.json # Module: bobzhang/kanban
├── Makefile # Build & serve (port 4005)
├── shared/ # Isomorphic package (js + native)
│ ├── types.mbt # Board, Column, Card, MoveCardRequest
│ ├── routes.mbt # API route constants
│ ├── validation.mbt # Input validation & limits
│ ├── logic.mbt # Positioning algorithms & helpers
│ ├── logic_test.mbt # Tests for positioning logic
│ ├── validation_test.mbt # Tests for validation
│ ├── routes_test.mbt # Tests for route builders
│ ├── types_test.mbt # JSON round-trip tests
│ └── README.mbt.md # Testable documentation
├── backend/ # Native target — Mocket + SQLite3
│ └── main.mbt
├── frontend/ # JS target — Rabbita MVU
│ └── main.mbt
└── public/
└── frontend.js # Compiled frontend (generated)moon test shared/ # Run shared package tests (50+ tests)
moon test shared/ -v # Verbose with test namesgraph LR
subgraph Browser
FE["Frontend (JS)<br/>Rabbita MVU<br/>frontend/main.mbt<br/>frontend/app/*.mbt"]
end
subgraph Server
BE["Backend (Native)<br/>Mocket HTTP<br/>backend/main.mbt<br/>backend/routes.mbt<br/>backend/db.mbt"]
DB[(SQLite<br/>kanban.db)]
end
subgraph "Shared Package"
SH["shared/<br/>types.mbt — domain structs<br/>routes.mbt — API paths<br/>validation.mbt — input rules<br/>logic.mbt — positioning"]
end
FE <-->|"REST API<br/>(JSON)"| BE
BE <-->|"SQL queries"| DB
SH -.->|"compiled to JS"| FE
SH -.->|"compiled to native"| BEerDiagram
Board {
Column[] columns
Card[] cards
}
Column {
Int id PK
String title
Int position
}
Card {
Int id PK
Int column_id FK
String title
String description
String color
Int position
}
MoveCardRequest {
Int card_id
Int target_column_id
Int new_position
}
Column ||--o{ Card : "has many"
Board ||--|{ Column : "aggregates"
Board ||--|{ Card : "aggregates"graph TD
subgraph "Initial State"
A["Card A<br/>position: 1000"]
B["Card B<br/>position: 2000"]
C["Card C<br/>position: 3000"]
end
subgraph "Append (next_position)"
D["Card D<br/>position: 3000 + 1000 = 4000"]
end
subgraph "Insert Between A and B (compute_insert_position)"
E["New Card<br/>position: (1000 + 2000) / 2 = 1500"]
end
subgraph "Gap Exhausted → Renumber (renumber_positions)"
F["Card A → 1000"]
G["Card B → 2000"]
H["Card C → 3000"]
end
A --> D
A --> E
B --> E
F --- G --- Hgraph LR
View["View<br/>view.mbt<br/>view_column.mbt<br/>view_card.mbt<br/>view_form.mbt"]
Model["Model<br/>types.mbt<br/>(Board, UI state)"]
Update["Update<br/>update.mbt<br/>(Msg → Model + Cmd)"]
Cmd["HTTP Commands<br/>GET /api/board<br/>POST /api/cards/:id/move<br/>POST /api/columns/:id/move"]
API["Backend REST API"]
View -->|"user clicks<br/>move / edit / create"| Update
Update -->|"new Model"| Model
Model -->|"re-render"| View
Update -->|"Cmd (HTTP request)"| Cmd
Cmd -->|"fetch / post / delete"| API
API -->|"JSON response"| UpdateInstall
Download zipDependencies