PRD Studio

Smoke Test App

Product Requirements Document

Approved

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

  1. 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.
  2. User types a non-empty text string into the "New todo" input field.
  3. User submits the form by pressing Enter or clicking the "Add" button.
  4. The app sends a POST /api/todos request with the todo text.
  5. The new todo appears at the bottom of the list with a checkbox (unchecked) and a delete button.
  6. The remaining count increments by 1.
  7. The input field is cleared and focused, ready for the next entry.

Flow 2 — Mark a Todo Complete / Incomplete

  1. User sees an existing incomplete todo in the list.
  2. User clicks the checkbox next to the todo.
  3. The app sends a PATCH /api/todos/:id request toggling the completed field.
  4. The todo's text is rendered with a strikethrough style and the checkbox becomes checked.
  5. The remaining count decrements by 1.
  6. 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

  1. User hovers over or focuses any todo item; a "Delete" (×) button becomes visible.
  2. User clicks the "Delete" button.
  3. The app sends a DELETE /api/todos/:id request.
  4. The todo is removed from the list immediately.
  5. 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

  1. At least one todo is marked complete.
  2. A "Clear completed" button is visible in the footer.
  3. User clicks "Clear completed".
  4. The app sends a DELETE /api/todos?completed=true request.
  5. All completed todos are removed from the list in one operation.
  6. The remaining count is unchanged (only completed items were deleted).
  7. If no completed todos exist, the "Clear completed" button is hidden or disabled.

Flow 5 — View Remaining Count

  1. At any point the footer displays "X items left" where X is the number of todos whose completed field is false.
  2. The count updates immediately after every add, toggle, or delete action without requiring a full page reload.

Flow 6 — Persist Across Page Reloads

  1. User adds and/or completes several todos.
  2. User refreshes the browser.
  3. The page re-fetches GET /api/todos.
  4. 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 completed state.
  • F3.2 PATCH /api/todos/:id — updates the completed boolean 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

ColumnTypeConstraintsDescription
idSERIAL / INTEGERPRIMARY KEY, auto-incrementUnique identifier
textVARCHAR(500)NOT NULL, CHECK (length > 0)The todo's display text
completedBOOLEANNOT NULL, DEFAULT falseCompletion state
created_atTIMESTAMPTZNOT NULL, DEFAULT NOW()Insertion timestamp used for ordering

No other entities are required. No users table, no tags table.

API Endpoints (contract)

MethodPathRequest BodyResponseDescription
GET/api/todos200 Todo[]Return all todos ordered by created_at ASC
POST/api/todos{ text: string }201 TodoCreate new todo
PATCH/api/todos/:id{ completed: boolean }200 TodoToggle completion
DELETE/api/todos/:id204Delete single todo
DELETE/api/todos?completed=true204Delete 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 (400 for bad input, 404 for missing resource, 500 for 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-label attributes.
  • 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

LayerTechnology
FrameworkNext.js 14+ (App Router or Pages Router)
LanguageTypeScript
DatabasePostgreSQL 15+
DB Accesspg (node-postgres) or Prisma ORM
StylingTailwind CSS (or CSS Modules as fallback)
RuntimeNode.js 18+
Environment.env.local for DATABASE_URL

9. Acceptance Criteria

Setup & Boot

  • npm run dev starts the app without errors.
  • The app connects to PostgreSQL using DATABASE_URL from .env.local.
  • A todos table 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 todos table.
  • 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 completed to true in the database.
  • The todo text renders with a strikethrough when completed = true.
  • Clicking the checkbox again sets completed back to false and 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 todos table.
  • 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 = true from 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/todos with { text: "" } returns 400.
  • PATCH /api/todos/99999 (non-existent ID) returns 404.
  • DELETE /api/todos/99999 (non-existent ID) returns 404.

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_URL value 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".