Skip to content

xNatthapol/TodoList

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 

Repository files navigation

TodoList Application

A full-stack Todo application built with Go (Fiber) for the backend and React (Vite) for the frontend. It features user authentication, CRUD operations for todo items, status updates, and image uploads associated with todos.

Features

  • User Authentication: Secure user sign-up and login functionality using JWT.
  • View Todo List: Displays all todo items belonging to the logged-in user, fetched from the database.
  • Add New Todo Items: Allows authenticated users to create new todo items with a title, description, and image.
  • Update Todo Status: Enables users to change the status of a todo item (Pending, In Progress, Done).
  • Edit Todo Items: Allows users to modify the title, description, and image of existing todos.
  • Delete Todo Items: Provides functionality to permanently remove todo items from the database.
  • Image Uploads: Users can upload an image associated with a todo item, stored securely in Google Cloud Storage.
  • Filtering: Users can filter the displayed todos by status (All, Pending, In Progress, Done, Hide Done).
  • API Documentation: Interactive API documentation is available via Swagger UI.

User Interface

SignUp Page

signup-app

Login Page

login-app

Todo List Page

todo-list-page

Add New Todo

add-todo

Edit Todo

edit-todo

Not Found Page

not-found-page

Tech Stack

  • Backend:
    • Language: Go (Golang)
    • Framework: Fiber
    • Database: PostgreSQL (via Docker Compose)
    • ORM: GORM
    • Authentication: JWT (JSON Web Tokens) using golang-jwt/jwt/v5
    • Configuration: Viper & GoDotEnv
    • Password Hashing: Bcrypt
    • Image Storage: Google Cloud Storage (GCS)
    • API Documentation: Swaggo (Swagger API Documentation)
    • Live Reloading (Dev): Air
  • Frontend:
    • Library/Framework: React
    • Build Tool: Vite
    • Routing: React Router DOM
    • HTTP Client: Axios
    • Styling: Tailwind CSS
    • State Management: React Context API (for Authentication)
  • Database Management:
    • PgAdmin (via Docker Compose)
  • Containerization:
    • Docker & Docker Compose (for Database & PgAdmin)

Project structure

