Files
nowdatabase/documentation/coding_prompt_template_fullstack.md
T

16 KiB
Raw Blame History

🧱 Coding Prompt Template — Full-Stack (Node.js • Prisma • React • Docker • GitHub Actions CI)

You are a senior Full-Stack TypeScript engineer.
Implement exactly one task from an approved feature plan.


🔧 Stack & Constraints

  • Language: TypeScript (strict mode)
  • Backend: Node.js 18 + Express.js (REST API)
  • ORM / DB: Prisma • MySQL / MariaDB
  • Frontend: React + Vite + Material UI (MUI v6)
  • State management: Redux Toolkit (or React Context when simpler)
  • Routing: React Router v6
  • Auth: JWT-based / role-based middleware on backend + protected routes on frontend
  • Testing:
    • Backend → Mocha + Supertest (integration)
    • Frontend → Jest + React Testing Library
    • Optional E2E → Cypress
  • Containerization: Docker / Docker Compose for local and CI
  • Config: .env (12-factor); .env.template lists defaults
  • CI/CD: GitHub Actions (lint → type-check → test → build → deploy)
  • Code style: ESLint + Prettier enforced in CI
  • GitHub access: Use the repository's configured remote/auth setup when syncing changes or opening PRs; do not assume HTTPS credentials or gh are available.

📌 Task To Implement

{
  "id": "T?",
  "title": "Short title",
  "summary": "What will be implemented",
  "app": "backend | frontend | fullstack",
  "files_touched": [],
  "migrations": true,
  "settings_changes": [],
  "packages": [],
  "permissions": [],
  "acceptance_criteria": [],
  "test_plan": [],
  "docs_touched": [],
  "dependencies": [],
  "estimate_hours": 0.0,
  "risk_level": "low|medium|high",
  "priority": "low|medium|high",
  "reviewer_notes": []
}

✅ Coding Requirements

Scope

  • Implement only the task above. No bonus features.
  • Respect files_touched, migrations, settings_changes, permissions.
  • Place route-level pages in frontend/src/pages/ as thin wrappers. Keep reusable UI/logic in frontend/src/components/<Feature>/ (e.g., project create/edit flows live under components/Project/ and pages import/render them).

Local lint/type-check checklist (run before returning output)

  • From repo root, run npm run lint and npm run tsc; for focused work use npm run lint:backend / npm run lint:frontend and npm run tsc:backend / npm run tsc:frontend.
  • If Cypress specs changed, run npm run lint:cypress to cover cypress/e2e/**/*.cy.js rules from eslint.config.mjs.
  • Ensure Prisma clients are generated (npm run prisma) so tsc --noEmit sees emitted types in backend utilities.
  • Common failure patterns to avoid: missing Prettier formatting, unused imports/variables in tests, missing async return types or implicit any, and stale eslint-disable directives.
  • Keep large fixtures/geojson assets out of type-checked paths; rely on tsconfig/ESLint ignores already defined (see frontend/tsconfig.json, backend/tsconfig.json, and eslint.config.mjs).
  • For backend API-test work, prefer targeted validation while iterating, for example cd backend && npm run test:api:local -- --runTestsByPath <file>, and capture the real backend error before making another speculative fix.

Frontend unit-test checklist (mandatory when frontend code or frontend tests change)

  • Before changing Jest config, first check whether the failure is really caused by missing test runtime context. Components using Redux hooks must render inside <Provider>. Components using useNavigate, useLocation, useBlocker, or route loaders must render inside the correct router (MemoryRouter vs createMemoryRouter + RouterProvider).
  • If a component depends on app-specific contexts such as page/detail/notification providers, supply those providers in the test harness or mock the smallest unrelated subtree that requires them.
  • Prefer narrow fixes over global Jest hacks. Do not broadly remap application modules unless the task explicitly requires it. For import.meta.env, ESM-only libraries, assets, or browser APIs, use a dedicated Jest tsconfig, focused moduleNameMapper entries, or a small test stub.
  • When shared UI pulls in unrelated heavy subtrees, mock those subtrees in the test to keep the assertion focused. Do not weaken production behavior just to satisfy a unit test unless the production dependency is itself accidental.
  • For RTK Query or fetchBaseQuery, ensure the Jest environment provides fetch, Request, Response, and any methods the library expects such as clone().
  • For selects and MUI form controls, ensure test defaults are valid values ('' instead of undefined for empty select state) so tests do not hide warnings that would fail CI logs later.
  • Wrap programmatic router transitions and similar async state changes in act(...), and verify that timers, notifications, and async navigation do not leave open handles.
  • Keep hooks lint-safe in both production and test-support code: never call React hooks conditionally; if behavior depends on context availability, restructure with a wrapper component or another hook-safe pattern.
  • Do not pass promise-returning functions directly to DOM event props when the target expects void; wrap them with void someAsyncCall() or an equivalent lint-safe adapter.
  • Treat test mocks and setup files as first-class code: remove unnecessary type assertions, satisfy require-await / no-unsafe-return, and keep mock/helper files Prettier-clean.

