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
31 changes: 31 additions & 0 deletions .context/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# SetRsoft Architecture Overview

This document provides a concise overview of the SetRsoft project's core architecture. It is intended to help AI agents quickly understand the technology stack and repository structure.

## 1. Technology Stack

### Frontend
- **Framework:** React 19 built with Vite.
- **Language:** TypeScript.
- **Styling:** Tailwind CSS v4 (configured via `@theme` in `src/index.css`). Design follows the "Stitch" UI charter ("The Kinetic Monolith").
- **Routing:** React Router v7.
- **State/Data Fetching:** React Query (TanStack Query v5).
- **Internationalization (i18n):** `react-i18next` supporting multiple languages (EN, FR, DE, RU, CN).

### Backend
- **Framework:** Django (Python).
- **Database:** PostgreSQL 16.

### Infrastructure & Deployment
- **Containerization:** Docker & Docker Compose.
- **Services:** `db` (Postgres), `backend` (Django runserver), `frontend` (Vite dev server).

## 2. Directory Structure

- `/frontend/` - Contains the React single-page application.
- `src/app/` - App-wide layout (`Root.tsx`), global routing, and main entry providers.
- `src/features/` - Domain-specific modules (e.g., `showcase`, `gym`, `editor`).
- `src/shared/` - Shared UI components (e.g., `Footer`, `LanguageSwitcher`), hooks, and utilities.
- `src/locales/` - JSON files for i18n translations.
- `/backend/` - Contains the Django server, API definitions, and models.
- `/docker-compose.yml` - Defines the local development environment using containerized services.
32 changes: 32 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copy to ".env" at the repository root (Docker Compose and local tooling load it from here).
# Django also loads this file via backend/setrsoft/settings.py (repo root).

# --- Django ---
# Required in production. Use a long random string.
SECRET_KEY=your-secret-key

# Development: True. Production: False.
DEBUG=True

# Comma-separated hostnames Django may serve (no spaces). Include your domain in production.
ALLOWED_HOSTS=localhost,127.0.0.1

# Set to 1/true/yes when Django sits behind a reverse proxy (Nginx, load balancer) so
# USE_X_FORWARDED_HOST and X-Forwarded-Proto are honored. Typical in production.
TRUST_PROXY=

# --- PostgreSQL (Django DATABASES + Docker "db" service) ---
POSTGRES_DB=setrsoft
POSTGRES_USER=setrsoft
POSTGRES_PASSWORD=changeme

# Host running PostgreSQL: use "localhost" for Django on the host; Docker Compose overrides
# to "db" for the backend container.
POSTGRES_HOST=localhost
POSTGRES_PORT=5432

# --- Frontend (Vite) ---
# Base URL for API requests from the browser. Leave empty when the SPA and API share the
# same origin (e.g. production Nginx serves / and proxies /api/ to Django).
# For local Vite (e.g. :5173) talking to Django on :8000, set e.g. http://localhost:8000
VITE_API_BASE=
49 changes: 49 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: CI

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
backend-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
cd backend
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run Django Tests
run: |
cd backend
python manage.py test

Comment on lines +12 to +29

Copilot AI Mar 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The backend job runs python manage.py test but the Django settings are configured to always use PostgreSQL (django.db.backends.postgresql), and this workflow does not start a Postgres service or set POSTGRES_* env vars. CI will fail to connect to a DB. Add a services: postgres: container (with health checks) and export matching POSTGRES_* vars, or provide a CI-only settings module that uses SQLite.

Copilot uses AI. Check for mistakes.
frontend-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: |
cd frontend
npm install
- name: Run Linter
run: |
cd frontend
npm run lint
- name: Run Build
run: |
cd frontend
npm run build
18 changes: 18 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# AI Agents Directives

This document provides foundational rules and context for any AI agent interacting with the SetRsoft repository.

