Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@ jobs:
build-and-test:
name: Build & test
runs-on: ubuntu-latest
services:
postgres:
image: postgres:17-alpine
env:
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
WEND_TEST_PG: "Host=localhost;Port=5432;Database=postgres;Username=postgres;Password=postgres"
steps:
- uses: actions/checkout@v7

Expand Down
19 changes: 15 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ A free, open-source, accessible, dark-mode-first kanban board — a calm alterna

**Slice 1 — local single-user board (complete).**

Boards, lists, and cards work end to end — create, rename, delete, and reorder lists inside a board, add cards to a list, move a card within its list or to another list, label them, delete a card with a one-click undo, open a card into a focused task view with an Edit mode, keep a per-card checklist (add, rename, reorder, check off into a collapsible Done strip, delete with undo) with progress shown on the board's card chips, and tune it all in a small settings screen — saved to SQLite, accessible and dark-mode-first.
Boards, lists, and cards work end to end — create, rename, delete, and reorder lists inside a board, add cards to a list, move a card within its list or to another list, label them, delete a card with a one-click undo, open a card into a focused task view with an Edit mode, keep a per-card checklist (add, rename, reorder, check off into a collapsible Done strip, delete with undo) with progress shown on the board's card chips, and tune it all in a small settings screen — saved to PostgreSQL, accessible and dark-mode-first.

- **Done:** the board, list, card, label, and checklist backend (JSON APIs behind `IBoardRepository`, `IListRepository`, `ICardRepository`, `ILabelRepository`, and `IChecklistItemRepository` seams, EF Core + SQLite, 147 NUnit tests, localhost-only) and the vanilla-JS MVC frontend (board-view navigation, accessible list reordering, card chips with a focused task view, accessible card moving with up/down buttons and a move-to-list dropdown, an inline label picker with soft-tint chips, a per-card checklist with a Done strip and chip progress bars, an undo-first delete for cards and checklist items with a transient "Deleted · Undo" toast, a task-view Edit mode, a localStorage settings screen gating the card Done checkboxes and the Delete card button, screen-reader announcements, keyboard focus management, per-list Done strips, and a mobile single-list switcher).
- **Done:** the board, list, card, label, and checklist backend (JSON APIs behind `IBoardRepository`, `IListRepository`, `ICardRepository`, `ILabelRepository`, and `IChecklistItemRepository` seams, EF Core + PostgreSQL with migrations, 147 NUnit tests, localhost-only) and the vanilla-JS MVC frontend (board-view navigation, accessible list reordering, card chips with a focused task view, accessible card moving with up/down buttons and a move-to-list dropdown, an inline label picker with soft-tint chips, a per-card checklist with a Done strip and chip progress bars, an undo-first delete for cards and checklist items with a transient "Deleted · Undo" toast, a task-view Edit mode, a localStorage settings screen gating the card Done checkboxes and the Delete card button, screen-reader announcements, keyboard focus management, per-list Done strips, and a mobile single-list switcher).
- **Next:** Slice 2 — sharing and multi-user accounts.

