# How the Sub2API Frontend Is Structured: A Complete Vue 3 Architecture Guide

> Explore the modular Vue 3 architecture of the Sub2API frontend. Learn about its Vite setup, routing, Pinia stores, API wrapper, and reusable components within the Wei-Shaw/sub2api repo.

- Repository: [Wesley Liddick/sub2api](https://github.com/Wei-Shaw/sub2api)
- Tags: architecture
- Published: 2026-08-23

---

**TLDR: The Sub2API frontend is a modular Vue 3 single-page application built with Vite, organized into focused layers — routing, Pinia stores, a typed API wrapper, reusable components, composables, and utilities — all configured under a single `frontend/` directory in the Wei-Shaw/sub2api repository.**

The Sub2API frontend follows a clean, layered architecture that separates concerns across routing, state management, API communication, and UI components. This guide walks through each structural layer, references the exact source files, and shows how they fit together — giving you a practical map of the Vue 3 codebase as implemented in the `frontend/` directory of the Wei-Shaw/sub2api repository.

## Root Configuration and Build Setup

Every Vue 3 application starts with its build tooling, and Sub2API configures everything through standard Vite and TypeScript configuration files at the frontend's root.

The key files in this layer include [`vite.config.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/vite.config.ts) (build and dev server), [`tsconfig.json`](https://github.com/Wei-Shaw/sub2api/blob/main/tsconfig.json) (TypeScript checking), [`tailwind.config.js`](https://github.com/Wei-Shaw/sub2api/blob/main/tailwind.config.js) (utility-first styling), and [`vitest.config.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/vitest.config.ts) (unit testing). These four files define how the rest of the frontend compiles, styles, and validates code.

## The Application Entry Point: main.ts

Bootstrap logic lives in [`src/main.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/src/main.ts), where the Vue app is created, plugins are registered, and the root component is mounted. This is the exact bootstrap flow as implemented in the source:

```ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'

const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')

```

The app wires in **Pinia** for state management and the **Vue Router** for navigation before mounting the root component [`App.vue`](https://github.com/Wei-Shaw/sub2api/blob/main/App.vue).

## Root Component and Routing Layer

The [`src/App.vue`](https://github.com/Wei-Shaw/sub2api/blob/main/src/App.vue) file serves as the top-level layout, hosting the `<router-view>` outlet and global UI elements like toast notifications.

Routing is handled declaratively through several dedicated modules:

- [`src/router/index.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/src/router/index.ts) — route definitions with lazy-loaded pages
- [`src/router/meta.d.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/src/router/meta.d.ts) — route metadata type declarations
- [`src/router/title.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/src/router/title.ts) — dynamic document titles based on the active route
- [`src/router/setupRedirect.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/src/router/setupRedirect.ts) — post-login redirect handling

Route guards protect sensitive pages, while the title module keeps the browser tab in sync with the current view. This modular approach keeps navigation logic testable and easy to extend.

## State Management with Pinia Stores

All mutable application state in Sub2API lives in dedicated **Pinia stores** under `src/stores/`. Each domain gets its own store file:

- [`auth.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/auth.ts) — user authentication state and login/logout actions
- [`app.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/app.ts) — global app settings and UI state
- [`subscriptions.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/subscriptions.ts) — user subscription data
- [`payment.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/payment.ts) — payment and billing information
- [`adminSettings.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/adminSettings.ts) — administrator configurations

Here is how a component consumes a store via the Composition API, as seen in [`src/views/user/DashboardView.vue`](https://github.com/Wei-Shaw/sub2api/blob/main/src/views/user/DashboardView.vue):

```ts
<script setup lang="ts">
import { useSubscriptionsStore } from '@/stores/subscriptions'
const subsStore = useSubscriptionsStore()
await subsStore.fetchSubscriptions()
</script>

```

Storing all mutable state in Pinia keeps data predictable and makes the stores independently testable — the repository includes test specs alongside each store.

## Typed API Layer with Axios

The frontend communicates with the backend through a thin wrapper layer in `src/api/`. Each wrapper returns typed promises, so components never deal with raw request plumbing.

Key files include:

- [`api/client.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/api/client.ts) — the configured Axios instance with interceptors
- [`api/auth.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/api/auth.ts), [`api/groups.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/api/groups.ts), [`api/channels.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/api/channels.ts) — endpoint-specific wrappers
- [`api/adminUIRequest.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/api/adminUIRequest.ts) — admin UI backend interactions

A typical component call looks like this from [`src/components/user/profile/ProfileInfoCard.vue`](https://github.com/Wei-Shaw/sub2api/blob/main/src/components/user/profile/ProfileInfoCard.vue):

```ts
<script setup lang="ts">
import { api } from '@/api/client'
const { data, error } = await api.auth.getProfile()
</script>

```

Centralized error handling is implemented in [`src/utils/apiError.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/src/utils/apiError.ts), ensuring every failed request surfaces a consistent, user-friendly error.

## Views and Reusable Components

The UI is organized into two complementary directories.

### Views (Pages)

`src/views/` groups full pages by feature area: `user/` for the dashboard and profile, `setup/` for onboarding flows, and `public/` for public-facing routes. Each view file maps to one top-level router route, for example [`views/user/DashboardView.vue`](https://github.com/Wei-Shaw/sub2api/blob/main/views/user/DashboardView.vue).

### Reusable Components

`src/components/` contains small, focused building blocks segmented by domain:

- `common/` — shared UI like [`Toast.vue`](https://github.com/Wei-Shaw/sub2api/blob/main/Toast.vue) and [`LoadingSpinner.vue`](https://github.com/Wei-Shaw/sub2api/blob/main/LoadingSpinner.vue)
- `auth/` — login and registration widgets
- `user/profile/` — profile cards and settings
- `user/monitor/` — monitoring views
- `keys/` and `channels/` — feature-specific components
- `charts/` — data visualization components

This tiny component design promotes reuse and keeps each Vue file readable.

## Composables and Utilities

Business logic that spans multiple components is extracted into composables under `src/composables/`. Examples include `useTableLoader`, `useAutoRefresh`, and `useOpenAIOAuth`, enables components to pull in logic via Composition API composables.

```ts
<script setup lang="ts">
import { useAutoRefresh } from '@/composables/useAutoRefresh'
useAutoRefresh(30_000) // refresh every 30 seconds
</script>

```

Supporting utilities live in:

- `src/utils/` — helper functions like [`apiError.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/apiError.ts)
- `src/types/` — TypeScript type definitions
- `src/constants/` — platform constants and helpers ([`platforms.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/platforms.ts))
- `src/assets/` — static files such as logos and screenshots

## Styling and Theming

Global styling relies on **Tailwind CSS**, configured in [`tailwind.config.js`](https://github.com/Wei-Shaw/sub2api/blob/main/tailwind.config.js). The design system is enforced through utility components like [`PlatformIcon.vue`](https://github.com/Wei-Shaw/sub2api/blob/main/PlatformIcon.vue) and [`StatusBadge.vue`](https://github.com/Wei-Shaw/sub2api/blob/main/StatusBadge.vue), which apply consistent theming and patterns across all pages.

## Testing

Unit tests sit alongside the modules they cover using Vitest. Each Pinia store has a companion test file under `src/stores/__tests__/*.spec.ts`, and router logic is covered in `src/router/__tests__/*.spec.ts`, ensuring that state transitions and navigation guard behavior stay correct as the project grows.

## Summary

The Sub2API frontend is a well-organized Vue 3 application that separates concerns cleanly through a layered architecture:

- **Build tools** (Vite, TypeScript, Tailwind) are configured at the repo root under `frontend/`.
- **Routing** is declarative with multiple helper modules for metadata, titles, and redirects.
- **State** is isolated into dedicated Pinia stores per domain.
- **API communication** goes through a typed wrapper layer built on Axios.
- **UI components** are reusable and grouped by domain for easy maintenance.
- **Composables and utilities** keep business logic reusable throughout the app.

## Frequently Asked Questions

### What is the frontend stack of Sub2API?

The Sub2API frontend runs on **Vue 3** with **Vite** as the build tool, **TypeScript** for static typing, **Pinia** for state management, **Vue Router** for navigation, and **Tailwind CSS** for styling. Unit tests are written with Vitest.

### How does the Sub2API frontend handle API requests?

All HTTP communication goes through a centralized Axios client defined in [`src/api/client.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/src/api/client.ts), with interceptors for auth and error handling. Domain-specific modules like [`src/api/auth.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/src/api/auth.ts) and [`src/api/groups.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/src/api/groups.ts) wrap the endpoints and return typed promises so components can simply `await api.auth.login(...)` without request plumbing.

### Where does the Sub2API store user authentication state?

Auth state lives in the dedicated Pinia store at [`src/stores/auth.ts`](https://github.com/Wei-Shaw/sub2api/blob/main/src/stores/auth.ts). Components and router guards read and mutate authentication status exclusively through this store, which keeps auth logic predictable and testable.

### How are UI components organized in Sub2API?

Components under `src/components/` are divided by domain — `common/` for shared elements, `auth/` for login forms, `user/` for profile and monitoring, plus separate folders for keys, channels, and charts. This domain-based grouping allows developers to locate and reuse components quickly.