Skip to content

31adityakumar/taskflow-adityakumar

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TaskFlow

TaskFlow is a backend-focused task management API for projects and tasks. It supports registration, login, JWT-protected project/task workflows, owner checks, task assignment, pagination, and project stats.

This submission targets the Backend Engineer role, so there is no React app. Instead, the repo includes a Postman collection at docs/taskflow.postman_collection.json.

1. Overview

Tech stack:

  • Go 1.23
  • PostgreSQL 16
  • database/sql with lib/pq
  • golang-migrate for versioned migrations
  • bcrypt with cost 12 or higher
  • JWT access tokens with 24-hour expiry
  • Docker Compose for local infrastructure
  • slog JSON logs

Core capabilities:

  • Register and log in users
  • Create, list, update, and delete projects
  • Create, list, update, and delete tasks inside projects
  • Assign tasks to any existing user
  • Filter tasks by status and assignee
  • Return project-level task stats

2. Architecture Decisions

The backend uses a small layered structure:

  • cmd/api owns process startup, logging, migration/seed execution, and graceful shutdown.
  • internal/httpapi owns routing, validation, JSON responses, auth middleware, and authorization decisions.
  • internal/store owns SQL queries and maps PostgreSQL rows into API models.
  • internal/auth owns JWT creation and parsing.
  • internal/database owns Postgres connectivity, migrations, and seed data.

I used the standard library HTTP router instead of adding a framework. The routing surface is small, so explicit path dispatch keeps the behavior easy to inspect in a review call.

The schema adds creator_id to tasks. The assignment requires deleting tasks only when the caller is the project owner or task creator, and that rule needs durable data.

Authorization rules:

  • Any authenticated user can create a project.
  • A project is visible to its owner, task creators, and assignees.
  • Only the project owner can update or delete a project.
  • Task updates are allowed for the project owner, task creator, or current assignee.
  • Task deletion is allowed only for the project owner or task creator.

Tradeoffs:

  • There is no separate project membership table. Assignment is task-based, which matches the constrained scope but would be too thin for a larger product.
  • Pagination is intentionally simple: page and limit, with a max limit of 100 and no total count.
  • The API uses access tokens only. Refresh tokens, token revocation, and password reset flows are intentionally out of scope.
  • Automated integration tests are not included in this pass; the Postman collection covers reviewer verification. With more time, I would add container-backed integration tests around auth and task authorization.

3. Running Locally

Assume the reviewer has Docker and nothing else installed.

git clone https://github.com/31adityakumar/taskflow-adityakumar
cd taskflow-adityakumar
cp .env.example .env
docker compose up --build

API available at:

http://localhost:8080

Health check:

curl http://localhost:8080/healthz

Login with the seed user:

curl -X POST http://localhost:8080/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com","password":"password123"}'

4. Running Migrations

Migrations run automatically when the API container starts.

The migration files live in:

backend/db/migrations

Every migration has both an up and down file. The API uses golang-migrate internally and starts with:

RUN_MIGRATIONS=true
MIGRATIONS_PATH=/migrations

Seed data also runs automatically by default:

SEED_ON_START=true

The equivalent seed SQL is included at:

backend/db/seed.sql

To disable automatic seeding, set SEED_ON_START=false in .env.

5. Test Credentials

Use these credentials immediately after docker compose up --build:

Email:    test@example.com
Password: password123

Seed data includes:

  • 1 user
  • 1 project
  • 3 tasks with todo, in_progress, and done statuses

6. API Reference

Import the Postman collection:

docs/taskflow.postman_collection.json

All protected endpoints require:

Authorization: Bearer <token>

All responses use JSON. Validation errors use:

{
  "error": "validation failed",
  "fields": {
    "email": "is required"
  }
}

Common errors:

{ "error": "unauthorized" }
{ "error": "forbidden" }
{ "error": "not found" }

Auth

POST /auth/register

Request:

{
  "name": "Jane Doe",
  "email": "jane@example.com",
  "password": "secret123"
}

Response 201:

{
  "token": "<jwt>",
  "user": {
    "id": "uuid",
    "name": "Jane Doe",
    "email": "jane@example.com",
    "created_at": "2026-04-14T10:00:00Z"
  }
}

POST /auth/login

Request:

{
  "email": "test@example.com",
  "password": "password123"
}

Response 200:

{
  "token": "<jwt>",
  "user": {
    "id": "uuid",
    "name": "Test User",
    "email": "test@example.com",
    "created_at": "2026-04-14T10:00:00Z"
  }
}

Projects

GET /projects?page=1&limit=20

Response 200:

{
  "projects": [
    {
      "id": "uuid",
      "name": "Greening India Launch",
      "description": "Seed project for reviewer testing",
      "owner_id": "uuid",
      "created_at": "2026-04-14T10:00:00Z"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20
  }
}

POST /projects

Request:

{
  "name": "Restaurant Ops Board",
  "description": "Track launch readiness"
}

Response 201: created project object.

GET /projects/:id

Response 200:

{
  "id": "uuid",
  "name": "Greening India Launch",
  "description": "Seed project for reviewer testing",
  "owner_id": "uuid",
  "created_at": "2026-04-14T10:00:00Z",
  "tasks": []
}

PATCH /projects/:id

Request:

{
  "name": "Updated Name",
  "description": "Updated description"
}

Response 200: updated project object.

DELETE /projects/:id

Response 204.

GET /projects/:id/stats

Response 200:

{
  "by_status": {
    "todo": 1,
    "in_progress": 1,
    "done": 1
  },
  "by_assignee": [
    {
      "assignee_id": "uuid",
      "name": "Test User",
      "email": "test@example.com",
      "count": 3
    }
  ]
}

Tasks

GET /projects/:id/tasks?status=todo&assignee=uuid&page=1&limit=20

Response 200:

{
  "tasks": [],
  "meta": {
    "page": 1,
    "limit": 20
  }
}

POST /projects/:id/tasks

Request:

{
  "title": "Prepare demo script",
  "description": "Keep the backend flow crisp",
  "priority": "high",
  "assignee_id": "uuid",
  "due_date": "2026-04-25"
}

Response 201: created task object.

PATCH /tasks/:id

Request:

{
  "title": "Updated title",
  "status": "done",
  "priority": "low",
  "assignee_id": null,
  "due_date": "2026-04-30"
}

Response 200: updated task object.

DELETE /tasks/:id

Response 204.

7. What You'd Do With More Time

  • Add container-backed integration tests for auth, task assignment, and authorization edge cases.
  • Add a project membership model so access does not depend only on task assignment.
  • Add total counts to paginated responses.
  • Add refresh tokens and token revocation for a more complete auth story.
  • Add CI that runs go test, builds the Docker image, and validates migrations from a clean database.
  • Add audit fields for task status transitions if this became a real team workflow product.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors