Skip to content

A modern platform for discovering, reviewing, and sharing movies with real-time Finnish theater data. Built with React, Node.js, and PostgreSQL

License

Notifications You must be signed in to change notification settings

andytrix/MovieApp-FullStack

Repository files navigation

Movie App | Full-Stack Movie Web App

A modern platform for discovering, reviewing, and sharing movies with real-time Finnish theater data. Built with React, Node.js, and PostgreSQL as part of a project at Oulu University of Applied Sciences (OAMK).

Movie App brings together social interaction and movie discovery in one responsive web experience. Users can create watch groups, share favorite lists, and exchange reviews - all in real time. The app is fully bilingual (English/Finnish), optimized for all devices, and integrates external APIs to deliver live theater showtimes and up-to-date movie data.

MovieApp

Contents

Features

  • Auth: JWT login/sign-up, password change, account deletion.
  • Search: Filters (genre, rating, year) + sorting; daily popular pick on Home.
  • Reviews: Write/edit reviews; public "Latest reviews" feed.
  • Groups: Create, join (request/approve), moderate; shared movie list + showtimes.
  • Favorites: Add/remove; share as public link (slug).
  • Realtime: SSE for group changes and shared lists.
  • Theaters (FI): Finnkino shows by theater/date; metro highlights on Home.
  • i18n: English and Finnish via i18next.
  • Responsive: Desktop, tablet, mobile.

Technology Stack

Frontend: React 19, Vite 7, Tailwind CSS 4, React Router 7, i18next, React Toastify
Backend: Node.js + Express 5 (SSE for live updates)
Database: PostgreSQL 14+ (pg)
Auth: JWT + bcrypt password hashing
APIs: TMDB (v3 endpoints, V4 Bearer auth), Finnkino XML API

Installation & Setup

Prerequisites

  • Node.js version 18 or higher
  • PostgreSQL version 14 or higher

1. Clone the repository

git clone https://github.com/andytrix/MovieApp-FullStack.git
cd MovieApp-FullStack

2. Database setup

Create a new local PostgreSQL database (you can name it freely, e.g., movieapp):

createdb movieapp

Load schema from the SQL file:

psql -U postgres -d movieapp -f backend/movieApp.sql

3. Backend setup (Node.js)

Navigate to the backend folder and install dependencies:

cd backend
npm install

Create a .env file inside the backend folder:

# backend/.env
PORT=3001
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=your_password
DB_NAME=movieapp
# Optional test database (used when NODE_ENV=test)
TEST_DB_NAME=movieapp_test

# JWT secret
JWT_SECRET=your_long_random_secret

# TMDB V4 Bearer token (required for TMDB requests)
# Get from https://developer.themoviedb.org/docs/authentication
TMDB_V4_TOKEN=your_tmdb_v4_bearer_token

Start the backend in development mode:

npm run devStart

The backend API should now be running at http://localhost:3001.


4. Frontend setup (React + Vite)

Open a new terminal window at the project root:

npm install

Create a .env file:

# .env
VITE_API_URL=http://localhost:3001
# No TMDB key needed in frontend (backend proxies TMDB)

Start the frontend:

npm run dev

Vite will display a local development URL, for example: http://localhost:5173.


5. Authentication & Authorization

  • Protected API routes require a valid JWT token in the Authorization header.
  • The frontend stores auth (user + token) in localStorage and attaches the token to API calls.

6. Testing mode (optional)

If you need a separate database for automated tests, create a new one (e.g., movieapp_test), set TEST_DB_NAME in backend/.env, and start the backend in test mode:

NODE_ENV=test npm run devStart

You can also run backend tests (Mocha/Chai) from backend/:

cd backend
npm test

Keep the backend running in test mode (NODE_ENV=test) while tests execute.


7. Common issues

  • CORS or Mixed Content Errors: Ensure VITE_API_URL in the frontend .env matches your backend address.
  • Database connection failed: Double-check PostgreSQL is running and credentials in backend/.env are correct.
  • TMDB errors (401/403): Make sure TMDB_V4_TOKEN is set in backend/.env and valid.
  • Frontend not updating: Restart both backend and frontend after any .env or schema changes.

After completing these steps, the full-stack application should be accessible locally with React (frontend) and Node.js (backend) connected to a PostgreSQL database.

How to run (dev)

Open two terminals and run:

# Terminal 1 – backend
cd backend
npm install
npm run devStart

# Terminal 2 – frontend (from project root)
npm install
npm run dev