TodoList/
├── backend/                      # Root directory for the Go backend application
│   ├── cmd/                      # Entry points for executable commands
│   │   └── main.go               # Main application entry point: initializes config, db, services, handlers, router, and starts the server.
│   ├── docs/                     # Directory containing auto-generated Swagger/OpenAPI documentation files
│   │   ├── docs.go               # Go file generated by Swaggo, contains Swagger spec info.
│   │   ├── swagger.json          # Swagger specification in JSON format.
│   │   └── swagger.yaml          # Swagger specification in YAML format.
│   ├── internal/                 # Private application code, not importable by other projects
│   │   ├── config/               # Configuration loading and management
│   │   │   └── config.go         # Loads config from .env/env vars using Viper, defines Config struct.
│   │   ├── database/             # Database connection and migration logic
│   │   │   └── database.go       # Establishes DB connection (PostgreSQL w/ GORM), runs auto-migrations.
│   │   ├── handlers/             # HTTP request handlers (Fiber framework specific)
│   │   │   ├── auth_handler.go   # Handlers for authentication routes (/signup, /login).
│   │   │   ├── todo_handler.go   # Handlers for CRUD operations on Todos.
│   │   │   ├── upload_handler.go # Handler for image uploads.
│   │   │   └── routes.go         # Defines API routes, groups them, applies middleware, sets up Swagger UI endpoint.
│   │   ├── middleware/           # HTTP middleware functions
│   │   │   └── auth_middleware.go # Middleware to protect routes by validating JWT tokens.
│   │   ├── models/               # Data structures, GORM models, request/response DTOs
│   │   │   ├── todo.go           # Todo model definition, status enum, and related request structs.
│   │   │   └── user.go           # User model definition.
│   │   ├── repositories/         # Data access layer (interacts directly with the database)
│   │   │   ├── todo_repository.go # Interface and implementation for Todo data operations using GORM.
│   │   │   └── user_repository.go # Interface and implementation for User data operations using GORM.
│   │   ├── services/             # Business logic layer
│   │   │   ├── auth_service.go   # Logic for user signup and login (hashing, JWT generation).
│   │   │   ├── todo_service.go   # Logic for managing Todos (CRUD operations, ownership checks).
│   │   │   └── upload_service.go # Logic for handling image uploads, interacts with GCS uploader.
│   │   └── utils/                # Utility functions (shared helpers)
│   │       ├── gcs_uploader.go   # Utility for interacting with Google Cloud Storage (upload, signed URLs).
│   │       ├── hash.go           # Utility for password hashing and comparison (bcrypt).
│   │       └── jwt.go            # Utility for generating and validating JWT tokens.
│   ├── keys/                     # Directory to store sensitive key files - **KEEP THIS OUT OF GIT**
│   │   └── gcs-service-account.json # Placeholder for your Google Cloud Storage service account key file.
│   ├── .env                      # Backend environment variables - **KEEP THIS OUT OF GIT**
│   ├── go.mod                    # Go module definition file.
│   └── go.sum                    # Go module checksum file.
│
├── frontend/                     # Root directory for the React frontend application
│   ├── public/                   # Static assets served directly by the web server
│   │   └── vite.svg              # Default Vite logo icon.
│   ├── src/                      # Main source code directory
│   │   ├── assets/               # Static assets imported into components
│   │   ├── components/           # Reusable UI components
│   │   │   ├── common/           # General-purpose components
│   │   │   │   └── Modal.jsx     # Reusable modal dialog component.
│   │   │   ├── layout/           # Components defining page structure
│   │   │   │   ├── Navbar.jsx    # Top navigation bar component.
│   │   │   │   └── ProtectedRoute.jsx # Wrapper component to guard routes requiring authentication.
│   │   │   └── todo/             # Components specific to the Todo feature
│   │   │       ├── AddTodoForm.jsx # Form for creating new Todo items (handles image upload).
│   │   │       ├── TodoItem.jsx  # Component to display a single Todo item.
│   │   │       └── TodoList.jsx  # Component to display a list of Todo items.
│   │   ├── contexts/             # React Context API providers
│   │   │   └── AuthContext.jsx   # Context for managing global authentication state (user, token).
│   │   ├── hooks/                # Custom React Hooks
│   │   │   └── useAuth.js        # Hook to easily access authentication context.
│   │   ├── pages/                # Page-level components
│   │   │   ├── LoginPage.jsx     # Login page component.
│   │   │   ├── NotFoundPage.jsx  # 404 Not Found page component.
│   │   │   ├── SignupPage.jsx    # Signup page component.
│   │   │   └── TodoPage.jsx      # Main page displaying the Todo list and handling interactions.
│   │   ├── services/             # Functions for interacting with the backend API
│   │   │   ├── authService.js    # API calls related to authentication (login, signup).
│   │   │   ├── todoService.js    # API calls related to Todos (CRUD operations).
│   │   │   └── uploadService.js  # API calls related to file uploads.
│   │   ├── App.css               # Component-specific or global CSS.
│   │   ├── App.jsx               # Root React component, sets up routing.
│   │   ├── index.css             # Global styles, Tailwind directives/imports.
│   │   └── main.jsx              # Entry point for the React application, renders App component.
│   ├── .env                      # Frontend environment variables - **KEEP THIS OUT OF GIT**
│   ├── .eslintrc.cjs             # ESLint configuration file.
│   ├── .gitignore                # Specifies intentionally untracked files that Git should ignore.
│   ├── index.html                # Main HTML file template used by Vite.
│   ├── package-lock.json         # Records exact versions of dependencies.
│   ├── package.json              # Project metadata and dependencies.
│   ├── README.md                 # Frontend specific README
│   └── vite.config.js            # Vite build tool configuration file.
│
├── .gitignore                    # Global gitignore for the entire project
├── docker-compose.yml            # Docker Compose configuration for running services (Postgres, pgAdmin).
└── README.md                     # Main project README file.

Architecture Overview

This application follows a standard three-tier architecture:

  1. Frontend (Client): The user interface built with React (Vite). It's responsible for presenting data to the user, capturing input, and communicating with the Backend API via HTTP requests (using Axios). It runs entirely in the user's web browser.
  2. Backend (Server): A RESTful API built with Go (Fiber). It acts as the intermediary between the frontend and the database. It handles incoming requests, enforces business logic (like checking user permissions), interacts with the database for data persistence, manages user authentication (using JWT), and handles tasks like image uploads to Google Cloud Storage.
  3. Database (Persistence): A PostgreSQL database, managed via Docker Compose in this setup. It stores all persistent application data, such as user accounts and their associated todo items.

