9 Technical Design Document
Martin Maikov edited this page 2026-09-24 10:31:43 +00:00
title
Technical Design Document

1. System overview

This document outlines the architecture and implementation blueprint for a full-stack Reddit clone called Discourse built by a team of three developers. The current implementation uses a component-based architecture with a Vue frontend, an Node.js API, and separate data services:

  • A Vue 3 frontend bundled with Vite.
  • A Node.js and Express backend providing the REST API.
  • PostgreSQL for relational post data.
  • Garage for S3-compatible object storage and uploaded images.

The frontend and backend are maintained as separate Git submodules inside a root infrastructure repository. The root repository owns the local integration environment, Docker Compose configuration, Garage configuration, and shared environment values. Repository setup and day-to-day development commands belong in the root (ref. Development workflow documentation).

The current system is a modular monolith rather than a microservice architecture. The backend owns API routing, validation, database access, health checks, upload URL generation, and storage setup. The frontend communicates with the backend over HTTP and uploads image content directly to object storage using a presigned URL.

2. System architecture

+----------------------+      REST API      +------------------------+       SQL       +-------------------+
| Vue 3 Client         | -----------------> | Node.js / Express API  | --------------> | PostgreSQL 18     |
| Vite development     |                    | Docker container       |                 | Relational data   |
+----------+-----------+                    +-----------+------------+                 +-------------------+
    |          ^                                        |
    |          | fetch images via Garage web endpoint   | S3 control API
    |          | (Direct GET)                           | sign/configure/check
    |          |                                        v
    |          |                              +------------------------+
    |          +----------------------------+ | Garage S3 storage      |
    |                                         | Images and web hosting |
    +---------------------------------------> +------------------------+
              direct PUT via presigned URL

Service topology

Service Container role Local host endpoint Internal service name
Frontend Vue/Vite development server http://localhost:5173 frontend:5173
Backend Express REST API and Swagger UI http://localhost:5000 backend:5000
PostgreSQL Relational database localhost:5432 db:5432
Garage S3 API S3-compatible object API localhost:3900 s3:3900
Garage web endpoint Public object hosting localhost:3902 s3:3902
Garage admin API Garage administration localhost:3903 s3:3903
Garage UI Storage administration UI http://localhost:8080 garage-ui:8080

Swagger UI and the OpenAPI JSON specification are served by the backend at /api-docs and /api-docs.json.

3. Component design & Tech stack

  • Frontend: Vue 3 bundled with Vite, with Vue Router for the post feed and post creation views. It communicates with the backend API and uploads images directly to Garage through presigned URLs.
  • Backend: Node.js runtime using Express.js for API routing, validation, post operations, health checks, image upload URL generation, and storage integration. Swagger UI and the generated OpenAPI specification are served by the backend.
  • Database: PostgreSQL stores posts, optional image keys, and aggregate like and dislike counters. Database schema changes are applied through node-pg-migrate.
  • Object storage: Garage provides S3-compatible storage for user-uploaded images. The backend manages storage configuration and presigned URLs, while the frontend sends image bytes directly to Garage.

4. API Specification Overview

The API is served by the backend on port 5000 in local development.

Method Endpoint Description Success Main errors
GET /api/health Check backend, PostgreSQL, and S3 availability. 200 when all dependencies are available. 503 when a dependency is unavailable.
GET /api/posts Return posts ordered by newest ID first. 200 with a JSON array. 500 for an unexpected server error.
POST /api/posts Create a post with a title, content, optional author, and optional image key. 201 with the created post. 400 for invalid title, content, or image key; 500 for server errors.
POST /api/posts/:id/like Increment the like counter for a post. 200 with the updated post. 400 for an invalid ID; 404 when the post does not exist; 500 for server errors.
POST /api/posts/:id/dislike Increment the dislike counter for a post. 200 with the updated post. 400 for an invalid ID; 404 when the post does not exist; 500 for server errors.
POST /api/uploads Generate a presigned Garage upload URL and a UUID object key. 200 with uploadUrl and fileKey. 500 for storage errors.
GET /api-docs Swagger UI endpoint. 200 with the documentation interface. -
GET /api-docs.json OpenAPI specification endpoint. 200 with an OpenAPI document. -

Post response shape example

{
  "id": 1,
  "author": "Anonymous",
  "title": "Example title",
  "content": "Example content",
  "imageUrl": "http://server.example:3902/discourse/object-key",
  "likeCount": 0,
  "dislikeCount": 0
}

Interactive API documentation

The Swagger UI at /api-docs lets developers browse endpoints, view request and response examples, and try requests interactively. The generated OpenAPI specification is available at /api-docs.json.

5. Database schema

Table posts

Column Type Constraints Description
id SERIAL PRIMARY KEY -
author TEXT DEFAULT 'Anonymous' Name of the author for the post
title VARCHAR(100) NOT NULL Title of the post
content TEXT NOT NULL Main body of the post
imageKey TEXT Nullable Image key in S3 bucket
like_count INTEGER NOT NULL, DEFAULT 0 Total number of likes received
dislike_count INTEGER NOT NULL, DEFAULT 0 Total number of dislikes received

6. Infrastructure

Versions of software used for the project:

  1. Node 26
  2. Express 5.2.1
  3. Postgres 18
  4. Garage
  5. node-postgres 8.23.0
  6. node-pg-migrate 9.0.0
  7. cors 2.8.6
  8. dotenv 17.4.2
  9. vue 3.5.41
  10. vue-router 5.3.1

Notable functions:

function runMigrations() in db.js

Runs migrations on the database.

async function loadPosts() in HomePage.vue

Loads posts onto the main page asyncronously