Environment variables (quick ref)

  • backend/.env
    • PORT=3001
    • DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME
    • TEST_DB_NAME (optional, tests; used when NODE_ENV=test)
    • JWT_SECRET (required)
    • TMDB_V4_TOKEN (required; TMDB Bearer V4)
    • TMDB_BASE_URL (optional; defaults to https://api.themoviedb.org/3)
  • .env (frontend)

Directory Structure

MovieApp-FullStack/
├─ README.md                      # Project overview & setup
├─ package.json                   # Frontend deps & scripts
├─ vite.config.js                 # Vite config
├─ tailwind.config.js             # Tailwind config
├─ eslint.config.js               # ESLint rules
├─ index.html                     # Vite index template
├─ .env                           # Frontend env (VITE_API_URL)
├─ backend/                       # Express API & DB layer
│  ├─ package.json                # Backend deps (Express, pg)
│  ├─ index.js                    # Express app & routers
│  ├─ movieApp.sql                # PostgreSQL schema
│  ├─ .env                        # Backend env (DB, JWT, TMDB)
│  ├─ controllers/                # Route handlers
│  │  ├─ userController.js        # Auth, profile, password, delete
│  │  ├─ searchController.js      # TMDB search & genres
│  │  ├─ movieController.js       # Movie details, popular today
│  │  ├─ reviewController.js      # Reviews CRUD & latest
│  │  ├─ favoritesController.js   # Favorites + share (SSE)
│  │  └─ groupController.js       # Groups, members, movies, shows (SSE)
│  ├─ routes/                     # Express routers
│  │  ├─ userRouter.js            # /api/user
│  │  ├─ searchRouter.js          # /api/search
│  │  ├─ movieRouter.js           # /api/movies (+ /:id/reviews)
│  │  ├─ reviewRouter.js          # /api/movies/:id/reviews (auth)
│  │  ├─ reviewsPublicRouter.js   # /api/reviews/latest (public)
│  │  ├─ favoritesRouter.js       # /api/favorites (+ /share, /stream)
│  │  └─ groupRouter.js           # /api/groups (+ /stream)
│  ├─ models/                     # SQL helpers (pg)
│  │  ├─ userModel.js             # Users (bcrypt)
│  │  ├─ reviewModel.js           # Reviews CRUD & latest
│  │  ├─ favoritesModel.js        # Favorites + sharing
│  │  └─ groupModel.js            # Groups, members, movies, shows
│  ├─ helper/                     # Utilities & clients
│  │  ├─ db.js                    # pg Pool, env-based DB
│  │  ├─ auth.js                  # JWT middleware
│  │  ├─ tmdbClient.js            # TMDB client (V4)
│  │  └─ test.js                  # Test helpers
│  └─ test/                       # Mocha/Chai API tests
│     ├─ setup.test.js            # Test setup (DB, server)
│     ├─ auth.*.test.js           # Auth flows
│     ├─ user.deleteAccount.test.js   # Delete account
│     └─ reviews.browse.test.js       # Public latest reviews
├─ src/                           # React frontend (Vite)
│  ├─ main.jsx                    # App entrypoint (i18n init)
│  ├─ App.jsx                     # Routes & layout
│  ├─ i18n.js                     # i18next config (EN/FI)
│  ├─ assets/                     # Static assets (images)
│  ├─ components/                 # Reusable UI
│  │  ├─ Navbar.jsx               # Top navigation
│  │  ├─ Footer.jsx               # Footer links
│  │  ├─ FavoriteButton.jsx       # Add/remove favorites
│  │  ├─ MovieReviews.jsx         # Movie reviews (CRUD)
│  │  ├─ ProtectedRoute.jsx       # Auth-guard
│  │  └─ FancySelect.jsx          # Styled select
│  ├─ context/                    # Auth/user context
│  │  ├─ UserProvider.jsx         # Auth state & favorites
│  │  ├─ UserContext.js           # React context
│  │  └─ useUser.js               # User hook
│  ├─ layouts/                    # Page layouts
│  │  └─ AppLayout.jsx            # App shell
│  ├─ lib/                        # API clients & helpers
│  │  ├─ api.js                   # Fetch wrapper & auth
│  │  └─ api/                     # Domain clients
│  │     ├─ movies.js             # Movie API (TMDB)
│  │     ├─ search.js             # Search endpoints
│  │     ├─ reviews.js            # Reviews endpoints
│  │     └─ shows.js              # Finnkino (XML)
│  ├─ pages/                      # Route pages
│  │  ├─ Home.jsx                 # Daily pick, shows, latest reviews
│  │  ├─ Search.jsx               # Movie search (filters/sort)
│  │  ├─ MovieDetails.jsx         # Details, cast, recommendations
│  │  ├─ Reviews.jsx              # Public latest reviews
│  │  ├─ Favorites.jsx            # My favorites & shared (SSE)
│  │  ├─ SharedFavorites*.jsx     # Public shared favorites
│  │  ├─ Groups.jsx               # Group list (SSE)
│  │  ├─ GroupPage.jsx            # Group details, members, shows (SSE)
│  │  ├─ Theaters.jsx             # Finnkino theater/day
│  │  ├─ Authentication.jsx       # Sign up
│  │  ├─ Login.jsx                # Sign in
│  │  ├─ Account.jsx              # Profile & delete
│  │  ├─ ChangePassword.jsx       # Change password
│  │  └─ NotFound.jsx             # 404
│  └─ styles/                     # Tailwind & custom styles
│     └─ tailwind.css             # Tailwind layers
└─ documents/                     # Docs & assets

Database Architecture

Key entities (table names):

  • "user" — accounts (id UUID, email, password_hash, created_at)
  • "review" — movie reviews (id, movie_id BIGINT, user_id UUID, rating 1–5, text)
  • favorites — user favorite movies (id, user_id UUID, movie_id INT)
  • favorite_share — public share settings (user_id PK, display_name, slug UUID, is_shared)
  • "group" — watch groups (id BIGSERIAL, name, owner_id UUID)
  • group_membership — membership with status/role (id, group_id, user_id, status, role)
  • group_movie — movies in a group (id, group_id, movie_id BIGINT, title, added_by)
  • group_showtime — scheduled times (id, group_movie_id, starts_at, theater, auditorium)

Database Class Diagram

API endpoints

  • Auth / User

    • POST /api/user/signup — create account (email, password)
    • POST /api/user/signin — login, returns JWT
    • PATCH /api/user/me/password — change password (auth)
    • DELETE /api/user/me — delete my account (auth)
    • GET /api/user/profile — current user profile (auth)
  • Search / Movies (TMDB-backed)

    • GET /api/search/genres — movie genres (?language)
    • GET /api/search/movies — search (?q, page, language, minRating, genre, yearFrom, yearTo, sort)
    • GET /api/movies/popular/today — daily popular pick
    • GET /api/movies/:id — movie details (with extras)
  • Reviews

    • GET /api/reviews/latest — public latest reviews (page, limit)
    • GET /api/movies/:movieId/reviews — list reviews for movie (public)
    • POST /api/movies/:movieId/reviews — upsert my review (auth)
    • PATCH /api/movies/:movieId/reviews/:id — edit my review (auth)
    • DELETE /api/movies/:movieId/reviews/:id — delete my review (auth)
  • Favorites & Sharing

    • GET /api/favorites/:userId — my favorite movie ids
    • POST /api/favorites — add favorite ({ userId, movieId })
    • DELETE /api/favorites/:userId/:movieId — remove favorite
    • GET /api/favorites/shared — list public shares (public)
    • GET /api/favorites/share/me — my share status (auth)
    • POST /api/favorites/share — upsert share { is_shared, display_name } (auth)
    • GET /api/favorites/share/:slug — share metadata (public)
    • GET /api/favorites/share/:slug/movies — share movie ids (public)
    • GET /api/favorites/stream — SSE for share list changes (public)
  • Groups

    • GET /api/groups — list groups (public)
    • POST /api/groups — create group (auth)
    • GET /api/groups/stream — SSE for group list (auth via ?token)
    • GET /api/groups/:id — group details (public)
    • POST /api/groups/:id/join — request to join (auth)
    • GET /api/groups/:id/members — members (auth; if owner/approved)
    • PATCH /api/groups/:id/members/:userId — approve/reject (auth; owner/mod)
    • DELETE /api/groups/:id/members/me — leave (auth)
    • DELETE /api/groups/:id — delete group (auth; owner)
    • DELETE /api/groups/:id/members/:userId — remove member (auth; owner/mod)
    • GET /api/groups/:id/movies — list movies (auth; members/owner)
    • POST /api/groups/:id/movies — add movie (auth; members)
    • DELETE /api/groups/:id/movies/:gmId — remove movie (auth; added-by)
    • POST /api/groups/:id/movies/:gmId/showtimes — add showtime (auth; members)
    • DELETE /api/groups/:id/movies/:gmId/showtimes/:sid — remove showtime (auth; added-by)
    • GET /api/groups/:id/stream — SSE for group (auth via ?token)
    • GET /api/groups/:id/membership/me — my membership (auth)

About

A modern platform for discovering, reviewing, and sharing movies with real-time Finnish theater data. Built with React, Node.js, and PostgreSQL

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages