Skip to content

mxilia/Quonet-backend

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

63 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Quonet

A forum web application that allows users to create, delete, and like or dislike posts. Users can also update their profile information, including their username and bio. The platform supports content moderation through an admin dashboard.

Alt text

typescript Go AWS Redis PostgreSQL Supabase TailwindCSS Next.js

πŸ“ Repositories

πŸ“„ Summary

The frontend is built with Next.js following Bulletproof Architecture, leveraging server-side rendering for fast initial page loads, TanStack for client-side caching, and Zustand for centralized state management.

Backend is built with Go using Clean Architecture and implements a RESTful API with Fiber v2. PostgreSQL is used for data persistence via GORM, Redis handles rate limiting, and images are stored using Supabase.

πŸ’» Tech Stack

  • Frontend: Next.js, ShadCN, Tailwind CSS, Zod, TanStack, Zustand
  • Backend: Go, Fiber, GORM, PostgreSQL, Redis
  • Service: AWS, Supabase

πŸš€ Getting started

Prerequisites

  • Go 1.25.2
  • Docker
  • Docker Compose

Setting up

Run this to clone project:

git clone https://github.com/mxilia/Quonet-backend.git

After that make sure your current directory is at the root of this project.

cd Quonet-backend

Run this to download Go package:

go mod download

Environment Variables

Make sure you use .env.dev when development and .env.production in production. Here is the variable list example:

ENV={dev or production}
DOMAIN=localhost

DB_HOST=localhost
DB_PORT=5432
DB_NAME=db_name
DB_USER=db_user
DB_PASSWORD=db_password

OWNER_EMAIL=xyz@email.com
OWNER_HANDLER=owner_handler

JWT_SECRET=nono22

FRONTEND_URL=https://localhost:3000
FRONTEND_OAUTH_REDIRECT_URL=http://localhost:3000

GOOGLE_CLIENT_ID=4567.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=4567
GOOGLE_OAUTH_REDIRECT_URL=http://localhost:8000/auth/google/callback

SUPABASE_URL=
SUPABASE_KEY=
BUCKET_NAME=

REDIS_ADDR=http://localhost:0000
REDIS_PASSWORD=

Write your own values for corresponding variables.

Usage

To run this project, you need to first open Docker Desktop then after that run this in terminal:

docker compose up --build

Then after that run:

go run cmd/app/main.go

And there you go, the backend is up and running.

Note

πŸ“ /internal/app/server.go

6 | db, storage, _, rateLimiter, cfg, err := setupDependencies(CURRENT_ENV)

Make sure to replace CURRENT_ENV according to your environment:

  • Set CURRENT_ENV = "production" for a production environment.
  • Set CURRENT_ENV = "dev" for a development environment.

🧱 Project Structure

