# RoboTeam Landing Page

# Introduction

### **System Architecture**

The landing page consists of these parts:

- **Reverse Proxy (Nginx):**<span style="white-space:pre-wrap;"> Acts as the entry point. It handles SSL termination and routes traffic to the Vue.js static files or the Spring Boot API.</span>
- **Frontend (Vue.js):**<span style="white-space:pre-wrap;"> A Single Page Application (SPA) that handles the UI and user interactions.</span>
- **Backend (Spring Boot):**<span style="white-space:pre-wrap;"> The RESTful API that handles business logic, database transactions, and security checks.</span>
- **Database (PostgreSQL):**<span style="white-space:pre-wrap;"> Persistent storage for news, team members, and configuration.</span>
- **Containerization (Docker):**<span style="white-space:pre-wrap;"> Everything is wrapped in Docker containers</span>

Which is easier to understand with following diagram:  
[![image.png](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/scaled-1680-/xqMimage.png)](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/xqMimage.png)

### **Admin Dashboard**

Our system implements a two-tier auth system to log in.

1. **The Super User:**<span style="white-space:pre-wrap;"> One hard-coded or environment-variable-based account used for initial setup or emergency access.</span>
2. **Google OAuth 2.0:**
    - **The Whitelist:**<span style="white-space:pre-wrap;"> Access isn't open to any Google account. Only emails ending with </span>`<span class="editor-theme-code">@roboteamtwente.nl</span>`<span style="white-space:pre-wrap;"> are permitted.</span>
    - **Logic:**<span style="white-space:pre-wrap;"> When a user logs in, the backend checks if the returned Google email exists in the authorized list. If it’s not there, the Spring Boot Security filter returns a </span>`<span class="editor-theme-code">403 Forbidden</span>`.

