From dd2989c8b01d80bf7224305908ba27e851572685 Mon Sep 17 00:00:00 2001 From: Jeison Tamara Date: Wed, 1 Apr 2026 20:34:10 -0500 Subject: [PATCH 01/19] Align challenge brief: README checklist, PATCH priority, Bun-first docs - Document requirements vs implementation in README; submission and AI notes - PATCH /api/tasks/:id accepts optional priority alongside title, description, columnId - package.json engines: add Bun; empty states mention bun/npm seed - Fix ESLint: remove unused import; suppress set-state-in-effect for mount fetch --- .gitignore | 44 + .nvmrc | 1 + README.md | 148 +- eslint.config.mjs | 18 + next.config.ts | 5 + package-lock.json | 7116 ++++++++++++++++++++++++++++++ package.json | 33 + postcss.config.mjs | 7 + public/file.svg | 1 + public/globe.svg | 1 + public/next.svg | 1 + public/vercel.svg | 1 + public/window.svg | 1 + scripts/seed.ts | 70 + src/app/api/boards/[id]/route.ts | 69 + src/app/api/boards/route.ts | 34 + src/app/api/columns/route.ts | 69 + src/app/api/tasks/[id]/route.ts | 103 + src/app/api/tasks/route.ts | 52 + src/app/boards/[id]/page.tsx | 426 ++ src/app/favicon.ico | Bin 0 -> 25931 bytes src/app/globals.css | 26 + src/app/layout.tsx | 33 + src/app/page.tsx | 126 + src/lib/api-response.ts | 39 + src/lib/client-api.ts | 14 + src/lib/db.ts | 56 + src/lib/schemas.ts | 38 + src/lib/types.ts | 31 + tsconfig.json | 34 + 30 files changed, 8515 insertions(+), 82 deletions(-) create mode 100644 .gitignore create mode 100644 .nvmrc create mode 100644 eslint.config.mjs create mode 100644 next.config.ts create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 postcss.config.mjs create mode 100644 public/file.svg create mode 100644 public/globe.svg create mode 100644 public/next.svg create mode 100644 public/vercel.svg create mode 100644 public/window.svg create mode 100644 scripts/seed.ts create mode 100644 src/app/api/boards/[id]/route.ts create mode 100644 src/app/api/boards/route.ts create mode 100644 src/app/api/columns/route.ts create mode 100644 src/app/api/tasks/[id]/route.ts create mode 100644 src/app/api/tasks/route.ts create mode 100644 src/app/boards/[id]/page.tsx create mode 100644 src/app/favicon.ico create mode 100644 src/app/globals.css create mode 100644 src/app/layout.tsx create mode 100644 src/app/page.tsx create mode 100644 src/lib/api-response.ts create mode 100644 src/lib/client-api.ts create mode 100644 src/lib/db.ts create mode 100644 src/lib/schemas.ts create mode 100644 src/lib/types.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba4259 --- /dev/null +++ b/.gitignore @@ -0,0 +1,44 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# SQLite (local dev) +/data/ diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..2bd5a0a --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +22 diff --git a/README.md b/README.md index 4b5193e..6eed6d7 100644 --- a/README.md +++ b/README.md @@ -1,107 +1,91 @@ -## Technical Challenge — Mid-Level +# Mid-Level Fullstack Technical Challenge — Solution -### Background +Task board (**Next.js App Router**, **SQLite**, **Tailwind CSS**, **Zod** validation). **Runtime: [Bun](https://bun.sh)** per the challenge brief; **Node.js 22.5+** is also supported. The app uses Node’s [`node:sqlite`](https://nodejs.org/api/sqlite.html) (`DatabaseSync`), which Bun implements for compatibility—same code path for `bun run dev` / `npm run dev`. -A small project management startup wants to build a simple internal tool for their team to organize work visually. They need a basic task board where team members can create boards, organize tasks into columns, and move tasks between stages. +## Run locally -In this challenge, you'll build a simplified task board application with a REST API, a database, and a functional UI. +### With Bun (challenge brief) -We are **not evaluating specific tools or patterns**. We simply want to understand how you think, how you code, and how you approach real-world problems. Be yourself. +Install [Bun](https://bun.sh/docs/installation), then from the project root: +```bash +bun install +bun run seed # optional: one board "Sample board" with columns and tasks +bun run dev +``` -### What You Need to Build +### With Node + npm -A functional **full stack application** with the ability to: +**Requirements:** Node **≥ 22.5** (for `node:sqlite`). -1. Create and view boards -2. Add columns to a board -3. Create, update, and delete tasks within columns -4. Move tasks between columns -5. View a board in a kanban-style layout +**nvm (Windows / nvm-windows):** the repo includes `.nvmrc` with `22`. +```bash +nvm install 22 +nvm use 22 +node -v # v22.x.x (≥ 22.5) +``` -### Database Schema +```bash +npm install +npm run seed # optional +npm run dev +``` -Design the schema yourself. At minimum, you should support: +Open [http://localhost:3000](http://localhost:3000). Open a board from the list to see the Kanban view. -- **Boards** with a name and creation date -- **Columns** belonging to a board, with a name and display order -- **Tasks** belonging to a column, with: title, description, priority, and creation date +## Challenge checklist -Include appropriate indexes and a seed script that creates one board with sample data. +| Requirement | How it’s met | +| ----------- | ------------ | +| Boards (name, creation date) | `boards` table; `GET/POST /api/boards` | +| Columns per board (name, display order) | `columns` + unique `(board_id, display_order)`; `POST /api/columns` | +| Tasks (title, description, priority, creation date) | `tasks` table; `POST/PATCH/DELETE /api/tasks` | +| Indexes | See `src/lib/db.ts` (boards, columns, tasks, FKs + WAL) | +| Seed script | `npm run seed` / `bun run seed` → `scripts/seed.ts` | +| API endpoints + validation + status codes | `src/app/api/**` + Zod in `src/lib/schemas.ts` | +| Consistent JSON | `{ ok, data }` / `{ ok: false, error: { code, message, details? } }` in `src/lib/api-response.ts` | +| Kanban UI, modal new task, dropdown move | `src/app/boards/[id]/page.tsx` | +| Loading & empty states | Home + board pages | +## Scripts -### Tech Stack +| Command | Description | +| ------- | ----------- | +| `bun run dev` / `npm run dev` | Next.js dev (Turbopack) | +| `bun run build` / `npm run build` | Production build | +| `bun run start` / `npm start` | Serve production build | +| `bun run seed` / `npm run seed` | One board `"Sample board"` (replaces existing row with same name) | +| `bun run lint` / `npm run lint` | ESLint | -#### Backend +## API -* Runtime: **Bun** -* Framework: **Next.js** (App Router) -* Database: **SQLite** (ORM, query builder, or raw SQL — your choice) +| Method | Path | Description | +| ------ | ---- | ----------- | +| `GET` | `/api/boards` | List boards | +| `POST` | `/api/boards` | Create `{ "name" }` | +| `GET` | `/api/boards/:id` | Board with columns and tasks | +| `POST` | `/api/columns` | Create column `{ "boardId", "name", "displayOrder" }` | +| `POST` | `/api/tasks` | Create `{ "columnId", "title", "description?", "priority?" }` | +| `PATCH` | `/api/tasks/:id` | Partial update: `title`, `description`, `columnId` (same board only), `priority` | +| `DELETE` | `/api/tasks/:id` | Delete task | -#### Frontend +Database file: `data/app.db` (gitignored). -* Framework: **Next.js** -* Styling: **TailwindCSS** -* Additional UI libraries are welcome but not required +## Architecture +- **`src/lib/db.ts`:** SQLite (`data/app.db`), schema, indexes, `PRAGMA foreign_keys`, WAL. No native addons beyond the runtime’s SQLite binding. +- **`src/lib/schemas.ts` + `src/lib/api-response.ts`:** Zod validation and uniform JSON errors (400 / 404 / 409, etc.). +- **`src/app/api/**`:** Route handlers: validate → DB → respond. +- **`src/app/page.tsx`:** Board list, create board, loading and empty states. +- **`src/app/boards/[id]/page.tsx`:** Kanban columns, task cards, modal for new tasks, ` setColName(e.target.value)} + placeholder="Column name" + /> + + + + + + + {b.columns.length === 0 ? ( +

+ No columns yet. Add a column above to start the board, or run{" "} + + bun run seed + {" "} + /{" "} + + npm run seed + + . +

+ ) : ( +
+ {b.columns.map((col) => ( +
+
+

+ {col.name} +

+

Order {col.displayOrder}

+
+
    + {col.tasks.length === 0 ? ( +
  • + No tasks +
  • + ) : ( + col.tasks.map((task) => ( +
  • +
    + + {task.title} + + + {task.priority} + +
    + {task.description ? ( +

    + {task.description} +

    + ) : null} +
    + + +
    +
  • + )) + )} +
+
+ ))} +
+ )} + + {modalOpen ? ( +
+
+

+ New task +

+
+ + +