Merge pull request #73 from ArnasDon/chore/contributor-experience

chore: fork-first contributor docs + housekeeping
This commit is contained in:
Arnas Donauskas 2026-04-20 21:34:52 +03:00 committed by GitHub
commit 9c25971c27
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 536 additions and 1 deletions

13
.editorconfig Normal file
View File

@ -0,0 +1,13 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
# Markdown line breaks come from trailing spaces; don't strip them.
trim_trailing_whitespace = false

28
.github/CODE_OF_CONDUCT.md vendored Normal file
View File

@ -0,0 +1,28 @@
# Code of Conduct
This project adopts the **[Contributor Covenant, version 2.1][covenant]**.
By participating in this project — filing an issue, opening a PR, commenting
on one, or interacting in any other community space — you agree to uphold
that standard.
## Reporting
If you witness or experience behaviour that violates the Code, please
report it privately to the project maintainer:
- Email: **a.donauskas@hostinger.com** with `[WaCRM conduct]` in the
subject.
Reports are handled confidentially. Expect an acknowledgement within
72 hours and a decision on next steps within a week.
## Enforcement
The maintainer is responsible for enforcement and will apply the community
impact guidelines described in the [Contributor Covenant][covenant-enforce]
— ranging from a private correction to a permanent ban, proportional to the
behaviour.
[covenant]: https://www.contributor-covenant.org/version/2/1/code_of_conduct/
[covenant-enforce]: https://www.contributor-covenant.org/version/2/1/code_of_conduct/#enforcement-guidelines

