Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
76fb9cd
Legacy
wordspherellc Jun 8, 2025
9105d62
feat: force dinamic and getBaseUrl changes
seneka-DSNA Jul 18, 2026
7cb85b2
feat: getBaseUrl changes
seneka-DSNA Jul 18, 2026
18d5799
add .gitignore
seneka-DSNA Jul 21, 2026
c4802ae
mod: .gitignore
seneka-DSNA Jul 21, 2026
485e0ca
fix: npm audit fix not breaking
seneka-DSNA Jul 21, 2026
95913f8
fix: npm audit fix package.json and -lock
seneka-DSNA Jul 22, 2026
0814dc6
add: .eslintrc.json with linter config
seneka-DSNA Jul 22, 2026
02f2f65
add: Pipeline workflows and dependabot .github dir
seneka-DSNA Jul 22, 2026
eb207b3
add: Linter check needs DEV validation SECURITY_DEBT.md info to fix
seneka-DSNA Jul 22, 2026
49d532c
mod: workflow to continue-on-error TypeCheck but needs review
seneka-DSNA Jul 22, 2026
0a0a0af
mod: workflow to format:write add
seneka-DSNA Jul 22, 2026
8dcb6f6
Merge pull request #2 from seneka-DSNA/main
seneka-DSNA Jul 24, 2026
93774db
add: vercel deploy ci/cd try
seneka-DSNA Jul 24, 2026
313c9ad
Merge pull request #3 from seneka-DSNA/main
seneka-DSNA Jul 24, 2026
ac0f4d2
Force pipeline
seneka-DSNA Jul 24, 2026
28f4c17
Update ci.yaml
seneka-DSNA Jul 26, 2026
341702f
Fix: ci.yml workflow
seneka-DSNA Jul 26, 2026
4452607
fix: ci.yml workflow
seneka-DSNA Jul 26, 2026
a9939aa
fix: ci.yml workflow
seneka-DSNA Jul 26, 2026
886a299
fix: ci.yml workflow
seneka-DSNA Jul 26, 2026
dd62d79
Update ci.yaml
seneka-DSNA Jul 26, 2026
cc27db2
Update ci.yaml
seneka-DSNA Jul 26, 2026
3376cbc
Update: README.md for dev install
seneka-DSNA Jul 26, 2026
86096c8
Update README.md
seneka-DSNA Jul 26, 2026
64cecfa
fix: prevent regex injection by using mongo filter and add unique id …
mph7 Jul 29, 2026
043a102
Merge pull request #7 from evuventures/fix/lint-security-cleanup
seneka-DSNA Jul 30, 2026
621a198
Fix: Typecheck bugs
mph7 Jul 30, 2026
9163b54
Merge pull request #12 from evuventures/fix-typecheck-bugs
seneka-DSNA Jul 31, 2026
1b7785f
fix: correct commisson_rate schema typo mismatch and invalid String t…
azlaan428 Aug 5, 2026
0de80a7
fix: correct commisson_rate schema typo mismatch and invalid String t…
azlaan428 Aug 5, 2026
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
9 changes: 9 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": [
"next/core-web-vitals",
"plugin:security/recommended-legacy"
],
"plugins": [
"security"
]
}
18 changes: 18 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
groups:
minor-and-patch:
update-types: ["minor", "patch"]
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-major"]

- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
64 changes: 64 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: CI

on:
pull_request:
branches: [main, stag]
push:
branches: [main, stag]

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install Dependencies
run: npm ci

- name: Lint
run: npm run lint

- name: Type Check
run: npm run typecheck
continue-on-error: true

- name: Write Format
run: npm run format:write

- name: Check Format
run: npm run format:check

- name: Build
run: npx vercel build --yes
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
MONGODB_URI: ${{ secrets.MONGODB_URI }}
NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
NEXTAUTH_URL: ${{ secrets.NEXTAUTH_URL }}
NEXT_PUBLIC_SALESFAM_API_KEY: ${{ secrets.NEXT_PUBLIC_SALESFAM_API_KEY }}
RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}

