Detailed setup, workflow, conventions, and deployment reference.
| Tool | Version | Notes |
|---|---|---|
| Node.js | v22 | See .nvmrc |
| Firebase CLI | Latest | npm install -g firebase-tools |
| Git | Any recent |
git clone https://github.com/scriptbuzz/gonow-app.git
cd gonow-app
npm installcp .env.example .envFill in the values from:
- Firebase Console → Project Settings → Your Apps → Web App config
- Google Cloud Console → APIs & Services → Credentials (Maps API key)
npm run dev # http://localhost:3000git pull origin main # Always pull first
npm install # Install any new dependencies
npm run dev # Start dev serverOr use the sync script (checks Node version, pulls, installs):
npm run dev-syncgonow-app/
├── components/ React components (PascalCase)
│ ├── App/ AppHeader, Sidebar
│ ├── RouteEditor/ Route editor sub-components
│ ├── UI/ Reusable UI primitives
│ ├── reports/ Report sub-components
│ └── app-status/ System health sub-components
├── contexts/ React Context providers
├── hooks/ Custom React hooks
├── services/ Firebase data access layer
├── functions/ Cloud Functions (Node 22, TypeScript)
│ └── src/ Function source files
├── scripts/ Dev automation (deploy, seed, test runner)
├── tests/ Vitest unit/component tests
├── cypress/ Cypress E2E tests
├── locales/ i18n JSON files (en.json, ar.json)
├── docs/ Architecture, PRD, data model
├── types.ts All TypeScript types and enums
├── constants.ts App-wide constants
├── App.tsx Root component and tab router
└── index.tsx React entry point
- Strict mode enabled — no
anyunless genuinely necessary - All domain types defined in
types.ts - Use enums from
types.tsinstead of magic strings (e.g.,Role.MANAGER, not'MANAGER')
- File names:
PascalCase.tsx - One component per file
- Props interfaces defined inline or at top of file
- File names:
camelCase.ts - Hooks prefix:
use(e.g.,useAppState) - Services are plain exported objects or functions — no class instances unless required
- All user-visible strings go through
useTranslation()— no hardcoded English strings in JSX - Add keys to both
locales/en.jsonandlocales/ar.jsontogether
- Use the service layer (
services/) — do not calldbdirectly from components - All list queries must use cursor-based pagination (see
CustomerService.getPaginated) - Search fields must use the
searchKeypattern (lowercase name stored alongside)
Use the shared SearchInput component for all list filtering:
import { SearchInput } from './SearchInput';
<SearchInput
value={searchTerm}
onChange={setSearchTerm}
placeholder={t('module.searchPlaceholder')}
className="flex-1 min-w-[200px]"
/>Backend search uses a searchKey field (stored as name.toLowerCase()) with a Firestore range query:
const q = query(
collection(db, 'users'),
where('searchKey', '>=', term.toLowerCase().trim()),
where('searchKey', '<=', term.toLowerCase().trim() + '\uf8ff')
);- Always debounce search inputs (500ms) to limit read operations
- Always
.trim()input to handle copy-paste whitespace - If the search term is empty, revert to the default paginated view
- When creating or updating a document with a
namefield, always writesearchKey: name.toLowerCase()alongside it
npm test # Run once
npm test -- --watch # Watch mode
npx vitest run --coverage # With coverage reportTests live in tests/. Component tests use @testing-library/react and jsdom.
npm run test:e2e # Headless
npm run test:e2e:headed # With browser visibleEnsure TEST_USER_PASSWORD is set in .env and the test user exists:
tsx scripts/ensure-test-user.ts- Log in as Administrator
- Navigate to Settings → Maintenance → Seed Data
- Configure: city, industry, customer count, history window
- Click Seed — triggers the
reseedCloud Function
Or seed users only via script:
tsx scripts/seedUsers.tsSee DEPLOYMENT.md for the full deployment guide — Firebase project setup, environment config, first deploy, and troubleshooting.
Quick reference for ongoing deployments:
npm run deploy # Full deploy (version bump + build + Firebase)
npx firebase deploy --only hosting # Frontend only
npx firebase deploy --only functions # Cloud Functions only
npx firebase deploy --only firestore:rules # Firestore rules only
npx firebase deploy --only storage # Storage rules onlyTest rules locally with the emulator:
npx firebase emulators:startEmulator ports: Auth 9099 · Firestore 8080 · Functions 5001 · Hosting 5000
- Create
components/MyModule.tsx - Add a tab entry in
components/App/Sidebar.tsxwith a role gate - Add the tab case in
App.tsxrender logic - Add Firestore queries in a new service file under
services/ - Add types to
types.ts - Add i18n keys to both
locales/en.jsonandlocales/ar.json - Write tests in
tests/MyModule.test.tsx
Version is stored in package.json and shown in the About section. Incremented automatically by npm run deploy. To bump manually:
npm run increment-version# Build functions only
npm --prefix functions run build
# Deploy functions only
npx firebase deploy --only functions
# Local emulator
npx firebase emulators:start --only functions,firestore,authFunction source: functions/src/
Compiled output: functions/lib/ (gitignored)