.
β”œβ”€β”€ .github
β”‚   └── workflows
β”‚       └── cicd.yml
β”œβ”€β”€ .vscode
β”‚   └── settings.json
β”œβ”€β”€ cmd
β”‚   └── app
β”‚       └── main.go
β”œβ”€β”€ internal
β”‚   β”œβ”€β”€ app
β”‚   β”‚   β”œβ”€β”€ app.go
β”‚   β”‚   └── server.go
β”‚   β”œβ”€β”€ announcement
β”‚   β”‚   β”œβ”€β”€ dto
β”‚   β”‚   β”‚   β”œβ”€β”€ mapper.go
β”‚   β”‚   β”‚   β”œβ”€β”€ request.go
β”‚   β”‚   β”‚   └── response.go
β”‚   β”‚   β”œβ”€β”€ handler
β”‚   β”‚   β”‚   └── rest
β”‚   β”‚   β”‚       └── handler.go
β”‚   β”‚   β”œβ”€β”€ repository
β”‚   β”‚   β”‚   β”œβ”€β”€ announcement_repository.go
β”‚   β”‚   β”‚   └── gorm_announcement_repository.go
β”‚   β”‚   └── usecase
β”‚   β”‚       β”œβ”€β”€ interface.go
β”‚   β”‚       └── usecase.go
β”‚   β”œβ”€β”€ comment
β”‚   β”‚   β”œβ”€β”€ dto
β”‚   β”‚   β”‚   β”œβ”€β”€ mapper.go
β”‚   β”‚   β”‚   β”œβ”€β”€ request.go
β”‚   β”‚   β”‚   └── response.go
β”‚   β”‚   β”œβ”€β”€ handler
β”‚   β”‚   β”‚   └── rest
β”‚   β”‚   β”‚       └── handler.go
β”‚   β”‚   β”œβ”€β”€ repository
β”‚   β”‚   β”‚   β”œβ”€β”€ comment_repository.go
β”‚   β”‚   β”‚   └── gorm_comment_repository.go
β”‚   β”‚   └── usecase
β”‚   β”‚       β”œβ”€β”€ interface.go
β”‚   β”‚       └── usecase.go
β”‚   β”œβ”€β”€ entities
β”‚   β”‚   β”œβ”€β”€ announcement.go
β”‚   β”‚   β”œβ”€β”€ comment.go
β”‚   β”‚   β”œβ”€β”€ like.go
β”‚   β”‚   β”œβ”€β”€ post.go
β”‚   β”‚   β”œβ”€β”€ session.go
β”‚   β”‚   β”œβ”€β”€ thread.go
β”‚   β”‚   └── user.go
β”‚   β”œβ”€β”€ like
β”‚   β”‚   β”œβ”€β”€ dto
β”‚   β”‚   β”‚   β”œβ”€β”€ mapper.go
β”‚   β”‚   β”‚   β”œβ”€β”€ request.go
β”‚   β”‚   β”‚   └── response.go
β”‚   β”‚   β”œβ”€β”€ handler
β”‚   β”‚   β”‚   └── rest
β”‚   β”‚   β”‚       └── handler.go
β”‚   β”‚   β”œβ”€β”€ repository
β”‚   β”‚   β”‚   β”œβ”€β”€ like_repository.go
β”‚   β”‚   β”‚   └── gorm_like_repository.go
β”‚   β”‚   └── usecase
β”‚   β”‚       β”œβ”€β”€ interface.go
β”‚   β”‚       └── usecase.go
β”‚   β”œβ”€β”€ post
β”‚   β”‚   β”œβ”€β”€ dto
β”‚   β”‚   β”‚   β”œβ”€β”€ mapper.go
β”‚   β”‚   β”‚   β”œβ”€β”€ request.go
β”‚   β”‚   β”‚   └── response.go
β”‚   β”‚   β”œβ”€β”€ handler
β”‚   β”‚   β”‚   └── rest
β”‚   β”‚   β”‚       └── handler.go
β”‚   β”‚   β”œβ”€β”€ repository
β”‚   β”‚   β”‚   β”œβ”€β”€ post_repository.go
β”‚   β”‚   β”‚   └── gorm_post_repository.go
β”‚   β”‚   └── usecase
β”‚   β”‚       β”œβ”€β”€ interface.go
β”‚   β”‚       └── usecase.go
β”‚   β”œβ”€β”€ session
β”‚   β”‚   β”œβ”€β”€ dto
β”‚   β”‚   β”‚   β”œβ”€β”€ mapper.go
β”‚   β”‚   β”‚   β”œβ”€β”€ request.go
β”‚   β”‚   β”‚   └── response.go
β”‚   β”‚   β”œβ”€β”€ handler
β”‚   β”‚   β”‚   └── rest
β”‚   β”‚   β”‚       └── handler.go
β”‚   β”‚   β”œβ”€β”€ repository
β”‚   β”‚   β”‚   β”œβ”€β”€ session_repostiory.go
β”‚   β”‚   β”‚   └── gorm_session_repository.go
β”‚   β”‚   └── usecase
β”‚   β”‚       β”œβ”€β”€ interface.go
β”‚   β”‚       └── usecase.go
β”‚   β”œβ”€β”€ thread
β”‚   β”‚   β”œβ”€β”€ dto
β”‚   β”‚   β”‚   β”œβ”€β”€ mapper.go
β”‚   β”‚   β”‚   β”œβ”€β”€ request.go
β”‚   β”‚   β”‚   └── response.go
β”‚   β”‚   β”œβ”€β”€ handler
β”‚   β”‚   β”‚   └── rest
β”‚   β”‚   β”‚       └── handler.go
β”‚   β”‚   β”œβ”€β”€ repository
β”‚   β”‚   β”‚   β”œβ”€β”€ thread_repository.go
β”‚   β”‚   β”‚   └── gorm_thread_repository.go
β”‚   β”‚   └── usecase
β”‚   β”‚       β”œβ”€β”€ interface.go
β”‚   β”‚       └── usecase.go
β”‚   β”œβ”€β”€ transaction
β”‚   β”‚   β”œβ”€β”€ interface.go
β”‚   β”‚   └── gorm_tx_manager.go
β”‚   └── user
β”‚       β”œβ”€β”€ dto
β”‚       β”‚   β”œβ”€β”€ mapper.go
β”‚       β”‚   β”œβ”€β”€ request.go
β”‚       β”‚   └── response.go
β”‚       β”œβ”€β”€ handler
β”‚       β”‚   └── rest
β”‚       β”‚       └── handler.go
β”‚       β”œβ”€β”€ repository
β”‚       β”‚   β”œβ”€β”€ user_repository.go
β”‚       β”‚   └── gorm_user_repository.go
β”‚       └── usecase
β”‚           β”œβ”€β”€ interface.go
β”‚           └── usecase.go
β”œβ”€β”€ pkg
β”‚   β”œβ”€β”€ apperror
β”‚   β”‚   └── apperror.go
β”‚   β”œβ”€β”€ config
β”‚   β”‚   └── config.go
β”‚   β”œβ”€β”€ database
β”‚   β”‚   β”œβ”€β”€ db.go
β”‚   β”‚   └── storage.go
β”‚   β”œβ”€β”€ middleware
β”‚   β”‚   β”œβ”€β”€ fiber.go
β”‚   β”‚   β”œβ”€β”€ jwt.go
β”‚   β”‚   β”œβ”€β”€ require_admin.go
β”‚   β”‚   └── rate_limit
β”‚   β”‚       β”œβ”€β”€ key.go
β”‚   β”‚       β”œβ”€β”€ policy.go
β”‚   β”‚       └── rate_limit.go
β”‚   β”œβ”€β”€ redisclient
β”‚   β”‚   β”œβ”€β”€ client.go
β”‚   β”‚   └── kv.go
β”‚   β”œβ”€β”€ responses
β”‚   β”‚   β”œβ”€β”€ error_response.go
β”‚   β”‚   └── message_response.go
β”‚   β”œβ”€β”€ routes
β”‚   β”‚   β”œβ”€β”€ not_found_route.go
β”‚   β”‚   β”œβ”€β”€ private_routes.go
β”‚   β”‚   └── public_routes.go
β”‚   └── token
β”‚       β”œβ”€β”€ claims.go
β”‚       └── jwt_maker.go
β”œβ”€β”€ utils
β”‚   └── format
β”‚        └── format.go
β”œβ”€β”€ .dockerignore
β”œβ”€β”€ .env.dev
β”œβ”€β”€ .env.example
β”œβ”€β”€ .env.production
β”œβ”€β”€ .gitignore
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ go.mod
β”œβ”€β”€ go.sum
β”œβ”€β”€ LICENSE
└── README.md

πŸ“ API Endpoints

/api/v2

Route Auth Requirement Params Description
GET /me Authenticated - Returns current user's info.
GET /auth/google/login Public - Redirects user to Google OAuth Page.
GET /auth/google/callback Public - Handles Google OAuth callback.
POST /auth/logout Authenticated - Delete current user's session.
GET /threads Public title, page Returns threads that match params.
GET /threads/:id Public id Returns a thread with specified id.
POST /threads Admin - Creates a new thread.
DELETE /threads/:id Admin - Delete a thread with specified id.
PATCH /sessions/:email Admin email Patch a session with specified id.
GET /users Public - Returns all users.
GET /users/:id Public id Returns a user with specified id.
GET /users/handler/:handler Public handler Returns a user with specified handler.
GET /users/email/:email Public email Returns a user with specified email.
PATCH /users/:id Authenticated - Update user with specified id.
DELETE /users/:id Authenticated - Delete user with specified id.
GET /posts Public page, author_id, thread_id, title Returns posts that match params.
GET /posts/:id Public id Returns a post with specified id.
GET /posts/top/like Public limit Returns a limited number of posts sorted by like count in descending order.
GET /posts/private Authenticated page, author_id, thread_id, title Returns private posts that match params.
GET /posts/private/:id Authenticated id Returns a private post with specified id.
POST /posts Authenticated - Creates a new post.
PATCH /posts/:id Authenticated id Update a post with specified id.
DELETE /posts/:id Authenticated id Delete a post with specified id.
GET /likes Public page, parent_type, owner_id, parent_id Returns likes that match params.
GET /likes/:id Public id Returns a like with specified id.
GET /likes/attributes/count Public parent_type, parent_id, owner_id Return a list of number representing entities' like count that match params.
GET /likes/attributes/state Authenticated parent_type, parent_id Return current user like state for the given parent.
POST /likes Authenticated - Create a new like.
GET /comments Public root_id, parent_id, owner_id Returns comments that match params.
GET /comments/:id Public id Returns a comment with specified id.
POST /comments Authenticated - Create a new comment.
PATCH /comments/:id Authenticated - Update a comment with specified id.
DELETE /comments/:id Authenticated - Delete a comment with specified id.
GET /announcements Public page Returns announcements that match params.
POST /announcements Admin - Create a new announcement.
DELETE /announcements Admin id Delete an announcement with specified id.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors