{"id":31693761,"url":"https://github.com/leventeback/sport-field-reservation-app","last_synced_at":"2026-04-02T01:02:33.228Z","repository":{"id":317551586,"uuid":"1061420845","full_name":"LeventeBack/sport-field-reservation-app","owner":"LeventeBack","description":"Full-stack sport field reservation platform built with React/TypeScript frontend, Node.js/Express backend, MySQL database with Sequelize ORM. Features JWT auth, role-based access, image uploads, and real-time booking system.","archived":false,"fork":false,"pushed_at":"2025-10-01T15:12:06.000Z","size":195,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-01T17:22:55.073Z","etag":null,"topics":["axios","bootstrap","express","image-upload","javascript","jwt","jwt-authentication","mysql","nodejs","react","react-hook-form","react-router","sequelize","typescript","vite","zod"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LeventeBack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-21T21:40:01.000Z","updated_at":"2025-10-01T15:14:13.000Z","dependencies_parsed_at":"2025-10-01T17:24:28.715Z","dependency_job_id":"ef5ef4fc-34b3-45e5-85ff-ee2afe5aa1ce","html_url":"https://github.com/LeventeBack/sport-field-reservation-app","commit_stats":null,"previous_names":["leventeback/sport-field-reservation-app"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/LeventeBack/sport-field-reservation-app","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeventeBack%2Fsport-field-reservation-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeventeBack%2Fsport-field-reservation-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeventeBack%2Fsport-field-reservation-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeventeBack%2Fsport-field-reservation-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LeventeBack","download_url":"https://codeload.github.com/LeventeBack/sport-field-reservation-app/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeventeBack%2Fsport-field-reservation-app/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278972328,"owners_count":26078017,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["axios","bootstrap","express","image-upload","javascript","jwt","jwt-authentication","mysql","nodejs","react","react-hook-form","react-router","sequelize","typescript","vite","zod"],"created_at":"2025-10-08T15:53:01.398Z","updated_at":"2025-10-08T15:53:07.246Z","avatar_url":"https://github.com/LeventeBack.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Sport Field Reservation App\n\n![Node.js](https://img.shields.io/badge/Node.js-18+-339933?logo=node.js\u0026logoColor=white)\n![Express](https://img.shields.io/badge/Express-4-black?logo=express\u0026logoColor=white)\n![Sequelize](https://img.shields.io/badge/Sequelize-6-52B0E7?logo=sequelize\u0026logoColor=white)\n![MySQL](https://img.shields.io/badge/MySQL-8-4479A1?logo=mysql\u0026logoColor=white)\n![JWT](https://img.shields.io/badge/JWT-Auth-000?logo=jsonwebtokens)\n![Passport](https://img.shields.io/badge/Passport-JWT-34E27A?logo=passport)\n![Multer](https://img.shields.io/badge/Multer-uploads-2B2E3A)\n\n![React](https://img.shields.io/badge/React-18-61DAFB?logo=react\u0026logoColor=000)\n![Vite](https://img.shields.io/badge/Vite-5-646CFF?logo=vite\u0026logoColor=white)\n![TypeScript](https://img.shields.io/badge/TypeScript-5-3178C6?logo=typescript\u0026logoColor=white)\n![React Router](https://img.shields.io/badge/React%20Router-6-CA4245?logo=react-router)\n![Axios](https://img.shields.io/badge/Axios-HTTP-5A29E4)\n![Bootstrap](https://img.shields.io/badge/Bootstrap-5-7952B3?logo=bootstrap\u0026logoColor=white)\n![Zod](https://img.shields.io/badge/Zod-Validation-3068B7)\n![React Hook Form](https://img.shields.io/badge/React%20Hook%20Form-7-EC5990)\n\nA full‑stack web application to browse sport fields, manage images, and create reservations. Features admin management for field types/fields/images and JWT‑based authentication, with a React + Vite frontend communicating with an Express backend over REST.\n\n---\n\n## Table of Contents\n\n- [Features](#features)\n- [Tech Stack](#tech-stack)\n- [Architecture \u0026 Communication](#architecture--communication)\n- [Project Structure](#project-structure)\n- [Quickstart](#quickstart)\n  - [Backend Setup](#backend-setup)\n  - [Frontend Setup](#frontend-setup)\n- [Environment Variables](#environment-variables)\n- [API Overview](#api-overview)\n- [Scripts](#scripts)\n\n## Features\n\n- **Authentication**: Register, login, token validation (`/auth/*`) using JWT stored client‑side; `withCredentials` for cookie support if needed.\n- **Admin Management**: Create/update/delete field types, sport fields, and images (protected by auth + admin role).\n- **Reservations**: Create, update, delete reservations (user auth), list all (public).\n- **Users**: Admin/user endpoints to manage user profiles.\n- **Media**: Image upload via `multer`, served as static files from `backend/uploads`.\n- **Validation**: Request validation via `express-validator` schemas.\n- **DX**: ESLint + Prettier, nodemon in dev; TypeScript + Vite on frontend.\n\n## Tech Stack\n\n- **Backend**: Node.js, Express, Sequelize (MySQL), Passport JWT, express‑validator, Multer, CORS, Morgan\n- **Frontend**: React 18, TypeScript, Vite, Axios, React Router, React Hook Form + Zod, Bootstrap/React‑Bootstrap, Lightbox/Photo album\n- **Auth**: JWT (Authorization: `Bearer \u003ctoken\u003e`), optional cookies via `cookie-parser`\n- **Database**: MySQL 8\n\n## Architecture \u0026 Communication\n\n- **Communication**: REST over HTTP. The frontend Axios client uses `BASE_URL = BACKEND_API_URL` and prefixes endpoints with `/api/*` (e.g., `/api/sport-fields`).\n  - Backend CORS origin defaults to `http://localhost:5173` and enables `credentials: true`.\n  - Requests include `Authorization: Bearer \u003ctoken\u003e` header when a token exists in `localStorage`.\n- **Static Files**: Images are served from `backend/uploads` via Express static middleware.\n\n## Project Structure\n\n```text\n  backend/\n    config/            # env, enums, forms, texts\n    controllers/       # route controllers (auth, users, fields, reservations, images)\n    db/                # Sequelize setup and models\n    middlewares/       # auth (jwt/admin), validators, upload\n    routes/            # /auth and /api/* routers\n    uploads/           # uploaded images (served statically)\n    index.js           # Express app entry\n  frontend/\n    src/\n      components/      # UI components\n      pages/           # route pages\n      services/        # Axios services (http, entities, auth)\n      config/env.ts    # BACKEND_API_URL, IMAGE_BASE_URL\n      hooks/, contexts/, providers/\n    vite.config.ts\n    index.html\n  README.md\n```\n\n## Quickstart\n\n### Backend Setup\n\n1. Create a MySQL database and user.\n2. Create `.env` in `backend/`:\n   ```env\n   DB_USER=your_user\n   DB_PASSWORD=your_password\n   DB_NAME=db_name\n   DB_HOST=127.0.0.1\n   JWT_SECRET=replace_with_strong_secret\n   PORT=8080\n   ```\n3. Install deps and run:\n   ```bash\n   cd backend\n   npm install\n   npm run dev\n   # Server: http://localhost:8080\n   ```\n\n### Frontend Setup\n\n1. Configure `frontend/src/config/env.ts` if needed:\n   ```ts\n   export const BACKEND_API_URL = \"http://localhost:8080\";\n   export const IMAGE_BASE_URL = \"http://localhost:8080\";\n   ```\n2. Install deps and run:\n   ```bash\n   cd frontend\n   npm install\n   npm run dev\n   # App: http://localhost:5173\n   ```\n\n## Environment Variables\n\n- Backend (`backend/.env`): `DB_USER`, `DB_PASSWORD`, `DB_NAME`, `DB_HOST`, `JWT_SECRET`, `PORT`\n- Frontend (`env.ts`): `BACKEND_API_URL`, `IMAGE_BASE_URL`\n\n## API Overview\n\n- `GET /auth/validate` — validate token\n- `POST /auth/login` — login\n- `POST /auth/register` — register\n\n- `GET /api/field-types` — list field types\n- `POST /api/field-types` — create (auth + admin)\n- `PUT /api/field-types/:id` — update (auth + admin)\n- `DELETE /api/field-types/:id` — delete (auth + admin)\n\n- `GET /api/sport-fields` — list fields\n- `GET /api/sport-fields/:id` — get field\n- `POST /api/sport-fields` — create (auth + admin)\n- `PUT /api/sport-fields/:id` — update (auth + admin)\n- `DELETE /api/sport-fields/:id` — delete (auth + admin)\n\n- `POST /api/sport-field-images` — upload image (auth + admin, multipart `image`)\n- `PUT /api/sport-field-images/:id` — update (auth + admin)\n- `DELETE /api/sport-field-images/:id` — delete (auth + admin)\n\n- `GET /api/reservations` — list\n- `POST /api/reservations` — create (auth)\n- `PUT /api/reservations/:id` — update (auth + admin)\n- `DELETE /api/reservations/:id` — delete (auth)\n\n- `GET /api/users` — list (auth + admin)\n- `GET /api/users/:id` — get (auth)\n- `PUT /api/users/:id` — update (auth)\n- `DELETE /api/users/:id` — delete (auth + admin)\n\n## Scripts\n\n- Backend:\n  - `npm run dev` — start with nodemon\n  - `npm start` — start server\n  - `npm run lint` — lint backend code\n- Frontend:\n  - `npm run dev` — Vite dev server\n  - `npm run build` — TypeScript check + build\n  - `npm run preview` — preview build\n  - `npm run lint` — lint frontend code\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleventeback%2Fsport-field-reservation-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleventeback%2Fsport-field-reservation-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleventeback%2Fsport-field-reservation-app/lists"}