76
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@ -0,0 +1,76 @@
name: Bug report
description: Something in WaCRM isn't working the way the docs say it should.
title: "[bug] "
labels: ["bug", "triage"]
body:
- type: markdown
attributes:
value: |
Thanks for reporting! The more specific you can be, the faster we
can land a fix.
**Not a bug in the code?** If this is a security issue, close this
form and follow [SECURITY.md](https://github.com/ArnasDon/wacrm/blob/main/.github/SECURITY.md)
instead.
- type: textarea
id: summary
attributes:
label: What happened?
description: One or two sentences describing the symptom.
placeholder: Clicking a conversation leaves the thread stuck on "No messages yet".
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce
description: The minimum steps we need to trigger the bug on our side.
placeholder: |
1. Sign in, go to /inbox.
2. Click any conversation that has past messages.
3. Thread pane shows "No messages yet" until hard refresh.
validations:
required: true
- type: textarea
id: expected
attributes:
label: What did you expect?
placeholder: Messages load the first time, every time.
validations:
required: true
- type: input
id: version
attributes:
label: Commit / version
description: |
The commit SHA or release you're on. `git rev-parse --short HEAD`
in the fork works.
placeholder: "e.g. d6a4677 or v0.2.0"
validations:
required: false
- type: dropdown
id: runtime
attributes:
label: Where is it running?
options:
- Local dev (npm run dev)
- Hostinger Managed Node.js
- Hostinger VPS
- Vercel
- Other Node host
validations:
required: false
- type: textarea
id: logs
attributes:
label: Logs / screenshots
description: Server logs, browser console errors, network tab — anything that looks suspicious. Scrub tokens before pasting.
render: text
validations:
required: false

11
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,11 @@
blank_issues_enabled: false
contact_links:
- name: Security vulnerability (private)
url: https://github.com/ArnasDon/wacrm/security/advisories/new
about: Do not file security issues in public. Follow the private disclosure flow.
- name: Setup / "how do I..." questions
url: https://github.com/ArnasDon/wacrm/blob/main/docs/README.md
about: Check the docs first — setup, deploy, troubleshooting are all covered.
- name: Using WaCRM as a template (forking)
url: https://github.com/ArnasDon/wacrm/blob/main/CONTRIBUTING.md
about: WaCRM is a template. Most changes belong in your fork, not an upstream issue — here's how that works.

View File

@ -0,0 +1,68 @@
name: Feature request
description: Propose a new feature or a meaningful enhancement.
title: "[feat] "
labels: ["enhancement", "triage"]
body:
- type: markdown
attributes:
value: |
Thanks for the idea — but read this first.
WaCRM is a **template**, not a collaborative product. The
upstream scope is intentionally narrow, so most feature
requests end up as *"build this in your fork"* rather than
landing here. That's the point of a template.
When an upstream feature request *is* useful:
- It fixes a correctness problem in the template.
- It makes the template cleaner for the next forker (reducing
friction, removing footguns).
- It's in scope for "a generic WhatsApp CRM template" rather
than a bet on your specific workflow.
If the feature is really for your own deployment, fork and
build it there — see
[CONTRIBUTING.md](https://github.com/ArnasDon/wacrm/blob/main/CONTRIBUTING.md).
- type: textarea
id: problem
attributes:
label: What's the problem?
description: What are you trying to do today that WaCRM makes harder than it should?
placeholder: |
When a broadcast ends I have no way to see which recipients
didn't reply so I can follow up manually.
validations:
required: true
- type: textarea
id: proposal
attributes:
label: What would you like to see?
description: Describe the feature from the user's perspective, not the implementation.
placeholder: |
On the broadcast detail page, a "No reply" filter that lists
recipients who received but didn't reply within 24 hours.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives you considered
description: Things that kinda work today, workarounds, related features in other tools.
validations:
required: false
- type: dropdown
id: scope
attributes:
label: Scope
description: Your guess — we'll re-scope if needed.
options:
- Small (a couple of hours)
- Medium (a couple of days)
- Large (a couple of weeks, probably breaks into multiple PRs)
validations:
required: false

53
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,53 @@
version: 2
updates:
# Runtime + dev dependencies. Weekly on Mondays — keeps the noise
# predictable and aligns with a normal review cycle.
- package-ecosystem: npm
directory: "/"
schedule:
interval: weekly
day: monday
open-pull-requests-limit: 5
reviewers:
- ArnasDon
labels:
- dependencies
groups:
# Batch related upgrades into one PR so we're not closing six
# independent Supabase-bumps per week.
supabase:
patterns:
- "@supabase/*"
types:
patterns:
- "@types/*"
update-types:
- minor
- patch
dev-dependencies:
dependency-type: development
update-types:
- minor
- patch
ignore:
# Next + React + Tailwind are pinned exactly on purpose. Let
# them flow through manual major bumps when we're ready.
- dependency-name: next
- dependency-name: react
- dependency-name: react-dom
- dependency-name: tailwindcss
- dependency-name: eslint-config-next
# GitHub Actions in .github/workflows/. Catches setup-node /
# checkout version bumps that keep the CI matrix healthy.
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
day: monday
open-pull-requests-limit: 3
reviewers:
- ArnasDon
labels:
- dependencies
- github-actions

42
.github/pull_request_template.md vendored Normal file
View File

@ -0,0 +1,42 @@
<!--
Heads up: WaCRM is a template, not a collaborative product. Most
changes belong in your fork. See CONTRIBUTING.md for which kinds of
upstream PRs tend to land (security, correctness, docs) vs. which
belong in a fork (new features, stack swaps, opinionated refactors).
If you haven't opened an issue yet for a non-trivial change, consider
doing that first to check alignment.
Keep this short and specific. The commit message is where the "why"
lives; this is where the reviewer gets the "what" and "how to try it".
-->
## Summary
<!-- One or two sentences. What does this PR do? -->
## What changed
<!-- Bullet list of the actual changes. Link file paths when useful. -->
## Test plan
<!--
How did you verify this works? How should the reviewer verify it?
Tick the boxes as you go.
-->
- [ ] `npm run typecheck` clean.
- [ ] `npm run lint` — no new errors beyond the pre-existing backlog.
- [ ] `npm run build` succeeds.
- [ ] Feature / fix manually exercised in the browser (or the reason it can't be).
## Related
<!-- Link the issue this closes, or "Part of #N" for multi-PR work. -->
<!--
Heads up:
- Security issues: do not disclose here; see .github/SECURITY.md.
- New deps: please justify briefly in the commit message or PR body.
- Runtime behaviour changes affecting forkers: update docs/*.
-->

9
.prettierignore Normal file
View File

@ -0,0 +1,9 @@
node_modules
.next
out
build
coverage
next-env.d.ts
package-lock.json
# Generated / vendored
supabase/migrations

10
.prettierrc Normal file
View File

@ -0,0 +1,10 @@
{
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 80,
"tabWidth": 2,
"arrowParens": "always",
"endOfLine": "lf",
"plugins": ["prettier-plugin-tailwindcss"]
}

124
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,124 @@
# Using WaCRM
WaCRM is a **template repository**, not a collaborative product. The
expected flow is:
1. **Fork** it to your own GitHub account or organisation.
2. **Deploy** the fork — see [`docs/`](./docs/README.md).
3. **Customise** your fork. Rebrand, add the features you need, remove
the ones you don't, swap hosting, change the schema.
You **don't** need to send changes back upstream. The fact that your
fork diverges is the whole point — the upstream is deliberately
opinionated about stack, UX, and scope, and your fork is where those
opinions become yours.
## Fork and run
```bash
# 1. Fork on GitHub: https://github.com/ArnasDon/wacrm → Fork
# 2. Clone your fork
git clone https://github.com/<your-username>/wacrm.git
cd wacrm
cp .env.local.example .env.local # fill in Supabase + Meta creds
npm install
npm run dev
```
Full setup (Supabase migrations, WhatsApp Business API, deploy) lives in
[`docs/`](./docs/README.md).
## Keeping your fork up to date
Pull in upstream bug fixes and security patches periodically:
```bash
git remote add upstream https://github.com/ArnasDon/wacrm.git # once
git fetch upstream
git checkout main
git merge upstream/main # or: git rebase upstream/main
# Resolve any conflicts (likely in areas you've customised), then push
git push origin main
```
If you've made heavy local customisations, rebasing can surface
conflicts every time you pull. Pinning to a specific upstream tag and
updating on your schedule is a valid alternative.
## Reporting bugs in the upstream template
If you find a bug in the upstream code — not one you introduced in your
fork — please file it using the
[bug report](https://github.com/ArnasDon/wacrm/issues/new?template=bug_report.yml)
template. Including the commit SHA, the runtime (Hostinger / Vercel /
local / other), and logs will get to a fix fastest.
## Reporting security issues
**Do not file security issues publicly.** Follow the private flow in
[SECURITY.md](./.github/SECURITY.md).
## Upstream pull requests
Not the primary flow, but welcome in specific cases:
- **Security fixes** — always welcome, please follow SECURITY.md first
for disclosure.
- **Bug fixes** that match upstream intent (crash, correctness,
documentation errors, typos) — land quickly.
- **Small improvements** (accessibility, obvious UX nits) — usually
welcome, open an issue first to check alignment.
Less likely to land:
- **New features.** The template's scope is intentionally narrow. A
"great idea for a CRM" is often a great idea for *your* CRM — i.e.
your fork — but would dilute the template for the next forker.
- **Stack changes** (different ORM, different UI kit, different auth
provider). These belong in a fork, not upstream.
- **Opinionated refactors** without a concrete correctness or
performance motivation.
If you do send a PR, the usual rules apply:
- Branch off the latest `main` (don't push to a merged branch — commits
end up orphaned).
- Run `npm run typecheck` and `npm run format` locally first.
- Fill in the PR template, especially the **Test plan**.
- One logical change per PR.
- Commit-message first line is imperative + terse; the body explains
the *why*, the diff shows the *what*.
Expect a review within a few days. PRs opened without an issue may be
closed — open the issue first to align.
## If you maintain a public fork
- Rebrand. The WaCRM name, favicon, and `wacrm.tech` URL belong to the
upstream project; please swap them for your own before putting your
deployment in front of users.
- Keep the MIT [`LICENSE`](./LICENSE) file — that's how the template's
permissions travel with the code. Attribution in a `README` section
is appreciated but not required.
- You are free to re-license additions to your fork however you like.
## Dev-loop reference
Even if you never send a PR upstream, these are the scripts you'll use
in your fork:
| Command | What it does |
| --- | --- |
| `npm run dev` | Turbopack dev server on port 3000. |
| `npm run build` | Production build. Next also runs its own typecheck here. |
| `npm run typecheck` | `tsc --noEmit`. Fast TS-only pass. |
| `npm run lint` | ESLint. |
| `npm run format` | Prettier write. |
| `npm run format:check` | Prettier in check-only mode. Useful in CI. |
## Licensing
This template is MIT ([`LICENSE`](./LICENSE)). Anything you contribute
upstream is assumed to be MIT too. Your fork's additions are yours to
license however you like.

97
package-lock.json generated
View File

@ -35,6 +35,8 @@
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "16.2.4",
"prettier": "^3.8.3",
"prettier-plugin-tailwindcss": "^0.7.2",
"tailwindcss": "^4",
"typescript": "^5"
},
@ -7939,6 +7941,101 @@
"node": ">= 0.8.0"
}
},
"node_modules/prettier": {
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz",
"integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prettier-plugin-tailwindcss": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.7.2.tgz",
"integrity": "sha512-LkphyK3Fw+q2HdMOoiEHWf93fNtYJwfamoKPl7UwtjFQdei/iIBoX11G6j706FzN3ymX9mPVi97qIY8328vdnA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=20.19"
},
"peerDependencies": {
"@ianvs/prettier-plugin-sort-imports": "*",
"@prettier/plugin-hermes": "*",
"@prettier/plugin-oxc": "*",
"@prettier/plugin-pug": "*",
"@shopify/prettier-plugin-liquid": "*",
"@trivago/prettier-plugin-sort-imports": "*",
"@zackad/prettier-plugin-twig": "*",
"prettier": "^3.0",
"prettier-plugin-astro": "*",
"prettier-plugin-css-order": "*",
"prettier-plugin-jsdoc": "*",
"prettier-plugin-marko": "*",
"prettier-plugin-multiline-arrays": "*",
"prettier-plugin-organize-attributes": "*",
"prettier-plugin-organize-imports": "*",
"prettier-plugin-sort-imports": "*",
"prettier-plugin-svelte": "*"
},
"peerDependenciesMeta": {
"@ianvs/prettier-plugin-sort-imports": {
"optional": true
},
"@prettier/plugin-hermes": {
"optional": true
},
"@prettier/plugin-oxc": {
"optional": true
},
"@prettier/plugin-pug": {
"optional": true
},
"@shopify/prettier-plugin-liquid": {
"optional": true
},
"@trivago/prettier-plugin-sort-imports": {
"optional": true
},
"@zackad/prettier-plugin-twig": {
"optional": true
},
"prettier-plugin-astro": {
"optional": true
},
"prettier-plugin-css-order": {
"optional": true
},
"prettier-plugin-jsdoc": {
"optional": true
},
"prettier-plugin-marko": {
"optional": true
},
"prettier-plugin-multiline-arrays": {
"optional": true
},
"prettier-plugin-organize-attributes": {
"optional": true
},
"prettier-plugin-organize-imports": {
"optional": true
},
"prettier-plugin-sort-imports": {
"optional": true
},
"prettier-plugin-svelte": {
"optional": true
}
}
},
"node_modules/pretty-ms": {
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz",

View File

@ -32,7 +32,9 @@
"build": "next build",
"start": "next start",
"lint": "eslint",
"typecheck": "tsc --noEmit"
"typecheck": "tsc --noEmit",
"format": "prettier --write .",
"format:check": "prettier --check ."
},
"dependencies": {
"@base-ui/react": "^1.4.0",
@ -61,6 +63,8 @@
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "16.2.4",
"prettier": "^3.8.3",
"prettier-plugin-tailwindcss": "^0.7.2",
"tailwindcss": "^4",
"typescript": "^5"
}