## Global Rules
1. **Language:** All code, comments, documentation, and commit messages MUST be written in English. Wait for explicit user override to write in another language.
2. **Context First:** Always review `.context/architecture.md` before making architectural decisions or proposing new libraries.
3. **No Destructive Operations:** Do not delete databases or wipe configuration files without explicit user approval.

## Frontend Development Guidelines
- **Styling:** The application uses Tailwind CSS v4. Do NOT use `tailwind.config.js` for themes; instead, rely on the `@theme` directive in `src/index.css`.
- **Design Charter:** The UI strictly follows the "Stitch" charter ("The Kinetic Monolith"). Use named tokens (`surface-low`, `mint`, `on-surface-variant`). Avoid traditional 1px borders in favor of background color shifts (`bg-surface-high` vs `bg-surface-low`).
- **Translations:** Any user-facing string must use the `useTranslation()` hook from `react-i18next` mapped to the JSON files in `src/locales/`.

## Backend Development Guidelines
- Standard Django conventions apply.
- Ensure database migrations are generated and applied properly if changes are made to models.
- The PostgreSQL database is named `setrsoft` by default.
File renamed without changes.
135 changes: 75 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,73 +1,88 @@
# React + TypeScript + Vite
# SetRsoft

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
[![CI Status](https://github.com/setrsoft/setrsoft_app/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/setrsoft/setrsoft_app/actions/workflows/ci.yml)
[![Discord](https://img.shields.io/badge/Discord-Join-7289da?logo=discord&logoColor=white)](https://discord.gg/BdyfNU9TpR)

Currently, two official plugins are available:
## Environment variables

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
All variables are listed in **`.env.example`** at the repository root. Before running Docker Compose, copy it once:

## React Compiler
```bash
cp .env.example .env
```

Compose loads **`.env`** automatically for `${VAR}` substitution in the YAML files, and each service uses **`env_file: .env`** so containers receive the same values. Django reads the same **`.env`** from the repo root when you run `manage.py` locally (see `backend/setrsoft/settings.py`).

The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
## Development (Docker)

## Expanding the ESLint configuration
From the repository root (after `cp .env.example .env`):

```bash
docker compose up
```

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
This starts:

```js
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
| Service | Role | URL / port |
| --------- | ---------------------------- | ----------------- |
| `db` | PostgreSQL | `localhost:5432` |
| `backend` | Django `runserver` (reload) | `http://localhost:8000` |
| `frontend`| Vite dev server (`npm run dev` in container) | `http://localhost:5173` |

// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,
Open the app at **http://localhost:5173**. Set **`VITE_API_BASE=http://localhost:8000`** in `.env` so the browser calls the API on port 8000 when the SPA is not served from the same origin.

// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
First-time backend setup (migrations, superuser) is usually run inside the backend container, for example:

```bash
docker compose exec backend python manage.py migrate
docker compose exec backend python manage.py createsuperuser
```

You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:

```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'

export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
## Production (Docker)

Production uses **`docker-compose.prod.yml`**: Nginx serves the built SPA and proxies `/api/` and `/admin/` to Gunicorn. Only **port 80** is published; the database and Django are not exposed on the host.

Required in **`.env`** at the repository root (or exported in your shell):

- `POSTGRES_PASSWORD`
- `SECRET_KEY`

See **`.env.example`** for the full list. Optional values such as `POSTGRES_DB`, `POSTGRES_USER`, `DEBUG`, `ALLOWED_HOSTS`, `TRUST_PROXY`, and **`VITE_API_BASE`** (passed as a Docker **build arg** for the `web` image when you need an absolute API URL in the built SPA) are documented there.

**Start production stack** (build images, run detached):

```bash
docker compose -f docker-compose.prod.yml up -d --build
```

With inline env (example):

```bash
POSTGRES_PASSWORD=your-secure-password SECRET_KEY=your-django-secret-key docker compose -f docker-compose.prod.yml up -d --build
```

Then open **http://localhost** (or your server’s hostname). Use **`ALLOWED_HOSTS`** (and HTTPS + `TRUST_PROXY` as already set in compose) when deploying under a real domain.

**Stop:**

```bash
docker compose -f docker-compose.prod.yml down
```

## Local frontend without Docker

You can still run Vite on the host:

```bash
cd frontend && npm install && npm run dev
```

Use this if you prefer not to use the `frontend` service from `docker compose up`.

## Project layout

- `.env.example` — template for all services (Django, PostgreSQL, Vite)
- `backend/` — Django project (`setrsoft`), API under `/api/`
- `frontend/` — Vite + React SPA; production image builds static assets and serves them with Nginx
- `docker-compose.yml` — development
- `docker-compose.prod.yml` — production
11 changes: 0 additions & 11 deletions backend/.env.example

This file was deleted.

5 changes: 5 additions & 0 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# Collect admin and app static files for WhiteNoise (no DB connection required).
ENV SECRET_KEY=collectstatic-build-placeholder
RUN python manage.py collectstatic --noinput
Comment on lines +15 to +16

Copilot AI Mar 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sets ENV SECRET_KEY=... in the image layers to make collectstatic run. That default persists into the runtime image and could accidentally be used if a real SECRET_KEY isn’t provided. Prefer setting the env var only for the single command (e.g. inline in the RUN ... collectstatic step) so it doesn’t become the container default.

Suggested change
ENV SECRET_KEY=collectstatic-build-placeholder
RUN python manage.py collectstatic --noinput
RUN SECRET_KEY=collectstatic-build-placeholder python manage.py collectstatic --noinput

Copilot uses AI. Check for mistakes.

EXPOSE 8000

CMD ["gunicorn", "setrsoft.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "2"]
16 changes: 4 additions & 12 deletions backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,14 @@ pip install -r requirements.txt

## Environment variables

Copy the example file and set your values:
Use the **repository root** template and file:

```bash
# From the repository root (not inside backend/)
cp .env.example .env
```

| Variable | Description |
|----------|-------------|
| `SECRET_KEY` | Django secret key (required in production). |
| `DEBUG` | Set to `True` for development, `False` in production. |
| `ALLOWED_HOSTS` | Comma-separated list of allowed hosts (e.g. `localhost,127.0.0.1`). |
| `POSTGRES_DB` | PostgreSQL database name. |
| `POSTGRES_USER` | PostgreSQL user. |
| `POSTGRES_PASSWORD` | PostgreSQL password. |
| `POSTGRES_HOST` | PostgreSQL host (`localhost` when running locally, `db` when using Docker). |
| `POSTGRES_PORT` | PostgreSQL port (default `5432`). |
Variable names and descriptions live in **`/.env.example`**. Django loads **`/.env`** via `setrsoft/settings.py` (`REPO_ROOT / '.env'`).

## Database

Expand All @@ -57,7 +49,7 @@ The API will be available at `http://localhost:8000/`. Health check: `http://loc

## Docker (optional)

From the repository root, ensure `backend/.env` exists (copy from `backend/.env.example` and set `POSTGRES_HOST=db` for the backend service, or use the defaults which point to the `db` service).
From the repository root, ensure **`.env`** exists (copy from `.env.example`). Docker Compose sets `POSTGRES_HOST=db` inside the backend container; keep `POSTGRES_HOST=localhost` in `.env` for running Django on the host against a local PostgreSQL instance.

Start both the database and the backend:

Expand Down
7 changes: 7 additions & 0 deletions backend/api/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.test import TestCase

class HealthCheckTest(TestCase):
def test_health_endpoint(self):
response = self.client.get('/api/health/')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For better maintainability, consider naming your URL path in api/urls.py (e.g., name='health-check') and using reverse('health-check') here to fetch the URL. This avoids hardcoding URL paths in tests, making them less brittle if the path changes in the future.

self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), {'status': 'ok'})
1 change: 1 addition & 0 deletions backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ djangorestframework
psycopg2-binary
python-dotenv
gunicorn
whitenoise
Loading
Loading