This separation allows the frontend and backend to be developed, deployed, and scaled independently.

Backend Architecture (Go/Fiber)

The backend employs a layered architecture to promote separation of concerns, testability, and maintainability:

  • Handlers (internal/handlers): Receive HTTP requests from the Fiber router, parse request data (body, parameters, headers), perform initial input validation (using validator/v10), call the appropriate methods in the Services layer, and format/send HTTP responses (typically JSON). They also contain Swaggo annotations for generating API documentation.
  • Middleware (internal/middleware): Functions executed before requests reach the main handlers. Used for cross-cutting concerns like logging (logger), CORS handling (cors), and JWT authentication (Protected).
  • Services (internal/services): This layer contains the core business logic of the application. Services orchestrate operations, implement business rules (e.g., checking if a user owns a todo before allowing modification), interact with one or more Repositories to fetch or persist data, and handle interactions with external utilities (like generating JWTs or calling the GCS uploader via Utils).
  • Repositories (internal/repositories): This is the Data Access Layer (DAL). Repositories abstract the database interactions. They define interfaces for data operations (CRUD - Create, Read, Update, Delete) specific to each model (User, Todo). The implementations use the GORM library to translate these operations into SQL queries for the PostgreSQL database. This isolates the rest of the backend from the specific database technology.
  • Models (internal/models): Define the Go structs representing the application's data entities (User, Todo). These structs include GORM tags for database mapping (gorm:"...") and JSON tags (json:"...") for controlling API request/response serialization. Request-specific structures (like CreateTodoRequest) are also defined here.
  • Utils (internal/utils): Provide common, reusable helper functions and components, such as password hashing/checking (Bcrypt), JWT generation/validation (jwt.go), and the Google Cloud Storage uploader logic (gcs_uploader.go).
  • Config (internal/config): Responsible for loading and providing access to application configuration (database credentials, JWT secrets, server port, GCS details) using Viper, reading from .env files and environment variables.
  • Database (internal/database): Handles the initialization of the database connection using GORM and performs automatic database migrations based on the defined models.
  • cmd/main.go: The application's entry point. It initializes all components (config, DB, GCS uploader), creates instances of repositories, services, and handlers (dependency injection), sets up the Fiber application with necessary middleware, defines the API routes, and starts the HTTP server.

Backend Design Decisions:

  • Layered Architecture: Chosen for clear separation of responsibilities (presentation, business logic, data access), making the code easier to understand, test, and maintain.
  • Dependency Injection: Repositories and services are instantiated in main.go and passed down to where they are needed (handlers, other services), promoting loose coupling and testability.
  • Interfaces: Used for repositories and services (UserRepository, TodoService, etc.) to define contracts, allowing for easier testing (mocking) and potential future implementation swaps without affecting dependent layers.
  • GORM: Selected as the Object-Relational Mapper (ORM) for simplified database interactions (CRUD operations, querying) and schema management (auto-migration).
  • Fiber: Chosen as the web framework due to its high performance, low memory footprint, and suitable for building APIs efficiently.
  • JWT for Authentication: Standard and stateless mechanism for securing API endpoints, preventing the need for server-side sessions.
  • Viper & GoDotEnv: Provide flexible configuration management, allowing settings to be loaded from environment variables or .env files, suitable for different deployment environments.
  • Bcrypt: Used for securely hashing user passwords before storing them in the database.
  • Google Cloud Storage (GCS): Selected as a scalable, and reliable cloud storage solution for handling image uploads, separating file storage concerns from the main application server and database.
  • Swaggo: Integrated for automatic generation of interactive Swagger/OpenAPI documentation from code comments, improving API discoverability and usability.
  • Air (for Development): Used for live reloading during backend development, improving developer productivity by automatically rebuilding and restarting the server on code changes.

Frontend Architecture (React/Vite)

