4ga Boards opens on demo/demo and ships three passwords in its compose file
Straightforward realtime kanban boards management for intuitive task tracking. 4ga Boards features an elegant dark mode, collapsible todo lists, and multitasking tools to supercharge your team's productivity.
At a glance
- What is it?
- A self-hosted kanban board built on Sails.js and PostgreSQL, deployed by pulling one compose file and editing it. The interesting parts are the defaults it publishes, the versioned volume names, and the manual SQL edit its restore path asks for.
- Who is it for?
- 4ga Boards is a reasonable pick for a team that wants its board on its own infrastructure and is willing to run Postgres and Redis behind it. Before deploying, change the three published credentials, confirm that the volume names still match the service versions you intend to run, and read the restore section end to end, because the documented recovery path edits a superuser statement inside your own backup archive.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 3, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The compose file publishes three credentials before anyone starts the stack
POSTGRES_PASSWORD is notpassword, SECRET_KEY is notsecretkey, and the redis service runs redis-server with --appendonly yes and --requirepass notredispassword. The rate limit URL repeats the last one as redis://:notredispassword@redis:6379/0, and the redis health check passes the same string to redis-cli -a inside the container, where it is visible to anyone who can read the container configuration.
The setup steps acknowledge two of them and give the recipe for the third. Edit BASE_URL to match your domain, edit SECRET_KEY with a random value that openssl rand -hex 64 produces, and edit POSTGRES_PASSWORD and DATABASE_URL, replacing notpassword with a randomly generated database password. Nothing in the file enforces any of that, because the values are literals in a YAML document. An instance started without those edits runs on the published strings, including the SECRET_KEY the application reads at startup.
Then there is the login. Both the compose route and the development route end with the same two lines: default url http://localhost:3000, default user demo, default password demo. A board that opens on a known account is a convenience on a laptop and an open door on a network, and the difference between the two cases is only whether the person reading the instructions also edited the YAML.
Database volume names carry the major version of the service they hold
The two stateful volumes are called db-data-18 for postgres:18-alpine and redis-data-8 for redis:8-alpine. Named volumes outlive the containers that mount them, and these names are why they outlive a version bump as well. Moving to the next major release of Postgres or Redis changes the name, so the new container mounts an empty volume instead of the existing data directory, and the old data stays behind under the previous name where nothing points at it.
Both services are health gated before the application starts. The database check is pg_isready -U postgres -d 4gaBoards every five seconds with twenty retries, redis runs the same interval on its own ping, and the 4gaBoards service declares depends_on with condition: service_healthy for both. The cluster is created with POSTGRES_DB: 4gaBoards and POSTGRES_INITDB_ARGS: '-A scram-sha-256', so the stored password uses SCRAM from the moment the database is initialised rather than after a later change.
Redis is not incidental here. The default compose file points UPLOAD_RATE_LIMIT_STORE at redis and UPLOAD_RATE_LIMIT_REDIS_URL at that service, and a second file, docker-compose-no-redis.yml, sits at the top level for instances that would rather not run it. Between them the application is two stateful services and three content volumes, and choosing between those two files is the first decision a self-hoster makes.
The restore path asks you to comment out a superuser statement in your own dump
./boards-backup.sh./boards-restore.sh 4gaBoards-backup.tgzBoth scripts have to run from the directory that holds docker-compose.yml, which the setup notes say before the commands rather than after them.
The restore step carries a condition that is easy to miss. When restoring, the password has to match the one in docker-compose. If it does not, the documented way forward is to set a new password in docker-compose and then edit the archive: skip altering the default user in the postgres.sql file inside the backup by commenting out the line ALTER ROLE postgres WITH SUPERUSER INHERIT CREATEROLE CREATEDB LOGIN REPLICATION BYPASSRLS PASSWORD 'XXX' before restoring. The instructions hand you a superuser statement and ask you to silence it inside a file you produced yourself.
That is the whole backup story: two shell scripts, one tarball, and a manual edit of SQL when the credentials have drifted since the backup was taken. The procedure is written down plainly, and the credentials stay in the archive where the person doing the restore has to notice them. Anyone automating restores will have to handle that step themselves.
The image installs npm and pnpm at latest, then asks for a frozen lockfile
The container is built on node:24-alpine in four stages, and the first two commands undercut the pinning that follows.
RUN npm install npm@latest --global
RUN npm install pnpm@latest --globalEvery later stage asks for pnpm install --frozen-lockfile, and the repository ships both pnpm-lock.yaml and pnpm-workspace.yaml, so the dependency graph is meant to be exact. The package manager itself is not, since npm and pnpm are taken at whatever latest resolves to on the build date. Two builds of the same commit can therefore install different pnpm releases over the same locked graph.
The rest of the Dockerfile is careful in ways worth naming. Lint is skipped in the image with DISABLE_ESLINT_PLUGIN=true on the client build. The server stage produces a production node_modules with pnpm deploy --filter server --prod, which is copied into the final stage instead of being installed there. That final stage upgrades the Alpine packages, adds bash, switches to USER node, and runs mv .env.sample .env, so the sample configuration becomes the live configuration inside the image. Three volumes are declared for user-avatars, project-background-images and attachments, the health check spiders http://localhost:1337, and the exposed port is 1337 while the compose file publishes 3000:1337.
package.json still reads 3.3.13 while the repository keeps moving
The version field reads 3.3.13 and the newest release tag is v3.3.13, published on 2026-07-15. Those two agree, which is worth noting because the repository was last pushed on 2026-10-02. Around eleven weeks of commits sit behind the version string that names the shipped image, and the two tags before it came on 2026-07-03 and 2026-07-02. Anyone tracking releases by tag is looking at July; anyone tracking the branch is looking at October.
The script list shows what that work involved. Tests are prefixed: preclient:test and preclient:ci:test both run packages:build first, so the workspace packages under packages/ are rebuilt before any client test starts. The database carries its own init, migrate, migration_make, seed, and two rollback entries, rollback_one and rollback, which is what you add when the schema moves often enough to want a single step undone. Lint runs across the workspace in parallel through pnpm -r --parallel lint, and prepare runs husky, so the commit hooks come from a .husky directory at the top level.
One script deserves a second look. docker:build_local builds rargames0/4gaboards:local and then pushes it, while docker:build tags ghcr.io/rargames/4gaboards:local and stops there. A fork inherits both, and one of them writes into somebody else's registry namespace.
The feature list has one unfinished item and one duplicated language code
Github 2-way sync sits in the same column as the shipped features and is marked Coming soon. Everything around it is written in the present tense, from the advanced Markdown editor through export and import of boards, so the list does not separate what runs today from what does not.
The language line carries an error. Seventeen codes are written out and one appears twice: CS, DA, DE, EN, ES, FR, IT, JA, KO, PL, PT, RU, SK, SV, UZ, ZH, UZ. Sixteen codes, seventeen entries. EN and PL are the two set in bold, which matches the two documentation sites linked from the project, English and Polski.
The data model is stated as one chain, projects to boards to lists to cards to tasks, and the multitasking line explains what the interface does with it. You can edit and review cards while filtering and rearranging the board, and description edits made locally are kept rather than discarded by the rearrangement. That is a specific claim about state surviving a drag, and claims about state during a drag are where this kind of board usually gives way. The GitHub import from Trello, by contrast, is a finished path: add a project, then press Import while creating a new board.
Development needs one client build copied into two server paths
Getting the development server to stop complaining takes two copies of the same build.
pnpm client:buildcp -r client/build server/publiccp client/build/index.html server/views/index.ejsBoth copies are marked optional, and the reason given is suppressing startup warnings. The container performs the same two operations in its client stage, copying the build into public and index.html into views/index.ejs, so the warning is a real mismatch between a built client and a server that looks in two places for it.
The rest of the sequence is short: cp server/.env.sample server/.env, docker compose -f docker-compose-dev.yml up -d for the development database, pnpm server:db:init, then pnpm dev. A separate dev compose file exists because the production one is a deployment document rather than a development one.
Around those files sits the tooling a workspace of this size needs: pnpm-workspace.yaml with a packages/ directory filtered as @4gaboards/*, a tests/ directory at the root, eslint-configs/ next to eslint.config.mjs and stylelint.config.mjs, .prettierrc.json, renovate.json for dependency updates, and a helm-chart/ directory that lines up with the Kubernetes option among the four documented install routes.
Editorial conclusion
4ga Boards is a reasonable pick for a team that wants its board on its own infrastructure and is willing to run Postgres and Redis behind it. Before deploying, change the three published credentials, confirm that the volume names still match the service versions you intend to run, and read the restore section end to end, because the documented recovery path edits a superuser statement inside your own backup archive. If hosted software with a login is what you need, the same project also sells managed hosting, and nothing here argues against that.
Frequently asked questions
What is 4ga Boards and what is it built on?
A self-hosted kanban board system whose hierarchy is projects to boards to lists to cards to tasks. The client stack is React, Redux, Redux-Saga, Redux-ORM, react-beautiful-dnd and floating-ui, the server is Sails.js with Knex.js, and storage is PostgreSQL. It is MIT licensed.
What are the default login credentials for 4ga Boards?
Both the compose route and the development route end with default url http://localhost:3000, default user demo, default password demo. The compose file additionally ships POSTGRES_PASSWORD: notpassword, SECRET_KEY: notsecretkey, and a redis password of notredispassword, all of which the setup steps tell you to replace.
How do I install 4ga Boards?
Download docker-compose.yml with curl, edit BASE_URL, SECRET_KEY and the database passwords, then run docker compose up -d. Kubernetes, TrueNAS and manual install routes are documented as well, and a helm-chart/ directory in the repository corresponds to the Kubernetes one.
Does 4ga Boards sync with GitHub?
Not yet. Github 2-way sync appears in the feature list marked Coming soon. Import from Trello is available: add a project, then click Import while creating a new board.
How do I back up and restore a 4ga Boards instance?
Run ./boards-backup.sh from the directory holding docker-compose.yml, and restore with ./boards-restore.sh 4gaBoards-backup.tgz. The compose password has to match at restore time, and if it does not you are told to comment out the ALTER ROLE line in the postgres.sql file inside the archive first.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/rargames-4gaboards)