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
7 changes: 5 additions & 2 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
.github
docs
node_modules
backend/filetree
backend/filetree.exe
app/web/node_modules
app/web/dist
app/uiembed/dist
app/filetree
app/filetree.exe
*.md
.env
.env.*
4 changes: 2 additions & 2 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/backend"
directory: "/app"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
Expand All @@ -13,7 +13,7 @@ updates:
open-pull-requests-limit: 5

- package-ecosystem: "npm"
directory: "/frontend"
directory: "/app/web"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
Expand Down
18 changes: 15 additions & 3 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,21 @@ Documentation:

Backend:
- changed-files:
- any-glob-to-any-file: backend/**
- any-glob-to-any-file: app/config/**
- any-glob-to-any-file: app/handlers/**
- any-glob-to-any-file: app/middleware/**
- any-glob-to-any-file: app/main.go
- any-glob-to-any-file: app/frontend_mount.go
- any-glob-to-any-file: app/go.mod
- any-glob-to-any-file: app/go.sum
- any-glob-to-any-file: app/uiembed/**

Frontend:
- changed-files:
- any-glob-to-any-file: frontend/**

- any-glob-to-any-file: app/web/src/**
- any-glob-to-any-file: app/web/public/**
- any-glob-to-any-file: app/web/index.html
- any-glob-to-any-file: app/web/package.json
- any-glob-to-any-file: app/web/package-lock.json
- any-glob-to-any-file: app/web/vite.config.*
- any-glob-to-any-file: app/web/tsconfig*.json
66 changes: 45 additions & 21 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ jobs:
if: github.event_name == 'pull_request'
run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose

backend:
name: Backend
app:
name: App (Go)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
Expand All @@ -54,22 +54,22 @@ jobs:
uses: actions/setup-go@v6
with:
go-version: '1.25'
cache-dependency-path: backend/go.sum
cache-dependency-path: app/go.sum

- name: Build
run: cd backend && go build -o filetree .
run: cd app && go build -o filetree .

- name: Vet
run: cd backend && go vet ./...
run: cd app && go vet ./...

- name: Test
run: cd backend && go test ./...
run: cd app && go test ./...

- name: Lint
uses: golangci/golangci-lint-action@v9
with:
version: v2.10
working-directory: backend
working-directory: app

gosec:
name: Go security scan
Expand All @@ -81,12 +81,12 @@ jobs:
uses: actions/setup-go@v6
with:
go-version: '1.25'
cache-dependency-path: backend/go.sum
cache-dependency-path: app/go.sum

- name: Run gosec
run: |
go install github.com/securego/gosec/v2/cmd/gosec@latest
cd backend && gosec ./...
cd app && gosec ./...

frontend:
name: Frontend
Expand All @@ -99,24 +99,54 @@ jobs:
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json
cache-dependency-path: app/web/package-lock.json

- name: Install dependencies
run: cd frontend && npm ci
run: cd app/web && npm ci

- name: Build
run: cd frontend && npm run build
run: cd app/web && npm run build

- name: Upload frontend artifact
uses: actions/upload-artifact@v4
with:
name: frontend-dist
path: frontend/dist
path: app/web/dist

app-embed:
name: App (embedded UI)
runs-on: ubuntu-latest
needs: [frontend]
steps:
- uses: actions/checkout@v6

- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: '1.25'
cache-dependency-path: app/go.sum

# Upload stores paths relative to app/web/dist (index.html, assets/...), not app/web/dist/...
# Extract directly into app/web/dist so cp below finds the built UI.
- name: Download frontend dist
uses: actions/download-artifact@v4
with:
name: frontend-dist
path: app/web/dist

- name: Stage UI for embed
run: |
rm -rf app/uiembed/dist
mkdir -p app/uiembed/dist
cp -R app/web/dist/. app/uiembed/dist/

- name: Build with embedded frontend
run: cd app && go build -tags embed -o filetree .

docker-build:
name: Build
runs-on: ubuntu-latest
needs: [commitlint, backend, gosec, frontend]
needs: [commitlint, app, gosec, frontend, app-embed]
steps:
- uses: actions/checkout@v6

Expand Down Expand Up @@ -145,12 +175,6 @@ jobs:
steps:
- uses: actions/checkout@v6

- name: Download frontend artifact
uses: actions/download-artifact@v4
with:
name: frontend-dist
path: frontend/dist

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

Expand Down Expand Up @@ -197,7 +221,7 @@ jobs:
ci-success:
name: CI success
runs-on: ubuntu-latest
needs: [commitlint, backend, gosec, frontend, docker-build]
needs: [commitlint, app, gosec, frontend, app-embed, docker-build]
steps:
- name: All checks passed
run: echo "All checks passed"
10 changes: 6 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# Go
backend/filetree
backend/filetree.exe
backend/data/
app/filetree
app/filetree.exe
app/data/

# Node / frontend
# Node / UI (also legacy paths)
node_modules/
app/web/dist/
app/uiembed/dist/
frontend/dist/

# MkDocs
Expand Down
17 changes: 9 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Thank you for your interest in contributing.

## Development setup

1. **Backend:** `cd backend && go mod tidy && go run .`
2. **Frontend:** `cd frontend && npm install && npm run dev`
1. **Go (API):** `cd app && go mod tidy && go run .`
2. **UI:** `cd app/web && npm install && npm run dev`
3. Set `CONFIG_FILE=./config.yaml` and configure auth (see `config.example.yaml`).

## Commit messages
Expand All @@ -21,9 +21,10 @@ Validate locally: `make commitlint` or `npx commitlint --last --verbose`
## Pull requests

1. Create a branch from `main`.
2. Ensure `go build ./... && go vet ./... && go test ./...` passes in `backend`.
3. Ensure `npm run build` passes in `frontend`.
4. Open a PR with a clear description of the change.
2. Ensure `go build ./... && go vet ./... && go test ./...` passes in `app`.
3. Ensure `npm run build` passes in `app/web`.
4. Optional: `make build` verifies the full embedded binary (frontend + `go build -tags embed`).
5. Open a PR with a clear description of the change.

## Code style

Expand All @@ -32,7 +33,7 @@ Validate locally: `make commitlint` or `npx commitlint --last --verbose`

## Go score & quality

CI runs these checks on the backend:
CI runs these checks on the Go module under `app/`:

| Tool | Purpose |
|------|---------|
Expand All @@ -45,10 +46,10 @@ CI runs these checks on the backend:
Run locally:

```bash
cd backend
cd app
go build ./... && go vet ./... && go test ./...
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest && golangci-lint run
go install github.com/securego/gosec/v2/cmd/gosec@latest && gosec ./...
```

If you fork the repo, update the Go Report Card badge in the README to point to your fork (e.g. `github.com/YOUR_ORG/filetree`) to see the score at [goreportcard.com](https://goreportcard.com).
If you fork the repo, update the Go Report Card badge in the README to point to your fork module path (e.g. `github.com/YOUR_ORG/filetree/app`) to see the score at [goreportcard.com](https://goreportcard.com).
16 changes: 9 additions & 7 deletions Containerfile
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
FROM node:20-alpine AS frontend
WORKDIR /app/frontend
COPY frontend/ ./
WORKDIR /app/web
COPY app/web/package.json app/web/package-lock.json ./
ENV NODE_OPTIONS="--max-old-space-size=4096"
RUN if [ ! -f dist/index.html ]; then npm ci && npm run build; fi
RUN npm ci
COPY app/web/ ./
RUN npm run build

FROM golang:1.25-alpine AS backend
WORKDIR /app
COPY backend/go.mod backend/go.sum ./
COPY app/go.mod app/go.sum ./
RUN go mod download
COPY backend/ ./
RUN CGO_ENABLED=0 go build -o filetree .
COPY app/ ./
COPY --from=frontend /app/web/dist ./uiembed/dist
RUN CGO_ENABLED=0 go build -tags embed -o filetree .

FROM alpine:3.20
RUN apk add --no-cache ca-certificates
WORKDIR /app

COPY --from=backend /app/filetree .
COPY --from=frontend /app/frontend/dist ./frontend/dist

EXPOSE 8080

Expand Down
48 changes: 26 additions & 22 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,37 +1,41 @@
.PHONY: build build-backend build-frontend test commitlint clean run-backend run-frontend
.PHONY: build all build-app build-frontend embed-ui build-app-embed test commitlint clean run run-frontend

# Build Go binary (output: backend/filetree or backend/filetree.exe)
build-backend:
cd backend && go build -o filetree .
# One binary with embedded UI: Vite → app/web/dist → app/uiembed/dist → go build -tags embed
build: embed-ui
cd app && go build -tags embed -o filetree .

# Build frontend (output: frontend/dist/)
build-frontend:
cd frontend && npm run build
all: build

# Same as build (kept for scripts and docs that name it explicitly)
build-app-embed: build

# Build both backend binary and frontend assets
all: build-backend build-frontend
# Go only, no embed (dev: skip npm when UI unchanged; serve from app/web/dist on disk if present)
build-app:
cd app && go build -o filetree .

# Frontend (output: app/web/dist/)
build-frontend:
cd app/web && npm run build

# Alias
build: all
# Stage static files for go:embed (used by build). Prereqs build-frontend so `make -j` cannot copy before Vite finishes.
embed-ui: build-frontend
rm -rf app/uiembed/dist
mkdir -p app/uiembed/dist
cp -R app/web/dist/. app/uiembed/dist/

# Validate last commit message (Conventional Commits)
commitlint:
npx commitlint --last --verbose

# Run tests
test:
cd backend && go vet ./... && go test ./...
cd frontend && npm run build
cd app && go vet ./... && go test ./...
cd app/web && npm run build

# Run Go backend (dev)
run:
./backend/filetree
./app/filetree

# Run frontend dev server (proxies /api to backend)
run-frontend:
cd frontend && npm run dev
cd app/web && npm run dev

# Remove build artifacts
clean:
rm -f backend/filetree backend/filetree.exe
rm -rf frontend/dist
rm -f app/filetree app/filetree.exe
rm -rf app/web/dist app/uiembed/dist frontend/dist
16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@


<p align="center">
<a href="https://goreportcard.com/report/github.com/heapoftrash/filetree/backend">
<img src="https://goreportcard.com/badge/github.com/heapoftrash/filetree/backend" alt="Go Report Card"/>
<a href="https://goreportcard.com/report/github.com/heapoftrash/filetree/app">
<img src="https://goreportcard.com/badge/github.com/heapoftrash/filetree/app" alt="Go Report Card"/>
</a>
<a href="https://github.com/heapoftrash/filetree/actions/workflows/ci.yml">
<img src="https://github.com/heapoftrash/filetree/actions/workflows/ci.yml/badge.svg" alt="Build status"/>
Expand Down Expand Up @@ -70,21 +70,25 @@ If the package is private, run `docker login ghcr.io` before `docker pull`.

### Production binary

**Production binary** — `make build` runs the Vite production build, copies output into `app/uiembed/dist` for `go:embed`, and compiles **one** `app/filetree` binary with the UI embedded (install UI deps once: `cd app/web && npm ci`):

```bash
git clone https://github.com/heapoftrash/filetree.git
make build
ROOT_PATH=/path/to/files CONFIG_FILE=./config.yaml ./backend/filetree
ROOT_PATH=/path/to/files CONFIG_FILE=./config.yaml ./app/filetree
```

Ship `backend/filetree` and `frontend/dist`. The binary serves the built UI when `frontend/dist` is present.
The **prebuilt container image** already uses an embedded UI (no separate static bundle directory in the image).

**UI on disk (optional)** — `make build-app` (Go only) plus `make build-frontend` if you want `app/web/dist` on disk; run `./app/filetree` from the repo root and the server will pick up `app/web/dist`, `app/uiembed/dist`, or cwd-relative paths (see [documentation](https://heapoftrash.github.io/filetree/)).

See [docs/API.md](docs/API.md) for the API. Build docs locally: `pip install mkdocs-material && mkdocs serve`.

### Development

**API** — `cd backend && go mod tidy && go run .` → **http://localhost:8080**
**API** — `cd app && go mod tidy && go run .` → **http://localhost:8080**

**UI** — `cd frontend && npm install && npm run dev` → **http://localhost:5173** (proxies `/api` to the backend)
**UI** — `cd app/web && npm install && npm run dev` → **http://localhost:5173** (proxies `/api` to the API)

Set `frontend.url` in config to `http://localhost:5173` for CORS and OAuth.

Expand Down
Loading
Loading