Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions .github/workflows/frontend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,20 @@ jobs:
steps:
- uses: actions/checkout@v5

- name: Setup yarn
- name: Enable Corepack
run: corepack enable

- name: Setup pnpm
uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'yarn'
cache-dependency-path: frontend/yarn.lock
cache: 'pnpm'
cache-dependency-path: frontend/pnpm-lock.yaml

- name: Install npm modules
run: yarn
run: pnpm i
working-directory: frontend

- name: Run prettier, lint, jest checks
run: yarn test
run: pnpm test
working-directory: frontend
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ uv.lock
.mypy_cache
.dmypy.json
.pytest_cache
.yarn

*.env
!ci.env
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
<h1></h1>

Tournament system meant to be easy to use. Bracket is written in async Python (with
[FastAPI](https://fastapi.tiangolo.com)) and [Next.js](https://nextjs.org/) as frontend using the
[FastAPI](https://fastapi.tiangolo.com)) and [Vite](https://vite.dev/) as frontend using the
[Mantine](https://mantine.dev/) library.

It has the following features:
Expand Down Expand Up @@ -104,17 +104,17 @@ Read the [configuration docs](https://docs.bracketapp.nl/docs/running-bracket/co
Bracket's backend is configured using `.env` files (`prod.env` for production, `dev.env` for development etc.).
But you can also configure Bracket using environment variables directly, for example by specifying them in the `docker-compose.yml`.

The frontend doesn't can be configured by environment variables as well, as well as `.env` files using Next.js' way of loading environment variables.
The frontend doesn't can be configured by environment variables as well, as well as `.env` files using Vite's way of loading environment variables.

# Running Bracket in production
Read the [deployment docs](https://docs.bracketapp.nl/docs/deployment) for how to deploy Bracket and run it in production.

Bracket can be run in Docker or by itself (using `uv` and `yarn`).
Bracket can be run in Docker or by itself (using `uv` and `pnpm`).

# Development setup
Read the [development docs](https://docs.bracketapp.nl/docs/community/development) for how to run Bracket for development.

Prerequisites are `yarn`, `postgresql` and `uv` to run the frontend, database and backend.
Prerequisites are `pnpm`, `postgresql` and `uv` to run the frontend, database and backend.

# Translations
Based on your browser settings, your language should be automatically detected and loaded. For now,
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ services:
bracket-frontend:
container_name: bracket-frontend
environment:
NEXT_PUBLIC_API_BASE_URL: http://localhost:8400
NEXT_PUBLIC_HCAPTCHA_SITE_KEY: 10000000-ffff-ffff-ffff-000000000001
VITE_API_BASE_URL: http://localhost:8400
VITE_HCAPTCHA_SITE_KEY: 10000000-ffff-ffff-ffff-000000000001
image: ghcr.io/evroon/bracket-frontend
ports:
- 3000:3000
Expand Down
2 changes: 1 addition & 1 deletion docs/content/community/development.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ two sections.

```bash
cd frontend
yarn run dev
pnpm run dev
```

### Backend
Expand Down
8 changes: 4 additions & 4 deletions docs/content/deployment/docker.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ services:
- "3000:3000"
environment:
NODE_ENV: "production"
NEXT_PUBLIC_API_BASE_URL: "http://your-site.com:8400"
NEXT_PUBLIC_HCAPTCHA_SITE_KEY: "10000000-ffff-ffff-ffff-000000000001"
VITE_API_BASE_URL: "http://your-site.com:8400"
VITE_HCAPTCHA_SITE_KEY: "10000000-ffff-ffff-ffff-000000000001"
restart: unless-stopped

bracket-backend:
Expand Down Expand Up @@ -63,9 +63,9 @@ Replace the lines that are highlighted in the code block from the previous step.

Replace the following values for `bracket-frontend`:

- `NEXT_PUBLIC_API_BASE_URL`: The address of your backend. The frontend will send
- `VITE_API_BASE_URL`: The address of your backend. The frontend will send
requests to this address.
- `NEXT_PUBLIC_HCAPTCHA_SITE_KEY`: Either leave empty to disable it or
- `VITE_HCAPTCHA_SITE_KEY`: Either leave empty to disable it or
[signup for hCaptcha](https://dashboard.hcaptcha.com/signup), create a site and
put the site key here

Expand Down
4 changes: 2 additions & 2 deletions docs/content/deployment/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ See [the config docs](/docs/running-bracket/configuration.mdx) for more informat

The following configuration variables need to be adjusted for the frontend to run it in production:

- `NEXT_PUBLIC_API_BASE_URL`: The base URL of the backend API to which the frontend sends requests.
- `VITE_API_BASE_URL`: The base URL of the backend API to which the frontend sends requests.
For example: `https://api.bracket.com`

Optional:

- `NEXT_PUBLIC_HCAPTCHA_SITE_KEY`: The HCaptcha key used for captcha challenges when creating new
- `VITE_HCAPTCHA_SITE_KEY`: The HCaptcha key used for captcha challenges when creating new
accounts. You get the secret when you create a new site in HCaptcha. If left blank, HCaptcha will
be disabled for your site.

Expand Down
6 changes: 3 additions & 3 deletions docs/content/deployment/nomad.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,15 @@ job "bracket-frontend" {
driver = "docker"

env {
NEXT_PUBLIC_API_BASE_URL = "https://my.bracketdomain.com"
NEXT_PUBLIC_HCAPTCHA_SITE_KEY = "xxxxx"
VITE_API_BASE_URL = "https://my.bracketdomain.com"
VITE_HCAPTCHA_SITE_KEY = "xxxxx"
NODE_ENV = "production"
}

config {
image = "ghcr.io/evroon/bracket-frontend"
ports = ["nextjs"]
args = ["yarn", "start", "-p", "${NOMAD_PORT_nextjs}"]
args = ["pnpm", "start", "-p", "${NOMAD_PORT_nextjs}"]
}

resources {
Expand Down
2 changes: 1 addition & 1 deletion docs/content/deployment/systemd.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ After=network.target
Type=simple
User=bracket
WorkingDirectory=/var/lib/bracket/frontend
ExecStart=/usr/local/bin/yarn start
ExecStart=/usr/local/bin/pnpm start
Environment=NODE_ENV=production
TimeoutSec=15
Restart=always
Expand Down
4 changes: 2 additions & 2 deletions docs/content/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ title: Introduction

[Bracket](https://github.com/evroon/bracket) is a tournament system meant to be easy to use. Bracket
is written in async Python (with [FastAPI](https://fastapi.tiangolo.com)) and
[Next.js](https://nextjs.org/) as frontend using the [Mantine](https://mantine.dev/) library.
[Vite](https://vite.dev/) as frontend using the [Mantine](https://mantine.dev/) library.

## Overview of features

Expand Down Expand Up @@ -36,7 +36,7 @@ tournament systems that exist usually only support Swiss, no other types of tour
(round-robin, elimination etc.). That is quite a limitation when you want to host a tournament that
starts with Swiss and determines a winner based on a knockoff (elimination) stage.

**Finally**, I developed this project to learn more about Next.js and apply my Python (e.g. FastAPI)
**Finally**, I developed this project to learn more about Vite and apply my Python (e.g. FastAPI)
experience to a project with a real purpose.

## Quickstart
Expand Down
24 changes: 12 additions & 12 deletions docs/content/running-bracket/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -44,28 +44,28 @@ AUTO_RUN_MIGRATIONS=true

## Frontend

- `NEXT_PUBLIC_HCAPTCHA_SITE_KEY`: The HCaptcha key used for captcha challenges when creating new
- `VITE_HCAPTCHA_SITE_KEY`: The HCaptcha key used for captcha challenges when creating new
accounts. You get the secret when you create a new site in HCaptcha.
- `NEXT_PUBLIC_API_BASE_URL`: The base URL of the backend API to which the frontend sends requests.
- `VITE_API_BASE_URL`: The base URL of the backend API to which the frontend sends requests.
For example: `https://api.bracket.com`
- `ANALYTICS_DATA_DOMAIN`: The `data-domain` attribute passed to the script for Plausible
- `VITE_ANALYTICS_DATA_DOMAIN`: The `data-domain` attribute passed to the script for Plausible
analytics
- `ANALYTICS_DATA_WEBSITE_ID`: The `data-website-id` attribute passed to the script for Umami
- `VITE_ANALYTICS_DATA_WEBSITE_ID`: The `data-website-id` attribute passed to the script for Umami
analytics
- `ANALYTICS_SCRIPT_SRC`: The URL to the script for analytics purposes.
- `VITE_ANALYTICS_SCRIPT_SRC`: The URL to the script for analytics purposes.

### Frontend: Example configuration file

You can store the config in `.env.local` (as described in the [Next docs][next-config-url]).
You can store the config in `.env.local` (as described in the [Vite docs][vite-config-url]).

This is an example of how the config file should look like:

```shell
NEXT_PUBLIC_HCAPTCHA_SITE_KEY='10000000-ffff-ffff-ffff-000000000001'
NEXT_PUBLIC_API_BASE_URL='https://api.bracket.com'
ANALYTICS_SCRIPT_SRC='https://analytics.bracket.com/script.js'
ANALYTICS_DATA_DOMAIN='bracket.com'
ANALYTICS_DATA_WEBSITE_ID='bracket.com'
VITE_HCAPTCHA_SITE_KEY='10000000-ffff-ffff-ffff-000000000001'
VITE_API_BASE_URL='https://api.bracket.com'
VITE_ANALYTICS_SCRIPT_SRC='https://analytics.bracket.com/script.js'
VITE_ANALYTICS_DATA_DOMAIN='bracket.com'
VITE_ANALYTICS_DATA_WEBSITE_ID='bracket.com'
```

[next-config-url]: https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables#loading-environment-variables
[vite-config-url]: https://vite.dev/guide/env-and-mode
2 changes: 1 addition & 1 deletion docs/content/running-bracket/faq.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ title: FAQ
This is likely because you are trying to access Bracket on a different address than
`http://localhost:3000` in the browser. In that case, two things need to be changed:

- Change `NEXT_PUBLIC_API_BASE_URL` to the address of the backend, e.g `https://api.example.org`.
- Change `VITE_API_BASE_URL` to the address of the backend, e.g `https://api.example.org`.
- You will also need to update `CORS_ORIGINS` to the address of the frontend, e.g.
`https://app.example.org`.

Expand Down
2 changes: 1 addition & 1 deletion frontend/.env.development
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
NEXT_PUBLIC_HCAPTCHA_SITE_KEY='10000000-ffff-ffff-ffff-000000000001'
VITE_HCAPTCHA_SITE_KEY='10000000-ffff-ffff-ffff-000000000001'
ANALYTICS_SCRIPT_SRC=''
ANALYTICS_DATA_DOMAIN=''
ANALYTICS_DATA_WEBSITE_ID=''
1 change: 1 addition & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

# production
/build
/dist

# misc
.DS_Store
Expand Down
30 changes: 11 additions & 19 deletions frontend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ FROM node:22-alpine AS deps

WORKDIR /app

COPY package.json yarn.lock ./
COPY pnpm-lock.yaml package.json ./

# Increase timeout for slow QEMU arm64 builds
# https://github.com/nodejs/docker-node/issues/1335
RUN yarn --network-timeout 1000000
RUN corepack enable && pnpm i

# Rebuild the source code only when needed
FROM node:22-alpine AS builder
Expand All @@ -17,9 +15,11 @@ WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules

RUN NEXT_PUBLIC_API_BASE_URL=http://NEXT_PUBLIC_API_BASE_URL_PLACEHOLDER \
NEXT_PUBLIC_HCAPTCHA_SITE_KEY=NEXT_PUBLIC_HCAPTCHA_SITE_KEY_PLACEHOLDER \
yarn build
RUN corepack enable

RUN VITE_API_BASE_URL=http://VITE_API_BASE_URL_PLACEHOLDER \
VITE_HCAPTCHA_SITE_KEY=VITE_HCAPTCHA_SITE_KEY_PLACEHOLDER \
pnpm build

# Production image, copy all the files and run next
FROM node:22-alpine AS runner
Expand All @@ -29,27 +29,19 @@ WORKDIR /app
ENV NODE_ENV=production

RUN addgroup -g 1001 --system nodejs && \
adduser --system nextjs -u 1001 -G nodejs
adduser --system vite -u 1001 -G nodejs

COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder --chown=vite:nodejs /app/public ./public
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
COPY --from=builder --chmod=0755 /app/docker-entrypoint.sh ./entrypoint.sh
COPY --from=builder /app/next.config.js ./next.config.js
COPY --from=builder /app/next-i18next.config.js ./next-i18next.config.js

RUN apk add bash

RUN yarn next telemetry disable

USER nextjs
USER vite

EXPOSE 3000

ENTRYPOINT ["/app/entrypoint.sh"]

HEALTHCHECK --interval=10s --timeout=5s --retries=5 \
CMD ["wget", "--spider", "http://0.0.0.0:3000", "||", "exit", "1"]

CMD ["yarn", "start"]
CMD ["pnpm", "start"]
23 changes: 0 additions & 23 deletions frontend/docker-entrypoint.sh

This file was deleted.

18 changes: 18 additions & 0 deletions frontend/i18n.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import i18n from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import Backend from 'i18next-http-backend';
import { initReactI18next } from 'react-i18next';

i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
fallbackLng: 'en',
defaultNS: 'common',
interpolation: {
escapeValue: false,
},
});

export default i18n;
17 changes: 17 additions & 0 deletions frontend/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Bracket</title>
<meta charSet="UTF-8" />
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="/favicon.svg" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
16 changes: 0 additions & 16 deletions frontend/jest.config.js

This file was deleted.

1 change: 0 additions & 1 deletion frontend/jest.setup.js

This file was deleted.

5 changes: 0 additions & 5 deletions frontend/next-env.d.ts

This file was deleted.

9 changes: 0 additions & 9 deletions frontend/next-i18next.config.js

This file was deleted.

Loading