The frontend utilizes a component-based architecture, a standard practice in React development:

  • Components (src/components): Contains reusable UI elements organized by feature (todo) or type (common, layout). Examples include Modal, Navbar, TodoItem, AddTodoForm.
  • Pages (src/pages): Top-level components that represent distinct views or routes within the application (e.g., LoginPage, SignupPage, TodoPage). They typically fetch data required for the view (using services) and compose smaller, reusable components.
  • Services (src/services): Modules dedicated to communicating with the backend API. They use Axios to make HTTP requests and abstract away the details of API endpoints and data fetching, often handling error formatting.
  • Contexts (src/contexts): Leverages React's Context API for managing global state, specifically AuthContext for user authentication status, token, user details, and related functions (login, logout, signup).
  • Hooks (src/hooks): Custom React hooks (useAuth) provide convenient access to context or encapsulate other reusable logic.
  • Routing: Client-side routing is handled by react-router-dom, configured primarily in App.jsx to map URL paths to specific Page components. ProtectedRoute ensures only authenticated users can access certain routes.
  • Styling: Using Tailwind CSS.

Frontend Design Decisions:

  • React: A popular and powerful library for building declarative user interfaces with a strong component model.
  • Vite: Chosen for its extremely fast development server (leveraging native ES modules) and optimized production builds.
  • Component-Based Structure: Standard React practice promoting reusability and maintainability of UI code.
  • React Router DOM: Provides robust client-side routing capabilities, enabling a single-page application (SPA) experience.
  • Context API for Auth: A built-in React solution for managing global state, deemed sufficient for the authentication needs of this application without requiring a larger state management library like Redux or Zustand.
  • Axios: A widely-used and promise-based HTTP client for making requests to the backend API, offering features like request/response interception.
  • Tailwind CSS: A utility-first CSS framework enabling rapid UI development and consistent styling directly within the component markup.
  • Protected Routes: Implemented using a custom ProtectedRoute component that leverages the AuthContext to redirect unauthenticated users, securing application sections.

API Documentation

Once the backend server is running, interactive API documentation (generated by Swaggo) is available via Swagger UI at:

http://localhost:8080/swagger/index.html

This interface allows you to explore and interact with the backend API endpoints. Remember to authorize using the JWT token obtained after login (use the "Authorize" button and enter Bearer <your_token>).

Database Schema

  • Type: PostgreSQL
  • Schema Management: Handled by GORM's AutoMigrate feature based on the models defined in internal/models.
  • Tables:
    • users table: Stores user credentials and information.
      • id (uint, primary key, auto-increment)
      • created_at (timestamp with time zone)
      • updated_at (timestamp with time zone)
      • email (string, unique index, not null)
      • password (string, not null - stores bcrypt hash)
    • todos table: Stores todo item details and links them to users.
      • id (uint, primary key, auto-increment)
      • created_at (timestamp with time zone)
      • updated_at (timestamp with time zone)
      • title (string, not null)
      • description (string)
      • image_url (text - stores GCS URL if image uploaded)
      • status (varchar(20), default: 'Pending', not null, allowed: 'Pending', 'In Progress', 'Done')
      • user_id (uint, not null, foreign key references users(id))

Prerequisites

  • Go (version 1.18 or higher recommended)
  • Node.js (version 18 or higher recommended) and npm
  • Docker & Docker Compose
  • Google Cloud Storage (GCS) Bucket and Service Account Key for image uploads.
  • Air (for Go backend live reloading)

