# 🧱 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 ```json { "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//` (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 `, 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 ``. 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: ` 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: (deleted)` with no code block. **Examples** ```markdown # 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: ```markdown # 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 (
{ e.preventDefault(); handleSubmit(); }}> setSubject(e.target.value)} fullWidth /> setMessage(e.target.value)} fullWidth multiline /> ); } ``` --- πŸ§ͺ **If Tests Are In Scope** ```markdown # 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: ```markdown # 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.