Design specs: [`docs/2026-06-15-wend-slice1-design.md`](docs/2026-06-15-wend-slice1-design.md), [`docs/2026-06-19-wend-lists-design.md`](docs/2026-06-19-wend-lists-design.md), [`docs/2026-06-22-wend-cards-design.md`](docs/2026-06-22-wend-cards-design.md), [`docs/2026-06-23-wend-labels-design.md`](docs/2026-06-23-wend-labels-design.md), [`docs/2026-06-24-wend-card-moving-design.md`](docs/2026-06-24-wend-card-moving-design.md), [`docs/2026-06-25-wend-done-design.md`](docs/2026-06-25-wend-done-design.md), [`docs/2026-07-07-wend-delete-undo-design.md`](docs/2026-07-07-wend-delete-undo-design.md), [`docs/2026-07-07-wend-checklist-design.md`](docs/2026-07-07-wend-checklist-design.md), [`docs/2026-07-08-wend-mobile-a11y-polish-design.md`](docs/2026-07-08-wend-mobile-a11y-polish-design.md)
Expand All @@ -24,7 +24,7 @@ Build plans: [`docs/plans/2026-06-16-slice1-foundation-boards.md`](docs/plans/20
## Stack

- ASP.NET Core (`net10.0`) — minimal API, localhost only
- EF Core → SQLite for storage, behind an `IBoardRepository` seam
- EF Core → PostgreSQL for storage (EF migrations), behind an `IBoardRepository` seam
- Vanilla-JavaScript MVC frontend, served from `wwwroot`
- NUnit tests

Expand All @@ -38,14 +38,25 @@ Build plans: [`docs/plans/2026-06-16-slice1-foundation-boards.md`](docs/plans/20

## Run it

Wend stores data in **PostgreSQL**. Install a local server once — a normal Windows service, no Docker:

```
winget install --exact --id PostgreSQL.PostgreSQL.17
```

Set the `postgres` password to `postgres` and keep port `5432`. Store the dev connection string once, then run:

```
dotnet user-secrets set "ConnectionStrings:WendDb" "Host=localhost;Port=5432;Database=wend;Username=postgres;Password=postgres" --project Wend.Api
dotnet run --project Wend.Api
```

Then open http://127.0.0.1:5174 to create boards, open one to manage its lists (create, rename, delete, reorder), add cards and move them within or between lists — open a card for its task view to edit the title, notes, due date, labels, and a per-card checklist. The API lives under `/api/boards`, `/api/lists`, `/api/cards`, `/api/labels`, and `/api/checklist-items`. On first run the SQLite database is created at `%LOCALAPPDATA%\Wend\data.db`.
Then open http://127.0.0.1:5174 to create boards, open one to manage its lists (create, rename, delete, reorder), add cards and move them within or between lists — open a card for its task view to edit the title, notes, due date, labels, and a per-card checklist. The API lives under `/api/boards`, `/api/lists`, `/api/cards`, `/api/labels`, and `/api/checklist-items`. The schema is created and kept current by EF Core migrations on startup.

## Tests

The API integration tests need the local PostgreSQL server running (each creates a throwaway database on it); the repository unit tests run on in-memory SQLite.

```
dotnet test
```
Expand Down
15 changes: 8 additions & 7 deletions Wend.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@

var builder = WebApplication.CreateBuilder(args);

// Config seam — DB path and port are overridable by tests and manual runs.
var dbPath = builder.Configuration["Wend:DbPath"] ?? WendPaths.DefaultDbPath();
// Config seam — connection string from user-secrets (dev) or environment (prod).
var connectionString = builder.Configuration.GetConnectionString("WendDb")
?? throw new InvalidOperationException(
"ConnectionStrings:WendDb is not configured. Set it via user-secrets (dev) or environment (prod).");
var port = int.TryParse(builder.Configuration["Wend:Port"], out var p) ? p : 5174;

builder.Services.AddDbContext<WendDbContext>(options => options.UseSqlite($"Data Source={dbPath}"));
builder.Services.AddDbContext<WendDbContext>(options => options.UseNpgsql(connectionString));
builder.Services.AddScoped<IBoardRepository, EfBoardRepository>();builder.Services.AddScoped<IListRepository, EfListRepository>();
builder.Services.AddScoped<ICardRepository, EfCardRepository>();
builder.Services.AddScoped<ILabelRepository, EfLabelRepository>();
Expand All @@ -24,11 +26,10 @@

var app = builder.Build();

// Create the SQLite schema on first run. NOTE: EnsureCreated does NOT migrate an existing
// database when later plans add tables — see "Schema & migrations" in the notes. Slice 1
// adopts EF Core migrations at the Slice 1 -> 2 boundary.
// Apply pending EF Core migrations on startup (dev-simple; the deployment plan switches this to
// migration bundles / scripts, which Microsoft recommends for production).
using (var scope = app.Services.CreateScope())
scope.ServiceProvider.GetRequiredService<WendDbContext>().Database.EnsureCreated();
scope.ServiceProvider.GetRequiredService<WendDbContext>().Database.Migrate();

// Unhandled failures → bodyless 500 (no developer exception page over the wire).
app.UseExceptionHandler(b => b.Run(ctx => { ctx.Response.StatusCode = 500; return Task.CompletedTask; }));
Expand Down
10 changes: 9 additions & 1 deletion Wend.Api/Wend.Api.csproj
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UserSecretsId>ce721b36-3c27-4a78-a047-720d9a894962</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Wend.Core\Wend.Core.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.9">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

</Project>
255 changes: 255 additions & 0 deletions Wend.Core/Migrations/20260711170130_InitialCreate.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading