Smoke Test App
Product Requirements Document
Smoke Test App
1. Overview
Smoke Test App is a minimal, single-page todo application built with Next.js and PostgreSQL. It allows users to add todo items, mark them as complete, delete them individually or in bulk (clear all completed), and always see an up-to-date count of remaining (incomplete) todos. The app requires no authentication — all todos are stored in a shared, publicly visible list. It is intended as an internal smoke-test harness to verify that the core full-stack pipeline (UI → API → database) works end-to-end.
2. Goals & Non-Goals
Goals
- Provide a working, deployable todo app with persistent storage in PostgreSQL.
- Demonstrate a functioning Next.js full-stack setup (React frontend + API Routes backend).
- Support creating, completing, and deleting todos with real-time UI feedback.
- Display an accurate count of remaining (incomplete) todos at all times.
Non-Goals
- User authentication, accounts, or per-user todo lists.
- Due dates, priorities, tags, categories, or any rich metadata on todos.
- Real-time multi-user sync (e.g., WebSockets, polling).
- Mobile-native apps (web only).
- Offline support or service workers.
- Pagination or search/filtering of todos.
3. Target Users
Internal developers and QA engineers who need a lightweight, representative full-stack application to verify that the deployment pipeline, database connectivity, and UI rendering are all functioning correctly. No public sign-up is required or expected.
4. User Flows
Flow 1 — Add a Todo
- User opens the app in a browser; the page loads and displays the todo list (empty or pre-existing items) and a remaining-count badge.
- User types a non-empty text string into the "New todo" input field.
- User submits the form by pressing Enter or clicking the "Add" button.
- The app sends a
POST /api/todosrequest with the todo text. - The new todo appears at the bottom of the list with a checkbox (unchecked) and a delete button.
- The remaining count increments by 1.
- The input field is cleared and focused, ready for the next entry.
Flow 2 — Mark a Todo Complete / Incomplete
- User sees an existing incomplete todo in the list.
- User clicks the checkbox next to the todo.
- The app sends a
PATCH /api/todos/:idrequest toggling thecompletedfield. - The todo's text is rendered with a strikethrough style and the checkbox becomes checked.
- The remaining count decrements by 1.
- User may click the checkbox again to unmark it; the strikethrough is removed and the remaining count increments by 1.
Flow 3 — Delete a Single Todo
- User hovers over or focuses any todo item; a "Delete" (×) button becomes visible.
- User clicks the "Delete" button.
- The app sends a
DELETE /api/todos/:idrequest. - The todo is removed from the list immediately.
- If the deleted todo was incomplete, the remaining count decrements by 1; if it was already complete, the count is unchanged.
Flow 4 — Clear All Completed Todos
- At least one todo is marked complete.
- A "Clear completed" button is visible in the footer.
- User clicks "Clear completed".
- The app sends a
DELETE /api/todos?completed=truerequest. - All completed todos are removed from the list in one operation.
- The remaining count is unchanged (only completed items were deleted).
- If no completed todos exist, the "Clear completed" button is hidden or disabled.
Flow 5 — View Remaining Count
- At any point the footer displays "X items left" where X is the number of todos whose
completedfield isfalse. - The count updates immediately after every add, toggle, or delete action without requiring a full page reload.
Flow 6 — Persist Across Page Reloads
- User adds and/or completes several todos.
- User refreshes the browser.
- The page re-fetches
GET /api/todos. - All todos reappear with their correct completion states.
5. Features
F1 — Todo List Display (MUST)
- F1.1 Fetch and render all todos on initial page load via
GET /api/todos. - F1.2 Display each todo with: a checkbox, the todo text, and a delete (×) button.
- F1.3 Render completed todos with a strikethrough on the text and a checked checkbox.
- F1.4 Display todos in insertion order (oldest first).
F2 — Add Todo (MUST)
- F2.1 Provide a text input and an "Add" button in a form.
- F2.2 Submit via Enter key or button click.
- F2.3 Reject empty or whitespace-only input (show an inline validation message or disable the button).
- F2.4
POST /api/todos— creates a new todo record in PostgreSQL. - F2.5 Clear and refocus the input after successful submission.
F3 — Complete / Uncomplete Todo (MUST)
- F3.1 Clicking a todo's checkbox toggles its
completedstate. - F3.2
PATCH /api/todos/:id— updates thecompletedboolean in PostgreSQL. - F3.3 UI updates immediately to reflect new state (optimistic or server-confirmed).
F4 — Delete Single Todo (MUST)
- F4.1 Each todo row has a delete button.
- F4.2
DELETE /api/todos/:id— removes the record from PostgreSQL. - F4.3 Todo disappears from the UI immediately after deletion.
F5 — Clear All Completed (MUST)
- F5.1 "Clear completed" button appears in the footer only when at least one completed todo exists.
- F5.2
DELETE /api/todos?completed=true— bulk-deletes all completed records. - F5.3 All completed todos are removed from the UI in one operation.
F6 — Remaining Count (MUST)
- F6.1 Footer displays "X items left" reflecting the count of incomplete todos.
- F6.2 Count updates immediately on every state change.
- F6.3 Displays "1 item left" (singular) vs "0 items left" / "2 items left" (plural).
F7 — Data Persistence (MUST)
- F7.1 All todo state is stored in PostgreSQL; no in-memory-only storage.
- F7.2 Data survives server restarts and full browser refreshes.
F8 — Basic Styling (NICE-TO-HAVE)
- F8.1 Clean, readable layout centered on the page.
- F8.2 Strikethrough + muted color on completed items.
- F8.3 Hover state reveals the delete button.
6. Data Model
Entity: todos
| Column | Type | Constraints | Description |
|---|---|---|---|
id | SERIAL / INTEGER | PRIMARY KEY, auto-increment | Unique identifier |
text | VARCHAR(500) | NOT NULL, CHECK (length > 0) | The todo's display text |
completed | BOOLEAN | NOT NULL, DEFAULT false | Completion state |
created_at | TIMESTAMPTZ | NOT NULL, DEFAULT NOW() | Insertion timestamp used for ordering |
No other entities are required. No users table, no tags table.
API Endpoints (contract)
| Method | Path | Request Body | Response | Description |
|---|---|---|---|---|
GET | /api/todos | — | 200 Todo[] | Return all todos ordered by created_at ASC |
POST | /api/todos | { text: string } | 201 Todo | Create new todo |
PATCH | /api/todos/:id | { completed: boolean } | 200 Todo | Toggle completion |
DELETE | /api/todos/:id | — | 204 | Delete single todo |
DELETE | /api/todos?completed=true | — | 204 | Delete all completed todos |
7. Non-Functional Requirements
- NFR-1 Performance: Initial page load (including data fetch) must complete in under 3 seconds on a local or same-region network.
- NFR-2 Reliability: API routes must return appropriate HTTP error codes (
400for bad input,404for missing resource,500for unexpected server errors) with a JSON error message body. - NFR-3 Data Integrity: The database must enforce NOT NULL and length constraints; invalid rows must never be inserted.
- NFR-4 Accessibility: All interactive elements (checkboxes, buttons, input) must be keyboard-navigable and have accessible labels or
aria-labelattributes. - NFR-5 Responsiveness: The layout must be usable on viewports as narrow as 320 px.
- NFR-6 Environment Config: Database connection string must be read from an environment variable (
DATABASE_URL) and must never be hard-coded.
8. Tech Stack
| Layer | Technology |
|---|---|
| Framework | Next.js 14+ (App Router or Pages Router) |
| Language | TypeScript |
| Database | PostgreSQL 15+ |
| DB Access | pg (node-postgres) or Prisma ORM |
| Styling | Tailwind CSS (or CSS Modules as fallback) |
| Runtime | Node.js 18+ |
| Environment | .env.local for DATABASE_URL |
9. Acceptance Criteria
Setup & Boot
-
npm run devstarts the app without errors. - The app connects to PostgreSQL using
DATABASE_URLfrom.env.local. - A
todostable with the schema in §6 is created automatically on first run (via migration or init script).
Add Todo
- Submitting a non-empty string via the input creates a new row in the
todostable. - The new todo appears in the UI list without a full page reload.
- The remaining count increases by 1.
- Submitting an empty or whitespace-only string does NOT create a todo; an error or disabled state is shown.
Complete / Uncomplete Todo
- Clicking a checkbox changes
completedtotruein the database. - The todo text renders with a strikethrough when
completed = true. - Clicking the checkbox again sets
completedback tofalseand removes the strikethrough. - The remaining count decrements by 1 when completed and increments by 1 when uncompleted.
Delete Single Todo
- Clicking the delete button removes the row from the
todostable. - The todo disappears from the UI immediately.
- Remaining count adjusts correctly based on whether the deleted todo was complete or not.
Clear Completed
- "Clear completed" button is hidden when zero todos are marked complete.
- "Clear completed" button is visible when one or more todos are marked complete.
- Clicking it removes all rows where
completed = truefrom the database. - Only completed todos are removed; incomplete todos remain untouched.
Remaining Count
- Footer shows "1 item left" (singular) when exactly 1 incomplete todo exists.
- Footer shows "0 items left" when all todos are completed or no todos exist.
- Count is always consistent with the actual number of incomplete rows in the DB.
Persistence
- After a full browser refresh, all todos reappear with correct completion states.
- After a server restart (stop/start
npm run dev), all todos are still present.
API Validation
-
POST /api/todoswith{ text: "" }returns400. -
PATCH /api/todos/99999(non-existent ID) returns404. -
DELETE /api/todos/99999(non-existent ID) returns404.
Non-Functional
- All interactive elements are reachable and operable via keyboard alone.
- The page layout does not break at 320 px viewport width.
- No
DATABASE_URLvalue appears anywhere in committed source code.
10. Out of Scope
- User authentication, sessions, or per-user data isolation.
- Todo editing (changing the text of an existing todo).
- Due dates, priorities, labels, or sub-tasks.
- Real-time sync across multiple browser tabs or users.
- Search, filtering, or sorting controls beyond default insertion order.
- Pagination or infinite scroll.
- Email or push notifications.
- Unit or integration test files (the PRD itself is the test specification).
- CI/CD pipeline configuration.
- Production deployment scripts or Docker setup.
Revision chat
Ask to add features, change a flow, or clarify anything.
e.g. "Add email reminders" or "Change signup to use magic links".