Installation Guide

  1. Clone the repository:

    git clone https://github.com/xNatthapol/TodoList.git

    Change directory to project directory

    cd TodoList
  2. Backend Setup:

    • Navigate to the backend directory:

      cd backend
    • Create Environment File (.env): Create a file named .env in the backend/ directory

      Or you can copy .env.example

      cp .env.example .env

      This file holds the configuration for the backend server and database connections. Populate it with the following variables, adjusting values as needed:

      # Server Configuration
      SERVER_PORT=8080
      
      # Database Configuration (for backend connection AND Docker)
      DB_HOST=localhost
      DB_PORT=5432
      DB_USER=your_postgres_user
      DB_PASSWORD=your_postgres_password # *** CHOOSE A STRONG PASSWORD ***
      DB_NAME=todo_db
      DB_SSLMODE=disable # Use 'require' or other modes if needed for production/cloud DBs
      TIME_ZONE=Asia/Bangkok      # Or your preferred timezone, e.g., UTC
      
      # PgAdmin Configuration (Used by Docker Compose)
      PGADMIN_DEFAULT_EMAIL=admin@example.com
      PGADMIN_DEFAULT_PASSWORD=your_pgadmin_password # *** CHOOSE A STRONG PASSWORD ***
      
      # JWT Configuration
      JWT_SECRET=your_very_strong_and_secret_jwt_key # *** IMPORTANT: CHANGE THIS FOR SECURITY! ***
      JWT_EXPIRES_IN_MINUTES=60m # e.g., 60m for 60 minutes
      
      # CORS Configuration
      CORS_ALLOWED_ORIGINS=http://localhost:5173 # Adjust for your frontend URL, use '*' for wide open development (less secure)
      
      # Google Cloud Storage Configuration (Optional - leave blank to disable image uploads)
      GCS_BUCKET_NAME=your_gcs_bucket_name
      GCS_SERVICE_ACCOUNT_KEY_PATH=./path/to/your/gcs-service-account-key.json # Relative path from backend directory or absolute path

      Important Notes:

      • JWT_SECRET: Replace the example value with a strong, unique secret. Do not commit your actual secret.
      • Passwords: Use strong, unique passwords for DB_PASSWORD and PGADMIN_DEFAULT_PASSWORD.
      • DB_HOST: Use db if you run the Go backend outside Docker but want it to connect to the PostgreSQL inside Docker. Use localhost if you plan to run PostgreSQL natively (not via the included Docker Compose).
      • GCS: Fill GCS_BUCKET_NAME and GCS_SERVICE_ACCOUNT_KEY_PATH to use the image upload feature. Ensure the key file exists at the specified path relative to the backend directory.
    • Install Go Dependencies:

      go mod download
    • Generate/Update API Documentation (Swaggo): Run this command whenever you change the API endpoint comments in your handlers or main file:

      swag init -g cmd/main.go

      This generates/updates the files in the backend/docs/ directory.

    • Run the Backend Server:

      • Option 1: Standard Run
        go run cmd/main.go
      • Option 2: Live Reloading with Air (Recommended for Development) Ensure you have air installed (go install github.com/cosmtrek/air@latest). Then run:
        air
        Air will watch your Go files and automatically rebuild and restart the server when changes are detected. Configuration for Air might be in an .air.toml file (if you have one).

      The backend server will start, typically listening on http://localhost:8080 (or the SERVER_PORT specified in .env).

  3. Database Setup (using Docker Compose):

    • Make sure you have Docker and Docker Compose installed.

    • Ensure the .env file created in the Backend Setup step exists in the backend/ directory, as Docker Compose will read database credentials from it.

    • Navigate back to the project root directory (e.g., TodoList-main).

    • Start the database and PgAdmin containers:

      docker-compose up -d

      This command builds and starts the PostgreSQL and PgAdmin services defined in docker-compose.yml in detached mode (-d).

      if you prefer to separate start only PostgreSQL database

      docker-compose up -d db

      Or Start only PgAdmin

      docker-compose up -d pgadmin

      if you want to stop you can do

      docker-compose stop

      Or compose down

      docker-compose down
      • PostgreSQL: Accessible on the host machine at the port specified by DB_PORT in .env (default: 5432). The Go backend (running either inside or outside Docker) will connect using the hostname db (as defined in docker-compose.yml and the default DB_HOST in .env).
      • PgAdmin: Accessible in your browser at http://localhost:5050. Log in using the PGADMIN_DEFAULT_EMAIL and PGADMIN_DEFAULT_PASSWORD from your .env file. You can then add a server connection within PgAdmin to manage the database:
        • Host name/address: db
        • Port: 5432
        • Maintenance database: todo_db (or your DB_NAME)
        • Username: postgres (or your DB_USER)
        • Password: Your DB_PASSWORD
  4. Frontend Setup:

    • Navigate to the frontend directory:

      cd frontend # Assuming you are in the project root

      (If you were in backend, use cd ../frontend)

    • Install Node.js Dependencies:

      npm install
    • Create Frontend Environment File (.env): Create a file named .env in the frontend/ directory. This tells the frontend where to find the backend API.

      Or you can copy .env.example

      cp .env.example .env
      # Frontend Environment Variables
      # Copy this file to .env and set the correct values
      
      # Base URL for Go backend API (including the /api path prefix)
      VITE_API_BASE_URL=http://localhost:8080/api

      Note: This URL is used by the Axios setup in src/services/ to make requests. Adjust the port if your backend runs elsewhere.

    • Run the Frontend Development Server:

      npm run dev

      The frontend development server will start, typically accessible at http://localhost:5173. Open this URL in your browser.

About

A Todo application with user authentication

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages