TaskTracker is a React + Vite task management app with authentication, protected routes, task and category screens, and an Axios-based API client. The frontend now talks to a real Express + MySQL backend through JWT-protected endpoints.
- React 19
- Vite
- Axios
- React Router DOM
- Zustand
- React Hook Form
- Zod
- Lucide React
- Tailwind CSS
- Express
- MySQL2
- JSON Web Tokens
- bcryptjs
- Install dependencies:
npm install- Configure environment variables:
Create a .env file in the project root and set the API base URL when your backend is not running on the default address:
VITE_API_URL=http://localhost:3000
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=rootadmin
DB_NAME=task_tracker
JWT_SECRET=tasktracker-dev-secretThe backend reads the database and JWT settings from the same .env file.
This project uses Sequelize migrations instead of sequelize.sync(), and the Express server serves the built React app from dist/.
Set these environment variables in Railway:
DATABASE_URLfor a single MySQL connection string, orMYSQLHOST,MYSQLPORT,MYSQLUSER,MYSQLPASSWORD, andMYSQLDATABASEJWT_SECRETVITE_API_URLonly if you split the frontend and backend onto different domains; for a single Railway service it can be left unset
Important: these database variables must be attached to the app service, not only the MySQL service.
Use these commands in Railway:
- Build command:
npm run build - Start command:
npm start
The start script runs scripts/railway-start.mjs, which checks for the production database variables, runs sequelize-cli db:migrate, and then launches the server. When dist/ exists, the server serves the React app at the same Railway URL as the API.
If Railway is still using an old start command in the dashboard, update it to npm start and redeploy.
- Start the app:
npm run devThis starts both the API server and the Vite client. Open the client URL shown in the terminal.
npm run dev- Start the API server and the Vite client together.npm run client- Start only the Vite development server.npm run server- Start only the API server.npm run build- Create a production build.npm run preview- Preview the production build locally.npm run lint- Run ESLint.
The frontend API client in src/lib/api.js uses these endpoints:
GET /api/health- Health check.POST /api/auth/register- Create a new account.POST /api/auth/login- Sign in and receive a JWT.
GET /api/auth/me- Return the currently authenticated user.GET /api/categories- List the current user's categories.POST /api/categories- Create a category.PUT /api/categories/:id- Update a category.DELETE /api/categories/:id- Delete a category.GET /api/tasks- List the current user's tasks.GET /api/tasks/:id- Fetch a single task with its related category.POST /api/tasks- Create a task.PUT /api/tasks/:id- Update a task.DELETE /api/tasks/:id- Delete a task.
GET /api/tasks supports:
statuscategory_idsearchpagelimit
- The backend auto-creates the database and tables if they do not exist, which is convenient for local development but may be too permissive for a locked-down production setup.
- The UI still uses a task status vocabulary of
todo,in-progress,hold,testing, anddone, so the backend stores those values to keep the current screens working. - The task model includes
prioritybecause the existing UI depends on it, even though the earlier database sketch did not include that field. - The client uses
http://localhost:3000only in development; in production it uses the same origin unlessVITE_API_URLis set.
The app focuses on:
- User registration and login with JWT authentication.
- Protected routes for authenticated users.
- Task browsing, creation, editing, and deletion.
- Category management.
- A responsive UI built with Tailwind CSS.