Contributing to filex
Thanks for considering a contribution. This is a small, opinionated codebase — before opening a sizeable PR please file an issue describing what you're about to do.
Development setup
Requirements:
- Go 1.22+
- Node.js 20+
- pnpm 9+
- (optional) Docker, ffmpeg, ghostscript, libreoffice for thumbnail dev
git clone https://gitlab.com/brftech/filemanager.git
cd filemanager
pnpm install # all workspace packages
pnpm run dev # parallel: package watch + admin Vite dev server
# In another shell — Go backend
cd backend
go run ./cmd/filex serve --listen 127.0.0.1:5212 --data-dir ./.dev-dataThe admin SPA is served by Vite at http://localhost:5173 in dev mode and proxies /api/* to the Go server at :5212. For the embedded build (what ships in the binary), use pnpm run build:all.
Running with hot-reload
# Terminal 1 — Go (recompiles on save with air)
go install github.com/cosmtrek/air@latest
cd backend && air
# Terminal 2 — admin SPA + packages
pnpm run devWorkflow
- Fork + create a feature branch off
main. - Code + write tests.
- Lint locally:
pnpm run lintandcd backend && go vet ./... && staticcheck ./.... - Test locally:
pnpm run testandcd backend && go test -race ./.... - Open MR against
main. CI runs lint + test + build. - Address review + squash if asked.
- Merge — maintainer squashes; commit message becomes a CHANGELOG line.
Branches
main— protected, always green.feat/<short-name>,fix/<short-name>,chore/<short-name>— feature branches.release/v0.X.Y— short-lived branch only used to cut a release.
We don't run a develop branch. Trunk-based development with feature flags when something needs to land partially.
Commit messages
Conventional Commits. The CHANGELOG generator depends on the prefixes:
<type>(<scope>): <subject>
<body, wrapped at 100>
<optional footer; e.g. BREAKING CHANGE: ...>Types we use:
| Type | Meaning |
|---|---|
feat | new user-visible feature |
fix | bug fix |
perf | performance change with no behaviour change |
refactor | internal restructuring, no behaviour change |
docs | documentation only |
test | tests only |
chore | tooling, deps, CI; no functional change |
ci | CI config only |
build | build pipeline / Dockerfiles |
Scopes (optional but encouraged): backend, core, webcomponent, react, web, docker, ci, docs, storage:s3, auth:oidc, etc.
Examples:
feat(storage:s3): add use_path_style for MinIO compatibility
fix(auth:oidc): refresh token before expiry instead of after
docs(api): document /api/admin/external/:name/test
build(docker): pin alpine to 3.20 to dodge ghostscript regressionBreaking changes:
feat(api)!: rename @file-explorer-share to @share-created
BREAKING CHANGE: the Vue event name changed. See docs/MIGRATION.md.Testing
Go
cd backend
go test -race ./...
go test -race -cover ./... # with coverage
go test -run TestStorageS3 -v ./internal/storage/s3For driver tests, we have integration suites under internal/storage/*/integration_test.go guarded by //go:build integration. Run with:
go test -tags=integration ./internal/storage/s3 \
-test-bucket="$TEST_BUCKET" -test-region=us-east-1Web
pnpm run test # all workspaces
pnpm --filter='@brftech/filex-core' testVitest with happy-dom; Playwright suites live in web/e2e/ (run separately: pnpm --filter='@brftech/filex-admin' e2e).
What needs tests
- Always: every new HTTP endpoint, every new storage driver method, every config knob.
- Encouraged: new UI components (Vitest
mount). - Optional but appreciated: end-to-end Playwright scenarios when the flow spans many components.
Code style
Go
gofmt -s(CI checksgofmt -l .is empty).go vet ./...clean.staticcheck ./...clean.- Public symbols documented (
// FuncName does X). - Error wrapping with
fmt.Errorf("...: %w", err). - No global state outside of
cmd/filex.
TypeScript / Vue
- ESLint with
eslint-plugin-vuerecommended config. - Strict TypeScript:
noImplicitAny,strictNullChecks. - Prefer composables for reusable logic; SFC for components.
- No default exports (named only) — easier IDE refactor.
General
- ASCII characters by default. Add comments in English even if the codebase is bilingual.
- No
console.logleft over — useimport.meta.env.DEVguards in dev-only code paths.
Docs
Doc updates live alongside code changes in the same PR. The pattern:
- New endpoint → update BACKEND.md.
- New component prop / event → update API.md.
- New config field → update CONFIGURATION.md.
- New driver → update ARCHITECTURE.md + driver-specific section in CONFIGURATION.md.
- New external service → all of the above.
- Behaviour change → CHANGELOG entry under
## [Unreleased].
Release process
Maintainer-only. Reproducible, automated by CI.
- Update
CHANGELOG.md— move[Unreleased]to a dated[vX.Y.Z]heading. - Bump
package.jsonversions across all packages:bashpnpm -r exec npm version X.Y.Z --no-git-tag-version - Commit:
chore(release): vX.Y.Z. - Tag:
git tag -s vX.Y.Z -m "vX.Y.Z". - Push:
git push origin main --tags.
CI does the rest:
release:goreleaser— multi-arch binaries → GitLab Release.release:npm— publishes@brftech/filex-core,@brftech/filex,@brftech/filex-reactto the GitLab npm registry.release:docker— pushes:slim-vX.Y.Z,:full-vX.Y.Z,:latest.
If something fails, fix forward — never delete a published tag.