secrets-scan:
runs-on: ubuntu-latest
container: zricethezav/gitleaks:latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Escanear secretos
run: gitleaks detect --source=. --verbose --redact
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.env
.env*.local
node_modules/
.next/
out/
coverage/
.vercel
*.tsbuildinfo
npm-debug.log*
.DS_Store
130 changes: 129 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,129 @@
#SALESFAM SALESFAM
# Sales Fam

Unleash Your Sales Potential with Sales Fam — a Next.js 14 (App Router) CRM/sales platform for managing companies, clients, projects, invoices, sales meetings, commissions, and contracts.

## Tech Stack

- **Framework:** Next.js 14 (App Router), React 18, TypeScript
- **Database:** MongoDB via Mongoose
- **Auth:** NextAuth (Credentials provider + JWT sessions)
- **UI:** Tailwind CSS, Radix UI, shadcn/ui, lucide-react
- **File uploads:** Multer + Cloudinary
- **Email:** Resend
- **Forms/validation:** react-hook-form + zod

## Prerequisites

- **Node.js 20.x** (matches the CI pipeline in [.github/workflows/ci.yaml](.github/workflows/ci.yaml))
- **npm** (comes with Node)
- A **MongoDB** connection string (a free [MongoDB Atlas](https://www.mongodb.com/cloud/atlas) cluster works fine)
- A **Cloudinary** account (for avatar/image uploads)
- A **Resend** account (for transactional emails) — optional for basic local development, required for any feature that sends emails (invitations, notifications, password reset, etc.)

## Getting Started

### 1. Clone and install dependencies

```bash
git clone <repo-url>
cd Salesfam_Org
npm install
```

### 2. Configure environment variables

Create a `.env` file at the project root (it is already git-ignored). Copy the template below and fill in your own values:

```bash
# --- MongoDB ---
# Connection string to your MongoDB cluster/database
MONGODB_URI=mongodb+srv://<user>:<password>@<cluster-url>/?appName=<app-name>

# --- NextAuth ---
# Random secret used to sign/encrypt session tokens.
# Generate one with: openssl rand -base64 32
NEXTAUTH_SECRET=<random-secret>
# Canonical URL of the app (required by NextAuth internally in some flows)
NEXTAUTH_URL=http://localhost:8080
# Public URL exposed to the client (used to build invite/signup links)
NEXT_PUBLIC_NEXTAUTH_URL=http://localhost:8080

# --- App / API base URL ---
# Used server-side to build absolute URLs (e.g. for server components/fetches)
NEXT_PUBLIC_API_URL=http://localhost:8080

# --- Resend (transactional email) ---
RESEND_API_KEY=<your-resend-api-key>

# --- Misc / app-specific ---
# Email treated as the platform admin/superadmin (used in project & contract flows)
NEXT_PUBLIC_ADMIN_EMAIL=<admin-email>
# API key used to identify/authorize the Sales Fam public API surface
NEXT_PUBLIC_SALESFAM_API_KEY=<any-string-locally>
```

> **Never commit `.env`.** It already contains real credentials pointing at a live database — treat it as a secret file, not a template.

### 3. Run the app in development mode

```bash
npm run dev
```

The dev server starts on **http://localhost:8080** (custom port set in [package.json](package.json)).

### 4. Log in / create a user

There is no seed script yet. To get a working account, either:
- Use the `/signup` page in the browser, or
- Insert a user document directly into the `users` collection in MongoDB (with a `bcrypt`-hashed `password` field, matching [models/user.js](models/user.js) and the credentials check in [app/api/auth/[...nextauth]/route.js](app/api/auth/%5B...nextauth%5D/route.js)).

## Available npm Scripts

| Script | Command | Description |
| --- | --- | --- |
| `npm run dev` | `next dev -p 8080` | Start the local dev server with hot reload on port 8080 |
| `npm run build` | `next build` | Create a production build |
| `npm run start` | `next start` | Serve the production build (run `build` first) |
| `npm run preview` | `next build && next start -p 8081` | Build and serve production output locally on port 8081 |
| `npm run lint` | `next lint` | Run ESLint |
| `npm run lint:fix` | `next lint --fix` | Run ESLint and auto-fix issues |
| `npm run typecheck` | `tsc --noEmit` | Run the TypeScript compiler in check-only mode |
| `npm run format:write` | `prettier --write "**/*.{ts,tsx,mdx}" --cache` | Format code with Prettier |
| `npm run format:check` | `prettier --check "**/*.{ts,tsx,mdx}" --cache` | Check formatting without writing changes |

## Project Structure

```
app/ Next.js App Router pages and API routes (app/api/**)
components/ Reusable React components (incl. shadcn/ui primitives)
config/ Static site configuration (name, description, nav)
lib/ Server/client utilities: MongoDB connection, Cloudinary, email, data fetching
middleware.js Route protection based on NextAuth session cookie
models/ Mongoose schemas (client, company, invoice, project, salesMetting, user)
public/ Static assets
styles/ Global styles
types/ Shared TypeScript types
```

## Authentication & Route Protection

[middleware.js](middleware.js) guards routes such as `/dashboard`, `/project`, `/settings`, `/sales`, `/api/**`, etc. Unauthenticated requests to protected routes are redirected to `/`; authenticated users hitting `/login` or `/signup` are redirected to `/dashboard`. Auth state is read from the `next-auth.session-token` / `__Secure-next-auth.session-token` cookie, so `NEXTAUTH_SECRET` must be set for sessions to validate correctly.

## Working on Features / Fixes

1. Create a branch from `main`.
2. Run `npm run dev` and reproduce/verify against `http://localhost:8080`.
3. Before opening a PR, run the same checks CI runs (see [.github/workflows/ci.yaml](.github/workflows/ci.yaml)):
```bash
npm run lint
npm run typecheck
npm run format:check
```
4. Check [SECURITY_DEBT.md](SECURITY_DEBT.md) for known, accepted risks before "fixing" something that's already tracked there.
5. CI also runs a `gitleaks` secrets scan — never commit `.env` or any real credentials.

## Notes

- `next.config.mjs` currently sets `typescript.ignoreBuildErrors: true`, so `npm run build` will succeed even with type errors — always run `npm run typecheck` separately.
- Image uploads only work for remote hosts `img.youtube.com` and `res.cloudinary.com` (see `images.remotePatterns` in [next.config.mjs](next.config.mjs)); adding another image source requires updating that list.
26 changes: 26 additions & 0 deletions SECURITY_DEBT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Known Security Debt

## 🟢 Fixed

### 1. Regex Injection / ReDoS in Company Search
- **File:** `app/api/company/route.js:120`
- **Risk:** `companyName` is received unsanitized from a query parameter and concatenated into a `RegExp`. This allows for ReDoS (server hang) and exact match bypass.
- **Suggested Fix:** Escape special regex characters before building the `RegExp`, or use an exact Mongo filter instead of `$regex`.
- **Detected by:** `eslint-plugin-security` (`detect-non-literal-regexp`), does not block CI (severity: warning).
- **Fix Applied:** Changed the previous regex to a Mongo filter and this way prevent Regex Injection and ReDoS

### 2. List Elements Without `key` (5 instances)
- **Files:** `app/settings/manage-contracts/AddContract.tsx:144`, `EditContract.tsx:156`, `components/ContractTable.jsx:99`, `components/datatable.tsx:363`, `components/datatableSeller1.tsx:275`
- **Risk:** Not a security issue — it is a React bug that can cause incorrect rendering when reordering/updating lists.
- **Suggested Fix:** Add `key={unique-id}` to each iterated element.
- **Note:** Temporarily downgraded to a warning via `eslint-disable-next-line` to avoid blocking the pipeline — see comments in each file.
- **Fix Applied:** Added a unique id key to each of the iterated element

## 🟢 Reviewed — False Positive, No Action Required

- `components/ResetPassword.tsx:29`, `components/SetPassword.tsx:34` — Comparison between two fields of the same form, not between a secret and a stored value. No remote attacker can measure timing here.
- `components/TabComponent.tsx:23` — The index used never comes from user input, only from the `tabs` array itself rendered by the component.

## Recommended run 'npm run lint' to see other needs

- `grep -rn "eslint-disable" --include="*.tsx" --include="*.jsx" --include="*.js" .` run it eventually to check not documented bypassed lines.
7 changes: 7 additions & 0 deletions app/Providers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"use client"

import { SessionProvider } from "next-auth/react"

export const AuthProvider = ({ children }) => {
return <SessionProvider>{children}</SessionProvider>
}
Loading
Loading