\*Adding new users to authorized list: while everyone is technically allowed to login if they are have a @roboteamtwente.nl email, you still have to add them to website's whitelist. It is done in "User Managing" tab on admin's dashboard. It is possible to have a user listed, though deactivated, for book keeping reasons.  
[![image.png](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/scaled-1680-/eJ8image.png)](https://bookstack.roboteamtwente.nl/uploads/images/gallery/2026-04/eJ8image.png)

### **Admin Panel &amp; Content Management**

<span style="white-space:pre-wrap;">The website isn't just a static landing page; it’s a dynamic CMS. Almost all pages hold content that you are able to edit and manage through the admin panel. </span>

# Deployment

## 1. Docker Compose Services

<span style="white-space:pre-wrap;">Our </span>`<span class="editor-theme-code">docker-compose.yml</span>`<span style="white-space:pre-wrap;"> runs four key services</span>

<table id="bkmrk-serviceimage%2Fbuildro" style="margin-bottom:32px;"><colgroup><col></col><col></col><col></col></colgroup><tbody><tr><td style="border:1px solid;">**Service**

</td><td style="border:1px solid;">**Image/Build**

</td><td style="border:1px solid;">**Role**

</td></tr><tr><td style="border:1px solid;">`<span class="editor-theme-code">frontend</span>`

</td><td style="border:1px solid;">`<span class="editor-theme-code">./frontend/...</span>`

</td><td style="border:1px solid;"><span style="white-space:pre-wrap;">Nginx server; handles port 80 and proxies </span>`<span class="editor-theme-code">/api</span>`<span style="white-space:pre-wrap;"> to the backend.</span>

</td></tr><tr><td style="border:1px solid;">`<span class="editor-theme-code">backend</span>`

</td><td style="border:1px solid;">`<span class="editor-theme-code">./backend/...</span>`

</td><td style="border:1px solid;">The Spring Boot REST API.

</td></tr><tr><td style="border:1px solid;">`<span class="editor-theme-code">postgres</span>`

</td><td style="border:1px solid;">`<span class="editor-theme-code">postgres:15</span>`

</td><td style="border:1px solid;">Relational database.

</td></tr><tr><td style="border:1px solid;">`<span class="editor-theme-code">postgres-backup</span>`

</td><td style="border:1px solid;">`<span class="editor-theme-code">./db_backup</span>`

</td><td style="border:1px solid;">Custom service that runs automated DB dumps via crontab.

</td></tr></tbody></table>

## 2. Maintenance Commands

To help a new dev manage the site, here are the main commands:

- **Start everything:**<span style="white-space:pre-wrap;"> </span>`<span class="editor-theme-code">docker compose up -d</span>`
- **Stop everything:** `<span class="editor-theme-code">docker compose down</span>`<span style="white-space:pre-wrap;"> (you can add -v flag to delete all volumes)</span>
- **View Backend Logs:**<span style="white-space:pre-wrap;"> </span>`<span class="editor-theme-code">docker compose logs -f backend</span>`
- **Check Backups:**<span style="white-space:pre-wrap;"> Logs are stored in </span>`<span class="editor-theme-code">./db_backup/logs</span>`<span style="white-space:pre-wrap;"> and actual dumps are in </span>`<span class="editor-theme-code">./db_backup/backups</span>`.
- **Build**: When in frontend/ or backend/ route directories use:  
    `<span class="editor-theme-code">docker build . -t roboteamtwente/website-{name, e.g. "frontend"}:{version}</span>`
- **Pushing**: First login to RoboTeam docker account on your device. Then -&gt;  
    `<span class="editor-theme-code">docker push roboteamtwente/website-{name, e.g. "frontend"}:{version}</span>`

## 3. Deployment

When you are done developing, please consider building the images of services and push them.  
After that you are able to ssh into our VPS that hosts a lot of products (main landing page included).

```bash
ssh user@h2960363.stratoserver.net
```

You have to add your user to that VPS's whitelist beforehand in order to login.  
In there:

1. `<span class="editor-theme-code">sudo -i </span>`<span style="white-space:pre-wrap;"> to switch to superuser.</span>
2. `<span class="editor-theme-code">cd docker </span>`to the main directory where all containers are started from.
3. `<span class="editor-theme-code">vim docker-compose.yml </span>`<span style="white-space:pre-wrap;"> and edit the used version of desired service(s) to the newest one.</span>
4. `<span class="editor-theme-code">docker pull roboteamtwente/name:version </span>`<span style="white-space:pre-wrap;"> pull desired updated images</span>
5. `<span class="editor-theme-code">docker compose up -d nameOfTheContainer</span>`<span style="white-space:pre-wrap;"> start the container(s)</span>

# Frontend Architecture & API Integration

Here, the frontend of our web page is going to be discussed. Please get familiar with VUE.js documentation if you haven't done so yet:

[https://vuejs.org/guide/introduction](https://vuejs.org/guide/introduction)

A RESTful API guide could also be useful:  
[<span style="white-space:pre-wrap;">https://restfulapi.net/ </span>](https://restfulapi.net/%20)

<span style="white-space:pre-wrap;">Our frontend is a </span>**Single Page Application (SPA)**<span style="white-space:pre-wrap;"> built with </span>**Vue.js**. We use a modular structure where every page and component encapsulates its own HTML, CSS, and JavaScript logic.

## 1. Directory Structure &amp; Organization

We separate the code based on its “responsibility” in the app.

<table id="bkmrk-directorypurposesrc%2F" style="margin-bottom:32px;"><colgroup><col></col><col></col></colgroup><tbody><tr><td style="border:1px solid;">**Directory**

</td><td style="border:1px solid;">**Purpose**

</td></tr><tr><td style="border:1px solid;">**`<strong class="editor-theme-bold editor-theme-code">src/views/</strong>`**

</td><td style="border:1px solid;"><span style="white-space:pre-wrap;">The main page containers. These are “Smart” components that usually handle data fetching for a whole page (e.g., </span>`<span class="editor-theme-code">HomeView.vue</span>`).

</td></tr><tr><td style="border:1px solid;">**`<strong class="editor-theme-bold editor-theme-code">src/components/</strong>`**

</td><td style="border:1px solid;"><span style="white-space:pre-wrap;">Reusable UI sections. These are “Dumb” or “Presentational” components (e.g., </span>`<span class="editor-theme-code">HeroSection.vue</span>`<span style="white-space:pre-wrap;">, </span>`<span class="editor-theme-code">FooterSection.vue</span>`).

</td></tr><tr><td style="border:1px solid;">**`<strong class="editor-theme-bold editor-theme-code">src/components/admin/</strong>`**

</td><td style="border:1px solid;">Specialized management modules for the Admin Dashboard. These handle the CRUD logic for news, teams, and members.

</td></tr><tr><td style="border:1px solid;">**`<strong class="editor-theme-bold editor-theme-code">src/services/</strong>`**

</td><td style="border:1px solid;">The API layer. All communication with the Spring Boot backend happens here.

</td></tr><tr><td style="border:1px solid;">**`<strong class="editor-theme-bold editor-theme-code">src/router/</strong>`**

</td><td style="border:1px solid;">The navigation logic. Maps URLs to specific Views.

</td></tr></tbody></table>

## 2. Routing (Adding New Pages)

```js
// src/router/index.js
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: "/",
      name: "home",
      component: HomeView,
    },
    // Add new routes here
  ]
})
```

## 3. Communication with Backend (API Service)

<span style="white-space:pre-wrap;">We </span>**never**<span style="white-space:pre-wrap;"> make direct </span>`<span class="editor-theme-code">fetch</span>`<span style="white-space:pre-wrap;"> or </span>`<span class="editor-theme-code">axios</span>`<span style="white-space:pre-wrap;"> calls inside a </span>`<span class="editor-theme-code">.vue</span>`<span style="white-space:pre-wrap;"> component. Instead, we use a centralized service layer in </span>`<span class="editor-theme-code">src/services/api.js</span>`. This allows us to manage global headers, authentication tokens, and base URLs in one place.

### Step 1: Register the API Endpoint

```js
export const aboutUsAPI = {
  get: () => apiRequest("/organization"),
  update: (id, data) =>
    apiRequest(`/organization/${id}`, {
      method: "PUT",
      body: JSON.stringify(data),
    }),
};
```

### Step 2: Use the API in a Component

```js
import { aboutUsAPI } from '@/services/api';

const fetchOrganization = async () => {
  try {
    const data = await aboutUsAPI.get();
    // Do something with data...
  } catch (err) {
    console.error("API Error:", err);
  }
};
```

## 4. Admin Panel Architecture

<span style="white-space:pre-wrap;">The Admin Panel follows a “Manager” pattern. The </span>`<span class="editor-theme-code">AdminView.vue</span>`<span style="white-space:pre-wrap;"> acts as the main wrapper, while the actual editing tools are found in </span>`<span class="editor-theme-code">src/components/admin/</span>`.

**Managers:**<span style="white-space:pre-wrap;"> Components like </span>`<span class="editor-theme-code">NewsManager.vue</span>`<span style="white-space:pre-wrap;"> or </span>`<span class="editor-theme-code">EventsManager.vue</span>`<span style="white-space:pre-wrap;"> contain the forms and logic needed to edit content.</span>

**Data Flow:**<span style="white-space:pre-wrap;"> Typically, a Manager fetches data on mount, allows the user to edit it, and sends a </span>`<span class="editor-theme-code">PUT</span>`<span style="white-space:pre-wrap;"> or </span>`<span class="editor-theme-code">POST</span>`<span style="white-space:pre-wrap;"> request back through the </span>`<span class="editor-theme-code">services/api.js</span>`<span style="white-space:pre-wrap;"> layer.</span>

## <span style="background-color:rgb(224,62,45);">5. TODO: COOKIES, TOKEN BASED SESSIONS</span>

# Backend & Infrastructure

#####   


##### <span style="white-space:pre-wrap;">This page covers the core parts of the backend whicih works with </span>**Spring Boot.**

##### Consider taking a proper look at the SpringBoot's documentation. It is not hard, most of the backend code are basic spring boot elements and concepts

##### [https://docs.spring.io/spring-boot/index.html](https://docs.spring.io/spring-boot/index.html)

## 1. Technical Core

- **Language/Framework:**<span style="white-space:pre-wrap;"> Java 21 (Eclipse Temurin) using Spring Boot 3.4.0.</span>
- **Build System:**<span style="white-space:pre-wrap;"> Gradle. The project is built inside the container using </span>`<span class="editor-theme-code">./gradlew build</span>`.
- **API Port:**<span style="white-space:pre-wrap;"> The backend runs internally on port </span>`<span class="editor-theme-code">8081</span>`.

## 2. The Bootstrap Logic (Admin Seeder)

<span style="white-space:pre-wrap;">We have a custom safety mechanism called </span>`<span class="editor-theme-code">AdminUserSeeder.java</span>`.

- **The Purpose:**<span style="white-space:pre-wrap;"> If the database is fresh (0 users), the app will automatically create a "Super User."</span>
- **Requirement:**<span style="white-space:pre-wrap;"> You </span>**must**<span style="white-space:pre-wrap;"> provide </span>`<span class="editor-theme-code">ADMIN_USER</span>`<span style="white-space:pre-wrap;"> and </span>`<span class="editor-theme-code">ADMIN_PASS</span>`<span style="white-space:pre-wrap;"> environment variables in your </span>`<span class="editor-theme-code">.env</span>`<span style="white-space:pre-wrap;"> file for the first startup.</span>
- **Behavior:**<span style="white-space:pre-wrap;"> If an admin already exists in the </span>`<span class="editor-theme-code">admin_users</span>`<span style="white-space:pre-wrap;"> table, this seeder does nothing.</span>

## 3. Security &amp; Session Management

We use a hybrid security model to ensure the team can always access the dashboard.

- **Google OAuth 2.0:**<span style="white-space:pre-wrap;"> Primary login for team members. Emails must be whitelisted in the Google Cloud Console.</span>
- **Spring Session (JDBC):**<span style="white-space:pre-wrap;"> Unlike standard apps, we store sessions in the </span>**PostgreSQL database**<span style="white-space:pre-wrap;"> (table: </span>`<span class="editor-theme-code">SPRING_SESSION</span>`).
    - **Benefit:**<span style="white-space:pre-wrap;"> If the backend container restarts or updates, users are </span>**not**<span style="white-space:pre-wrap;"> logged out.</span>
- **Cookie Policy:**<span style="white-space:pre-wrap;"> </span>`<span class="editor-theme-code">SameSite=Lax</span>`<span style="white-space:pre-wrap;"> and </span>`<span class="editor-theme-code">HttpOnly</span>`<span style="white-space:pre-wrap;"> are enabled.</span>
    - **Note:**<span style="white-space:pre-wrap;"> In full production with HTTPS, </span>`<span class="editor-theme-code">server.servlet.session.cookie.secure</span>`<span style="white-space:pre-wrap;"> should be set to </span>`<span class="editor-theme-code">true</span>`.

## 4. Database &amp; Persistence

<span style="white-space:pre-wrap;">We use </span>**PostgreSQL 15**<span style="white-space:pre-wrap;"> as our source of truth.</span>

- **JPA/Hibernate:**<span style="white-space:pre-wrap;"> Configured with </span>`<span class="editor-theme-code">ddl-auto: update</span>`. This automatically creates tables based on Java Entities.
- **File Uploads:**<span style="white-space:pre-wrap;"> News images and team photos are stored in </span>`<span class="editor-theme-code">/app/uploads</span>`.
- **Volumes:**<span style="white-space:pre-wrap;"> To ensure data isn't lost when containers stop, we use two named volumes:</span>
    - `<span class="editor-theme-code">postgres_data</span>`: For all SQL records.
    - `<span class="editor-theme-code">uploads_data</span>`: For all physical images.