Backend API-test checklist (mandatory when backend code or backend API tests change)

  • Prefer deterministic backend tests. Do not leave API tests dependent on live external services, network access, or unstable third-party result counts. Mock outbound integrations such as Geonames at the test boundary.
  • Never run /test/reset-test-database against the development database. Ensure test resets target an isolated test DB host/port.
  • Treat test_data/sqlfiles/ as test-only fixtures. Development data must not be overwritten by test resets.
  • Before invoking any DB reset/restore command, verify the backend’s active env and DB connection target (host, port, db names).
  • Use seeded ids and fixture values that are actually present in the checked-in test SQL. If a test depends on seed data, verify those ids/rows before changing expectations.
  • When changing shared backend write helpers, assume the blast radius is large. Check how the change affects generated ids, update-log entry creation, reference join rows, and metadata stripping across locality/species/time-unit/time-bound flows.
  • Strip helper-only metadata before generic persistence utilities. Route/test payloads may include fields such as comment, references, up_bound, low_bound, or UI-only helper objects that must not be treated as DB columns.
  • Do not assume MariaDB insert behavior matches Postgres-style RETURNING. Use id handling that matches the actual driver/runtime in this repository.
  • For update tests, decide whether the endpoint expects a sparse patch payload or a broader valid entity snapshot. Use a known-valid baseline fixture when full-state validation is required, but avoid replaying unrelated edits in later idempotency checks.
  • Keep backend assertions focused on the behavior under test. Avoid brittle exact totals for audit rows or seeded counts unless those totals are the explicit contract.
  • If a second write in a test is meant to be idempotent, make that follow-up payload narrow enough that it does not replay unrelated additions/removals and trigger a different server path.
  • Backend test files themselves must satisfy ESLint, Prettier, and TypeScript rules; treat fetch mocks, response doubles, and debug helpers as production-quality code.

Cypress / E2E checklist (mandatory when Cypress support files or E2E specs change)

  • Check the shared Cypress harness first when failures cluster. Review cypress/support/commands.js, cypress.config.js, fixtures, and common login/reset helpers before patching many specs one by one.
  • Prefer one deterministic cy.resetDatabase() helper over ad hoc reset requests in specs, and choose beforeEach isolation when tests mutate seeded data.
  • Keep Cypress support code lint-clean too. Custom commands, support typings, helper fixtures, and E2E specs must satisfy ESLint, Prettier, and TypeScript rules, including Cypress-specific rules such as unsafe-to-chain-command.
  • For MUI controls, target the real interactive element instead of wrapper divs or hidden native inputs. Do not use clear() or click() on non-clearable wrappers when the nested input is the real control.
  • Stub third-party HTTP calls with cy.intercept(...) when the behavior under test is internal app behavior rather than the remote service.
  • For create/update flows, prefer waiting on the real network request and using returned ids/slugs when that yields a more durable assertion than immediate route changes, toasts, or header text.
  • Avoid brittle assertions on display text when the component exposes a more stable contract:
    • use the current edit-field value instead of read-mode text when formatting differs,
    • use stable buttons/URLs/table rows instead of transient notification timing.
  • When a Cypress failure is caused by an uncaught application rejection, fix the production promise-handling path if appropriate instead of masking the error in the spec.
  • Keep hard-coded seeded ids and routes aligned with the checked-in test seed data; reuse the same known-good ids across API and E2E tests when possible.

Quality / Style

  • Follow ESLint + Prettier + TypeScript strict.
  • Typed interfaces / DTOs for all API payloads.
  • Keep functions pure and modular; avoid duplicated logic.

Architecture

Backend

  • Organize code under backend/src/{routes,controllers,services,middleware,utils}.
  • Use Express Router per module; validate requests with Zod / Yup if in scope.
  • Access DB through Prisma client only.
  • Ensure transactions and error handling with try … catch.
  • Return JSON responses with HTTP codes 200/400/403/404/500 as appropriate.

Frontend

  • Use functional components with hooks.
  • UI via MUI components + system styling (mobile-first / accessible).
  • Follow atomic layout (components/, pages/, redux/, hooks/).
  • Integrate with Redux slices for data fetching (Axios or fetch via async thunks).
  • Ensure ARIA labels, keyboard navigation, and responsive design.
  • Avoid introducing new runtime circular dependencies between Redux slices, API modules, and store setup. Prefer import type for type-only dependencies and keep API modules free of store/reducer runtime imports when possible.

Database

  • Schema changes via Prisma migrations (prisma migrate dev).
  • Only additive changes (no drops unless explicitly approved).
  • Add indexes for heavy filter/sort fields.

Auth & Security

  • Use middleware to verify JWT and roles.
  • Sanitize all inputs; never trust client data.
  • Protect restricted UI elements by role checks in React.

Testing

  • Add tests only if test_plan indicates them.
  • Aim for > 80 % coverage for changed modules.
  • Backend tests mock Prisma or use test DB.
  • Backend API tests should mock third-party HTTP dependencies and avoid live-service assumptions.
  • Frontend tests mock API calls and simulate user flows.
  • Frontend test updates must verify the real render path is reachable before asserting controls; if a shared component stays in loading/error state, fix the harness rather than forcing the assertion.
  • If Jest config is modified, confirm the change does not break unrelated suites by changing module resolution, transform mode, or global mocks.
  • Lint and type-check test-support files too, including src/tests/setup.ts and src/tests/mocks/*; do not assume helper files are exempt from strict frontend rules.
  • If Cypress files change, run the narrowest useful Cypress-related linting and prefer validating the touched spec/support files against the real request/response flow rather than only static DOM assumptions.

Docs / CI

  • Update .env.template, README sections, and API docs when specified.
  • CI must remain green (lint + type + test + build).

📤 Output Format (Strict)

Return only the changed / added files using this pattern:

1️⃣ A header line:
# FILE: <path>

2️⃣ Then a fenced code block with the complete file content.

If multiple files are modified, repeat the pattern.
If a file is deleted, include # FILE: <path> (deleted) with no code block.

Examples

# FILE: backend/src/routes/feedback.ts

import { Router } from "express";
import { createFeedback } from "../controllers/feedbackController";

const router = Router();
router.post("/", createFeedback);
export default router;

# FILE: backend/src/controllers/feedbackController.ts

import { Request, Response } from "express";
import prisma from "../utils/prismaClient";

export const createFeedback = async (req: Request, res: Response) => {
try {
const { userId, subject, message } = req.body;
const feedback = await prisma.feedback.create({ data: { userId, subject, message } });
res.status(201).json(feedback);
} catch (err) {
res.status(500).json({ error: "Failed to create feedback" });
}
};

For frontend tasks, example:

# FILE: frontend/src/components/FeedbackForm.tsx

import { useState } from "react";
import { TextField, Button } from "@mui/material";
import axios from "axios";

export default function FeedbackForm() {
const [subject, setSubject] = useState("");
const [message, setMessage] = useState("");
const handleSubmit = async () => {
await axios.post("/api/feedback", { subject, message });
setSubject(""); setMessage("");
};
return (

<form onSubmit={e => { e.preventDefault(); handleSubmit(); }}>
<TextField label="Subject" value={subject} onChange={e => setSubject(e.target.value)} fullWidth />
<TextField label="Message" value={message} onChange={e => setMessage(e.target.value)} fullWidth multiline />
<Button type="submit" variant="contained">Send</Button>
</form>
);
}

🧪 If Tests Are In Scope

# FILE: backend/tests/feedback.test.ts

import request from "supertest";
import app from "../src/index";

describe("POST /api/feedback", () => {
it("creates feedback", async () => {
const res = await request(app).post("/api/feedback").send({ subject: "Hi", message: "Test" });
expect(res.status).toBe(201);
});
});

🔒 If Settings / Env / Permissions Are In Scope

  • Show the exact diff within .env.template or config file:
# FILE: .env.template

DATABASE_URL="mysql://user:pass@db:3306/nowdatabase"
JWT_SECRET="replace_me"
  • Role permissions → define middleware checks or Prisma seeds for roles.

🧯 Non-Functional Requirements

  • Performance: Use pagination, indexes, and select fields to minimize payloads.
  • Security: Never log secrets; use HTTPS; sanitize user input.
  • Accessibility: Follow WCAG AA; test keyboard and screen reader flows.
  • i18n: Prepare text strings for translation if framework supports it.

🚫 Do Not

  • Include explanations or logs outside # FILE: blocks.
  • Change unrelated files.
  • Add new packages unless listed in packages.
  • Bypass lint / type rules or CI checks.
  • Add broad temporary Jest workarounds such as global module remaps, disabled caches, or wide transform exceptions unless you also verify they are truly necessary and safe for unrelated suites.
  • Silence hooks or async-handler lint errors by bypassing the rule instead of restructuring the code safely.

🧾 Final Checklist Before Return

  • All acceptance criteria met.
  • TypeScript compiles without errors.
  • Backend & frontend tests pass.
  • Frontend tests have the correct Provider/router/context wrappers, and async router actions are wrapped in act(...) where needed.
  • Jest/browser shims are minimal and compatible with Vite config, ESM dependencies, RTK Query, and asset imports used by the changed code.
  • Backend API tests use stable fixtures, deterministic generated-id handling, and mocked external integrations where applicable.
  • Backend write paths do not leak helper metadata into shared DB utilities.
  • Cypress support/spec changes use stable selectors, shared reset/login helpers, and deterministic intercepts where applicable.
  • Production, test, and test-support files all satisfy hooks rules, async-handler rules, strict TypeScript linting, and Prettier.
  • Prisma migrations exist if migrations:true.
  • Role-based permissions verified.
  • Docs and .env.template updated if required.
  • CI pipeline green after push or PR update.