Skip to content

zonghangoh/grapevine

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hear through the Grapevine

Grapevine is a full-stack web application for managing audio files with user authentication. The system consists of a Node.js backend service and a React frontend application.

grape.mov

Running Instructions

  1. Copy and paste the provided ENV variables provided into the root directory's .env file
  2. Build and start the containers: docker-compose up --build
  3. The application will be available at:

System Components

1. Backend Service

  • Framework: Koa.js with TypeScript

  • Database: PostgreSQL with Sequelize ORM

  • Storage: AWS S3 for audio file storage

  • Authentication: JWT-based with HTTP-only cookies

2. Frontend Application

  • Framework: React with TypeScript

  • Build Tool: Vite

  • Styling: Tailwind CSS

  • Routing: React Router

3. Deployment

  • Containerized using Docker
  • Nginx serving the frontend static files
  • Environment configuration via .env files

Database Schema

Users Table

Column Type Constraints
id INTEGER PRIMARY KEY
username VARCHAR NOT NULL, UNIQUE
password VARCHAR NOT NULL
passwordVersion INTEGER DEFAULT 0
admin BOOLEAN DEFAULT false
createdAt TIMESTAMP NOT NULL
updatedAt TIMESTAMP NOT NULL

AudioFiles Table

Column Type Constraints
id INTEGER PRIMARY KEY
title VARCHAR NOT NULL
description TEXT NOT NULL
userId INTEGER REFERENCES Users(id)
fileUrl VARCHAR NOT NULL
metadata JSONB
createdAt TIMESTAMP NOT NULL
updatedAt TIMESTAMP NOT NULL

API Documentation

Error Handling

If an error occured, an error key will be present in the response body.

Authentication via cookies

All authenticated endpoints require a valid JWT token in the auth-token cookie. This cookie is automatically set after successful login and removed on logout. If admin updates user's password via the PUT /users/:id endpoint, existing JWT tokens for the user will become invalid and he/she will have to re-login to retrieve a new JWT token.

Authentication Endpoints

POST /auth/login

Login with username and password.

Request Body:

{
  "username": "string",
  "password": "string"
}

Response:

{
  "userId": "number",
  "admin": "boolean",
  "username": "string"
}

POST /auth/logout

Logout the current user.

GET /auth/verify

Verifies if the user and auth-token (in cookies) is still valid. A 401 error will be returned if verification fails.

Response:

{
  "userId": "number",
  "admin": "boolean",
  "username": "string"
}

Audio Files Endpoints

GET /audio_files

List audio files with pagination and filtering.

Query Parameters:

Parameter Type Default Description
page number 1 Page number for pagination
limit number 10 Number of items per page
search string Search term for filtering
tags string Comma-separated list of tags

Response:

{
  "audioFiles": [
    {
      "id": "number",
      "title": "string",
      "description": "string",
      "fileUrl": "string",
      "userId": "number",
      "metadata": {
        "key": "string",
        "tags": ["string"]
      },
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "pagination": {
    "currentPage": "number",
    "totalPages": "number",
    "totalItems": "number",
    "itemsPerPage": "number"
  }
}

POST /audio_files/presigned-url

Get a pre-signed URL for uploading an audio file.

Request Body:

{
  "fileName": "string", 
  "fileType": "string"
}

Response:

{
  "presignedUrl": "string", 
  "key": "string"
}

GET /audio_files/:id/presigned-url

Get a pre-signed URL for downloading/playing an audio file.

Response:

{
  "presignedUrl": "string"
}

POST /audio_files

Create a new audio file entry.

Request Body:

{
  "title": "string",
  "description": "string",
  "key": "string",
  "tags": ["string"]
}

PUT /audio_files/:id

Update audio file metadata.

Request Body:

{
  "title": "string",
  "description": "string",
  "tags": ["string"]
}

DELETE /audio_files/:id

Delete an audio file.

User Management Endpoints (Admin Only)

GET /users

List users with pagination.

Query Parameters:

Parameter Type Default Description
page number 1 Page number for pagination
limit number 9 Number of items per page

Response:

{
    "users": [
      {
        "id": "number",
        "username": "string",
        "admin": "boolean",
        "createdAt": "string",
        "updatedAt": "string"
      }
    ],
    "pagination": {
      "currentPage": "number",
      "totalPages": "number",
      "totalItems": "number",
      "itemsPerPage": "number"
    }
}

POST /users

Create a new user.

Request Body:

{
  "username": "string",
  "password": "string"
}

PUT /users/:id

Update user details. User with existing session will get logged out when password is changed.

Request Body:

{
  "username": "string",
  "password": "string"
}

DELETE /users/:id

Delete a user and associated files.

Security Features

  • JWT Authentication stored in HTTP-only cookies
  • Log user out if admin changed user's password during a session
  • Password hashing using bcrypt
  • Admin-only routes protection
  • User-specific file access control: users can only access their own files
  • Input validation using Joi
  • Secure file uploads using S3 presigned URLs

File Storage

Audio files are stored in AWS S3 with the following structure:

uploads/
  ├── {userId}/
  │   ├── {timestamp}-{filename}
  │   └── ...

About

low_crime != no_crime

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published