Skip to content

Repository files navigation

TaskFlow

Task management API and Angular SPA: JWT auth, CRUD tasks with domain-driven status rules, Orleans grains and SQL persistence, demo data via SQL migration (008_DemoSeed_Data.sql). The API returns RFC 7807 Problem Details for errors; persistence uses parameterized ADO.NET (Microsoft.Data.SqlClient) without EF or Dapper—see BACKEND_SPEC.md and FRONTEND_SPEC.md for behavioral detail.

GenAI documentation

GENAI.md — Long-form notes on how generative AI was used in this delivery (prompts, validation, and what was accepted or rejected). Part 2 below lists only verified, narrow uses for evaluators.

Angular app (TaskFlow/src/TaskManager.Web)

Single-page client (Angular CLI 21+). Product rules and API alignment: FRONTEND_SPEC.md. Local dev from this folder: npm ci, npm start (or ng serve); tests: ng test (Vitest); production build: ng build.

Project structure

Paths below are under TaskFlow/src/TaskManager.Web/.

  • src/app/app.ts, app.html, app.scss, app.config.ts, app.routes.ts — application shell, root wiring, routes.
  • src/app/auth — identity and session (auth.service.ts, auth.guard.ts, storage keys).
  • src/app/shared/http — JWT and error interceptors.
  • src/app/shared/models — shared DTOs (e.g. auth request/response types).
  • src/app/pages/login, pages/register, pages/tasks — lazy-loaded route containers.
  • src/app/features/tasks — task domain (task.service.ts, task-status.ts, models/, UI under components/).
  • src/environments — API base URL per environment.

This layout is intentionally compact for the challenge scope.

Move map (P-10)

Mechanical refactor (slice P-10, 2026-04-08) aligned the tree with pages / components / shared / auth layering:

FromTo
src/app/core/auth/*src/app/auth/*
src/app/core/http/*src/app/shared/http/*
src/app/core/models/auth.models.tssrc/app/shared/models/auth.models.ts

Task-scoped UI (card, dialogs, status badge) lives under src/app/features/tasks/components/. Routing URLs unchanged (/, /login, /register, /tasks); lazy loadComponent paths still under pages/.

Recommended layout for larger codebases

  • pages/ — route-level containers.
  • components/ — reusable presentational pieces.
  • shared/ — utilities, pipes, generic models.
  • auth/ — identity isolated from feature logic.
  • features/<feature-name>/ — bounded feature code.

Evaluator talking points (frontend)

  • Minimal, feature-first structure; auth/ and shared/http keep pages thin.
  • Lazy-loaded routes; tasks are the main bounded feature.
  • Larger apps benefit from clearer pages / components / shared / auth boundaries and tests colocated with those boundaries.
  • Mechanical-only moves → P-10; reference-driven structure/visual alignment → P-11.
  • P-11 visual reference:.tasks/Front References/TaskFlow-Design-Spec.md and taskflow-mockup.html. The mockup includes a marketing-style hero; this app keeps the task dashboard only (no hero) — intentional.

Technical choices (frontend)

  • Standalone components — No NgModule app shell; lazy loadComponent in app.routes.ts.
  • inject() — DI in components and services without constructor boilerplate (AuthService, TaskService, pages).
  • Signals — Session and loading state (signal / computed, e.g. auth.service.ts, login/register submitting).
  • Functional HTTP interceptorsprovideHttpClient(withInterceptors([jwtInterceptor, errorInterceptor])) in app.config.ts: JWT on protected calls, Problem Details–aware errors, 401 session handling.
  • Timezone headertask.service.ts sends X-Timezone-Offset-Minutes on task create/update (Date.getTimezoneOffset()), aligned with TasksController calendar rules.
  • Angular Material + Vitest — Material (e.g. snackbar) via importProvidersFrom; unit tests via Vitest.

Primary evaluation path: Docker Compose

From the repository root (this folder):

docker compose up --build

Wait until SQL is healthy and the API has started. Then:

ServiceURL
Web (Angular)http://localhost:4200
API (Swagger in Development)http://localhost:5278/swagger
SQL Serverlocalhost:1433sa / TaskFlow@2026! (see docker-compose.yml; dev-only)

The stack runs SQL Server with a healthcheck, then the API (depends_on with condition: service_healthy), then the Web container. API and Web publish ports per the table above.

Demo credentials (SQL migration 008_DemoSeed_Data.sql)

Users are inserted idempotently when the API runs SqlServerDatabaseMigrator (same pipeline as tests). Argon2id hashes in the migration match .tasks/users.json (companion reference).

Login (SPA or Swagger “Authorize”)

EmailPassword
demo@taskflow.localDemo#2026!
reviewer@taskflow.localDemo#2026!

Ids and seeded data

EmailUser id (fixed)Seeded tasks
demo@taskflow.local1ad4232f-68f2-42c9-a04a-7c3755e1e69f21 (Todo / In progress / Done)
reviewer@taskflow.local45874c56-7c03-4c33-bc35-d87af4f5966121 (Todo / In progress / Done)

All seeded non-null due dates are strictly after 2026-04-09 (see Risks and when to apply). Calendar-overdue rows are not included in the seed (that would require past due dates and would break the anchor rule); after real time advances past a task’s due date, list filters can show overdue behavior.

Manual run (without Docker for the app)

  1. SQL Server — start your instance or run only the sql service from Compose. Connection string format matches TaskFlow/src/TaskManager.Api/appsettings.json (use 127.0.0.1 on Windows hosts when connecting from the host to Docker SQL; Encrypt=True;TrustServerCertificate=True).

  2. API — from TaskFlow/:

    dotnet run --project src/TaskManager.Api/TaskManager.Api.csproj

    Default dev URL is shown in console (see Program.cs / launch settings).

  3. Web — from TaskFlow/src/TaskManager.Web/:

    npm ci
    npm start

    Development environment points the SPA at http://127.0.0.1:5278 (see environment.development.ts).

Tests

From TaskFlow/:

dotnet test

All test projects should pass with zero build warnings (dotnet build).

Technology highlights

Short map of where notable choices appear, why they are there, and what they are meant to demonstrate. Full behavioral and layering rules live in BACKEND_SPEC.md.

HighlightWhereWhy / what it demonstrates
Orleans 10Co-hosted silo in TaskManager.Api; grains and Orleans wiring in TaskManager.Infrastructure (e.g. task grain sync).Actor-style per-task state and activation alongside HTTP; Orleans 10 keeps grain messaging and serialization predictable, including types such as CancellationToken (see BACKEND_SPEC §3.8).
Orleans events / streamsAfter a successful SQL commit, domain events are dispatched to an SQL event log and Orleans streams; grains are updated in the dual-write order described in BACKEND_SPEC (SQL first, then events and grain projection).Shows event-driven task lifecycle handling and projection into grains—not only CRUD and not only “grain as database row”—plus familiarity with stream providers (in-memory in dev; durable providers in real deployments).
Argon2idPassword hashing in TaskManager.Infrastructure on register/login.Memory-hard hashing with strong modern defaults; deliberate choice over legacy algorithms (BACKEND_SPEC §3.1).
Clean architecture layersTaskManager.Domain, TaskManager.Application, TaskManager.Infrastructure, TaskManager.ApiDomain has no EF, Dapper, Orleans, or ASP.NET references; Application holds use-case handlers; Infrastructure implements SQL, Orleans, hashing, JWT. See BACKEND_SPEC section 3.7.
Parameterized SQL (no ORM)TaskManager.Infrastructure — e.g. SqlTaskRepository, SqlUserRepositoryMicrosoft.Data.SqlClient with bound parameters only; demonstrates explicit SQL control and injection-safe access (BACKEND_SPEC section 3.7).
RFC 7807 Problem Details + traceIdTaskManager.ApiExtensions/ProblemDetailsHttp.cs, ResultExtensions.cs, Middleware/ExceptionMiddleware.cs, JWT OnChallenge in Program.csStable error shape (application/problem+json), traceId from Activity.Current or HttpContext.TraceIdentifier; integration tests assert traceId on failures (TaskManager.Api.Tests).
JWT sub claimTaskManager.Api/Program.csJwtBearerOptions.MapInboundClaims = falseKeeps sub on the principal for owner lookups instead of default claim remapping (BACKEND_SPEC section 3.1).
CORS policyTaskManager.Api/Program.cs; Compose Cors__Origins__* in docker-compose.ymlNamed Frontend policy, explicit WithOrigins, no wildcard + credentials anti-pattern.
Due date / timezone headerAPI task endpoints + TaskManager.Webtask.service.ts (X-Timezone-Offset-Minutes)Aligns server “today” with the browser calendar for past-due validation (BACKEND_SPEC.md section 3.4; FRONTEND_SPEC.md section 3.5).
Domain status machine & soft deleteTaskManager.DomainValueObjects/TaskStatus.cs, Aggregates/Tasks/Task.csEnforced transitions (Todo → InProgress → Done / reopen rules); soft delete in SQL with list queries excluding deleted rows (BACKEND_SPEC sections 3.5–3.6).
Result / AppError pipelineTaskManager.Application (Result, AppError, ErrorType) → API ResultExtensionsUse cases return discriminated outcomes mapped to HTTP status + Problem Details without exceptions for expected failures.
Embedded SQL migrationsTaskManager.InfrastructurePersistence/SqlServerDatabaseMigrator.cs, Persistence/Scripts/*.sqlVersioned embedded scripts applied at API startup (skipped under Testing so WebApplicationFactory tests control state); includes app schema and Orleans ADO.NET setup (BACKEND_SPEC.md).
Test layoutTaskManager.Domain.Tests, TaskManager.Application.Tests, TaskManager.Infrastructure.Tests, TaskManager.Api.TestsPyramid: fast domain/application/unit tests plus HTTP integration tests via TaskFlowWebApplicationFactory and Orleans Testing profile (localhost clustering, memory streams).
Nullable reference typesAll TaskFlow project .csproj files (<Nullable>enable</Nullable>)End-to-end C# null-safety across layers.
Compose + SQL health gateRoot docker-compose.ymlSQL Server healthcheck (sqlcmd); API depends_oncondition: service_healthy so the API starts after the database is ready.

API & backend implementation notes

Compact backend-only talking points (frontend structure and patterns are in Angular app above):

  • Controllers vs minimal APIs: Classic MVC controllers in TaskManager.Api/Controllers/ (project convention in BACKEND_SPEC.md section 3.7).
  • No mediator package: Handlers are explicit DI-registered types in TaskManager.Application (no MediatR-style library).
  • Orleans profiles:Development uses localhost clustering to avoid stale SQL membership on restarts; non-dev uses ADO.NET clustering and grain storage; Testing uses in-memory Orleans per Program.cs for TaskManager.Api.Tests.
  • Dual-write reminder: SQL tasks row is the list source of truth; after commit, domain events (SQL log + memory streams in dev) and grain sync run in the order documented in BACKEND_SPEC.md §3.7 (Dual-write row).

Architecture

System diagram

flowchart TB
subgraph client [Browser]
SPA[Angular SPA]
end
subgraph host [ASP.NET Core host + Orleans silo]
API[TaskManager.Api]
JWT[JWT Bearer auth]
APP[Application layer handlers]
G[Orleans TaskGrain]
EVT[Domain events → SQL log + Orleans streams]
end
DB[(SQL Server — app schema + Orleans clustering / persistence)]
SPA -->|HTTPS REST + CORS| API
API --> JWT
JWT --> APP
APP --> DB
APP --> G
APP --> EVT
G --> DB
EVT --> DB
Loading

Layered solution

  • TaskFlow/src/TaskManager.Domain — aggregates, value objects, domain events, task status transitions.
  • TaskFlow/src/TaskManager.Application — command/query handlers (register, login, task CRUD, status change).
  • TaskFlow/src/TaskManager.Infrastructure — SQL repositories, Orleans grains and stream-backed domain dispatch, Argon2id password hashing, JWT provider.
  • TaskFlow/src/TaskManager.Api — ASP.NET Core hosts Orleans silo (SQL storage in non-dev), JWT bearer auth, Swagger in Development, CORS from Cors:Origins; demo users/tasks come from embedded SQL migrations (see 008_DemoSeed_Data.sql).
  • TaskFlow/src/TaskManager.Web — Angular (standalone, signals) + Angular Material; lazy-loaded tasks feature.

Architectural decisions and trade-offs

  • Dual-write (SQL + grain): The tasks table is the queryable source of truth for lists; after each successful commit, ITaskGrainSync projects the row into TaskGrain state so per-task concurrency and fast activation stay in Orleans without dropping relational reporting. Trade-off: two persistence legs to keep consistent (ordering: SQL first, then grain sync and events).
  • Domain events → composite dispatcher: Events go to an SQL-backed event log and Orleans streams for cross-cutting subscribers. Trade-off: more moving parts than a single bus; chosen to satisfy both durability and silo-local consumers.
  • JWT for SPA: Bearer tokens issued at login/register; Angular stores and sends them on API calls. Trade-off: stateless validation vs server sessions—appropriate for this API surface.
  • Orleans in-process with API: Simplifies local and Docker deployment; clustering uses SQL membership scripts. Trade-off: silo lifecycle tied to the API process unless scaled out explicitly.
  • Explicit CORS origins: Configured per environment (Compose sets localhost / 127.0.0.1 for the SPA). Wildcard + credentials patterns were avoided.

Public HTTP API (summary)

Base URL: http(s)://<host>:<port> (Compose maps API to 5278 on the host). Request/response and status semantics: BACKEND_SPEC.md §4.

Unauthenticated

MethodPathDescription
GET/api/public/statusHealth payload for load balancers / compose
GET/api/public/versionAPI version string
POST/api/auth/registerRegister; returns JWT + user info
POST/api/auth/loginLogin; returns JWT + user info

AuthenticatedAuthorization: Bearer <JWT>

MethodPathDescription
POST/api/tasksCreate task
GET/api/tasksList tasks (query: status, page, pageSize, sortBy, sortDir)
GET/api/tasks/{id}Get task by id
PUT/api/tasks/{id}Update task
PATCH/api/tasks/{id}/statusChange status (NewStatus body)
DELETE/api/tasks/{id}Soft-delete task

Task mutations may send header X-Timezone-Offset-Minutes (JavaScript Date.getTimezoneOffset()) for due-date calendar rules.

In Development, GET / redirects to Swagger.

Definition of Done — smoke checklist

Use this after docker compose up or local API + web. Layer-specific DoD: BACKEND_SPEC.md §8, FRONTEND_SPEC.md §10.

  • Register a new user; log in; session persists across refresh (JWT in storage).
  • Create, list (with filter/pagination), edit, change status, and delete tasks; errors show sanely.
  • Demo login shows seeded tasks (Todo / In progress / Done); overdue appears naturally once wall-clock passes a task’s future due date.
  • GET /api/public/status returns 200.
  • dotnet test green; npm run build succeeds for the SPA.

Part 2 — AI integration and GenAI workflow

This section documents only verified uses I made of generative AI in this workstream. It does not imply RAG, embeddings, or autonomous tooling. Evaluators can cross-check scope here; narrative detail and critique live in GENAI.md (expanded further in slice P-08).

  1. Chat planning and pair checks: I brought concrete goals into the assistant to debate them; together we shaped a story in the chat of what should be done. After I coded, I validated alignment with the assistant (does this match what we agreed?) and used that loop for quick verifications and time-efficient iteration—pair-style, not autonomous delivery. Requirements and final judgment stayed with me.
  2. Commit messages and naming: I used AI for wording on commit messages and branch or slice naming where useful.
  3. Code review for patterns: I used AI to recheck adherence to chosen project patterns (layers, auth, Orleans usage) before merge-style checkpoints.
  4. Repeated-code problem: Where similar handlers or wiring duplicated structure, I used AI to propose consistent patterns; I still verified with tests and review.
  5. Date validation (past vs “today”): I used AI to reason through calendar and timezone-offset rules for due dates versus the evaluation “today,” aligned with domain rules and headers.
  6. Demo seed data: I defined the demo users (fixed ids and [Demo] task titles in 008_DemoSeed_Data.sql); AI helped me shape bulk seed SQL and related data—not arbitrary production-like personas.
  7. Markdown docs: I used AI to polish my .md files (structure, readability, presentation) and to tighten adherence to specs and repo facts—always with me checking that nothing was overstated or misaligned with the codebase.

Further reflection, sample prompts, and validation notes: GENAI.md.

Risks and when to apply

  • A.9 anchor (demo due dates): Seeded tasks with non-nulldue_date are all after 2026-04-09. If you change the seed or the evaluation clock, re-check list filters and overdue behavior; do not add “forced overdue” rows without reconciling domain rules and the anchor comment in 008_DemoSeed_Data.sql.

Future improvements

  • Broader Orleans deployment (multi-silo, dashboards) beyond the single-process Docker demo.
  • Additional automated E2E coverage for auth and task flows.
  • Optional read-model projection if list query patterns outgrow direct SQL.

Repository layout

  • README.md (this file) — single entry-point documentation for the repo (API, SPA, runbooks, highlights).
  • TaskFlow/ — .NET solution, Angular app under src/TaskManager.Web/ (no separate SPA README.md).
  • docker-compose.ymlroot compose file (SQL + API + Web).

About

Task management system built with ASP.NET Core, Microsoft Orleans 10, Angular 19+, and SQL Server. Features JWT auth, DDD-driven status transitions, event-driven grain sync, Clean Architecture layers, and parameterized ADO.NET persistence — no EF, no Dapper, no MediatR.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages