From 648344a2c94e5c9a6c9a8402e172944aa6a6f8c4 Mon Sep 17 00:00:00 2001 From: omprakash kumar Date: Fri, 10 Apr 2026 22:37:20 +0530 Subject: [PATCH 1/4] docs: add development setup overview for contributors (#14132) Adds a minimal development setup overview section, including native and Docker-based approaches for running NodeBB locally. This does not replace existing documentation but provides a quick entry point for contributors. --- README.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/README.md b/README.md index dbf2ff306f..e508592149 100644 --- a/README.md +++ b/README.md @@ -43,12 +43,49 @@ NodeBB requires the following software to be installed: * MongoDB, version 5 or greater **or** Redis, version 7.2 or greater * If you are using [clustering](https://docs.nodebb.org/configuring/scaling/) you need Redis installed and configured. * nginx, version 1.3.13 or greater (**only if** intending to use nginx to proxy requests to a NodeBB) +* (Optional) [Docker](https://docs.docker.com/get-docker/) for container-based setup +> Installation steps vary by operating system. Please follow the official documentation links above. + ## Installation [Please refer to platform-specific installation documentation](https://docs.nodebb.org/installing/os). If installing via the cloud (or using Docker), [please see cloud-based installation documentation](https://docs.nodebb.org/installing/cloud/). +## Development Setup Overview + +> NodeBB uses a CLI-based setup and does not run via standard `npm start`. + +You can run NodeBB locally in two ways: + +### Option 1: Native Setup (Recommended for Beginners & Contributors) + +This approach helps you understand how NodeBB works internally. + +**Basic flow:** +1. Clone the repository ```` https://github.com/NodeBB/NodeBB.git ```` +2. Run the setup script ```` cd NodeBB ```` ```` ./nodebb setup ```` +3. Start the application ```` ./nodebb start ```` + +**During setup, you will configure:** + - Database (MongoDB / Redis) + - Admin account + - Port (default: 4567) + +### Option 2: Docker Setup (Quick & Isolated) + +> Requires Docker to be installed: https://docs.docker.com/get-docker/ + +Run: + +```bash +docker-compose up +```` + +This will start NodeBB along with required services at: ```` http://localhost:4567 ```` + +**For more details, see: https://docs.nodebb.org** + ## Securing NodeBB It is important to ensure that your NodeBB and database servers are secured. Bear these points in mind: From 15d65943fb178e7446f498065d608cd9fd403ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20U=C5=9Fakl=C4=B1?= Date: Fri, 10 Apr 2026 13:05:29 -0400 Subject: [PATCH 2/4] test: fix unread deleted topic test (#14164) instead of posting and immediately deleting, add a deleted param to topics.post which deletes the topic before sending notifications --- src/topics/create.js | 7 ++++--- test/topics.js | 10 ++++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/topics/create.js b/src/topics/create.js index d2b709333c..ef94fdaf42 100644 --- a/src/topics/create.js +++ b/src/topics/create.js @@ -167,14 +167,15 @@ module.exports = function (Topics) { topicData.index = 0; postData.index = 0; - if (topicData.scheduled) { - await Topics.delete(tid); + if (data.deleted || topicData.scheduled) { + await Topics.delete(tid, uid); + topicData.deleted = true; } analytics.increment(['topics', `topics:byCid:${topicData.cid}`]); plugins.hooks.fire('action:topic.post', { topic: topicData, post: postData, data: data }); - if (!topicData.scheduled) { + if (!topicData.scheduled && !topicData.deleted) { setImmediate(async () => { try { if (utils.isNumber(uid)) { diff --git a/test/topics.js b/test/topics.js index f67e0fc40e..479167717a 100644 --- a/test/topics.js +++ b/test/topics.js @@ -1420,8 +1420,14 @@ describe('Topic\'s', () => { it('should not return topic as unread if topic is deleted', async () => { const uid = await User.create({ username: 'regularJoe' }); - const result = await topics.post({ uid: adminUid, title: 'deleted unread', content: 'not unread', cid: categoryObj.cid }); - await topics.delete(result.topicData.tid, adminUid); + const result = await topics.post({ + uid: adminUid, + title: 'deleted unread', + content: 'not unread', + cid: categoryObj.cid, + deleted: 1, + }); + const unreadTids = await topics.getUnreadTids({ cid: 0, uid: uid }); await sleep(2000); From ab6d462becbf20d3d3ecee7eefeac9162f55702d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 10 Apr 2026 16:27:47 -0400 Subject: [PATCH 3/4] test: another delete after create --- test/categories.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/categories.js b/test/categories.js index 40c3039310..c204a00768 100644 --- a/test/categories.js +++ b/test/categories.js @@ -197,13 +197,13 @@ describe('Categories', () => { content: 'The content of test topic', tags: ['nodebb'], }); - const data = await Topics.post({ + await Topics.post({ uid: posterUid, cid: categoryObj.cid, title: 'will delete', content: 'The content of deleted topic', + deleted: 1, }); - await Topics.delete(data.topicData.tid, adminUid); }); it('should get recent replies in category', (done) => { From ac8bad8bc95394e27445b696515e3d115373bca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 10 Apr 2026 16:43:14 -0400 Subject: [PATCH 4/4] test: set thumbs during topic.post --- test/topics/thumbs.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/topics/thumbs.js b/test/topics/thumbs.js index 85517588a0..657a2e7e60 100644 --- a/test/topics/thumbs.js +++ b/test/topics/thumbs.js @@ -64,15 +64,11 @@ describe('Topic thumbs', () => { cid: categoryObj.cid, title: 'Test Topic Title', content: 'The content of test topic', + thumbs: [relativeThumbPaths[0]], }); // Touch a couple files and associate it to a topic createFiles(); - - await topics.setTopicFields(topicObj.topicData.tid, { - numThumbs: 1, - thumbs: JSON.stringify([relativeThumbPaths[0]]), - }); }); it('should return bool for whether a thumb exists', async () => {