Skip to content
Closed
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
44 changes: 20 additions & 24 deletions .github/workflows/pr-labeler.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: PR Labeler

on:
pull_request:
pull_request_target:
types: [opened, synchronize, reopened, ready_for_review]

permissions:
Expand All @@ -26,34 +26,30 @@ jobs:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Fetch PR commit messages
id: check-breaking
uses: actions/github-script@v7
with:
fetch-depth: 0
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const pull_number = context.payload.pull_request.number;

- name: Check commits for breaking changes
id: check-breaking
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
echo "Scanning commits from $BASE_SHA to $HEAD_SHA..."
const commits = await github.paginate(
github.rest.pulls.listCommits,
{ owner, repo, pull_number }
);

const commitMessages = commits
.map(c => `${c.commit.message}`)
.join('\n');

# Collect all commit messages in the PR
COMMITS=$(git log "$BASE_SHA".."$HEAD_SHA" --pretty=format:"%s %b")
console.log('PR Commit Messages:\n', commitMessages);

echo "Commit messages:"
echo "$COMMITS"
const regex = /BREAKING[ \t]+CHANGE|breaking[ \t]+change|!:|feat!|fix!|refactor!|perf!|chore!/i;
const found = regex.test(commitMessages);

# Check for breaking change indicators (Conventional Commits spec + common patterns)
if echo "$COMMITS" | grep -qiE \
'BREAKING[[:space:]]+CHANGE|breaking[[:space:]]+change|!:|feat!|fix!|refactor!|perf!|chore!'; then
echo "found=true" >> "$GITHUB_OUTPUT"
echo "Breaking change detected in commit messages."
else
echo "found=false" >> "$GITHUB_OUTPUT"
echo "No breaking changes detected."
fi
core.setOutput('found', found ? 'true' : 'false');

- name: Add breaking-change label
if: steps.check-breaking.outputs.found == 'true'
Expand Down
189 changes: 0 additions & 189 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,189 +0,0 @@
<h1 align="center">
<img width="1280" height="354" alt="fxManager banner" src="./.github/assets/banner.png" />
</h1>

<p align="center">
<img alt="GitHub License" src="https://img.shields.io/github/license/fxManagerProject/fxManager">
<img alt="GitHub latest release" src="https://img.shields.io/github/downloads/fxManagerProject/fxManager/total?logo=github">
<img alt="GitHub commits since latest release" src="https://img.shields.io/github/commits-since/fxManagerProject/fxManager/latest">
<img alt="GitHub contributors" src="https://img.shields.io/github/contributors/fxManagerProject/fxManager">
<img alt="Tests" id="test-coverage" src="https://img.shields.io/badge/coverage-97%25-brightgreen">
</p>
<p align="center">
<a href="https://fxmanager.dev/docs" target="_blank" style="text-decoration: none;">
<img alt="Documentation" src="https://img.shields.io/badge/view-documentation-orange?logo=readthedocs&logoColor=white">
</a>
<a href="https://discord.gg/5K6CTkFKJR" target="_blank" style="text-decoration: none;">
<img alt="Documentation" src="https://img.shields.io/badge/join-discord-5865F2?logo=discord&logoColor=white">
</a>
</p>

A self-contained, cross-platform admin panel for FiveM & RedM servers.
Single binary deployment - no runtime dependencies required on the target machine.

> [!WARNING]
> This project is still in intensive development, it is **not** to be considered stable until a `v1.0.0+` release.
> If this repository is public, it's for transparency, feedback and open source contributions to help it achieve this milestone.

## Structure

Each app/package will have it's own more detailled structure in it's README.

```
fxManager/
├── apps/
│ ├── core/ # Process Manager & Webserver
│ ├── resource/ # FxServer resource to connect to panel
│ └── webpanel/ # React SPA served by the webserver
├── packages/
│ ├── database/ # Drizzle schema & Migration handler
│ ├── shared/ # Enums, types, and utils
│ └── ui/ # Shared React ShadCN components
├── biome.json # Root linting/formatting
├── package.json # Workspace definitions
└── turbo.json # Build pipeline config
```

---

## Development

```bash
# Install dependencies
bun install

# Start system
bun dev
```

The React dev server runs on `:5173` and proxies API/WS calls on `:3000`.

---

## Code Quality

```bash
bun check # lint + format + fix (recommended during dev)
bun lint # lint only
bun format # format only
bun typecheck # tsc --noEmit across all packages (via Turbo)
bun db:studio # open Drizzle Studio to browse the database (optional)
bun db:migrate # creates a new migration file
```

---

### Game Resource ( [`apps/resource`](./apps/resource) )
Commands specific to the game-side resource and NUI:

* **`bun web:dev`** – Runs the Vite dev server for the NUI frontend.
* **`bun watch`** – Rebuilds the resource automatically as you save files.
* **`bun deploy`** – Bundles the resource and copies it to the path defined in your `DEPLOY_PATH` environment variable.

---

## Database Migrations

Migrations are automated via a synchronization utility. Do not manually edit the migration registry.

### Adding a Migration

1. **Generate Migration**: Run the generation script using:
```bash
bun run db:migrate
```
2. **Describe**: When prompted, provide a short description of the changes.

The utility will automatically:
* Sanitize and split the SQL queries.
* Create a structured `.ts` migration file in `packages/database/src/migrations/migrations/`.
* Register the new migration in `packages/database/src/migrations/index.ts`.

### Rules
* **Immutability**: Never modify a migration file (`.sql`, `.ts`, or `.json`) once it has been deployed to production.
* **Automation**: Migrations are applied automatically on the next application startup.

---

## Tooling

**Biome** handles linting and formatting (replacing ESLint and Prettier) using a single, high-performance configuration at the root.

---

## Releasing

Releases are driven by a maintainer - the workflow never commits, pushes, or tags. To cut a new release:

```bash
bun ./scripts/release.ts v0.3.3
```

---

## Building

```bash
# Build for both platforms
bun run build

# Build for a specific platform
bun run build --target=linux
bun run build --target=windows
```

Turbo caches build outputs - subsequent builds only rebuild what changed.

Output in `dist/`:

```
dist/
fxmanager-linux ← Linux binary
fxmanager-windows.exe ← Windows binary
assets/ ← UI assets - must stay next to the binary
resource/ ← Drop into your server's resources/ folder
```

> [!IMPORTANT]
> The `assets/` folder must remain in the same directory as the binary when deploying. The server resolves it relative to its own location at runtime.

---

## Deployment

### 1. Run the binary

```
your-deploy-folder/
fxmanager-linux (or fxmanager-windows.exe)
assets/
.env
```

```bash
./fxmanager-linux # or fxmanager-windows.exe
```

The panel will be available at `http://your-server-ip:4000`.

### 2. Install the resource

1. Copy `dist/resource/` into your server's `resources/` folder as `fxManager`
2. **IMPORTANT** Do not add `ensure fxManager` to your `server.cfg` or attempt to stop it

---

## Environment Variables

| Variable | Default | Description |
|-----------------------|-------------------|--------------------------------------|
| `FXSERVER_EXECUTABLE` | `./FXServer` | Path to FXServer binary |
| `FXSERVER_DATA_PATH` | `./server-data` | Path to server-data folder |
| `FXSERVER_CFG` | `server.cfg` | Config file name inside data path |
| `PANEL_PORT` | `3000` (opt) | Web panel port |
| `COOKIE_SECRET` | N/A (opt) | Defines the secret for cookie sign |
| `DEPLOY_PATH` | N/A | Used in development for the resource |

## Errrh anything else ?

![dumb monke](.github/assets/image.png)
Loading