Car rental platforms typically require stitching together a customer-facing web app, a mobile app, an admin backend, and payment processing—each with its own stack and deployment story. BookCars packages all four into one repository, so an operator gets a single source for fleet management, bookings, and payments without building integrations from scratch.
What This Does
BookCars is a full car rental platform with five self-contained projects: admin/ (339 files) for fleet and booking management, frontend/ (268 files) for customer web booking, mobile/ (135 files) for a React Native app, backend/ (123 files) for the API, and packages/ (41 files) for shared code. It supports Stripe and PayPal payment gateways and both single-supplier and multi-supplier modes.
The backend exposes a REST API with controllers for bookings, users, and suppliers. The admin panel includes a scheduler component for managing availability. The mobile app is built with React Native and can be deployed via EAS (.easignore present).
How It Is Wired
Execution starts at backend/src/index.ts, which boots the Express server defined in backend/src/app.ts. That app wires routes to controllers like backend/src/controllers/bookingController.ts (876 lines—the largest file) and userController.ts. The most-connected module is backend/src/config/env.config.ts, which 64 modules import; changing it ripples across the entire backend.
The admin panel's scheduler is the other hotspot: admin/src/components/scheduler/hooks/useStore.ts (32 importers) and types.ts (27 importers) sit inside a circular dependency cycle with helpers/generals.tsx. That cycle means changing any one of those files requires understanding how the others re-import it.
The frontend and mobile apps call the backend API over HTTP. The stack uses npm workspaces with lockfiles at admin/, backend/, and frontend/ levels. Dockerfiles exist for admin/ and backend/.
How To Use It
Setup: Clone and install dependencies per project:
git clone https://github.com/moses-y/bookcars
cd bookcars/backend && npm install
cd ../admin && npm install
cd ../frontend && npm install
Configuration: Each project has an .env.example file (backend/.env.example, admin/.env.example) defining required variables—database connection, Stripe/PayPal keys, and the API URL. Copy these to .env and fill in values.
Running it: Start the backend first, then the frontend/admin:
cd backend && npm run dev
cd ../admin && npm run dev
cd ../frontend && npm run dev
Docker deployments are supported via admin/Dockerfile and backend/Dockerfile, with __config/nginx.conf for reverse proxying.
Real-World Use
A regional car rental operator deploys the backend and admin panel on a VPS, runs the frontend for customer bookings, and publishes the mobile app to app stores. The admin panel handles fleet management, the scheduler handles availability, and Stripe/PayPal handle payments. Multi-supplier mode lets independent operators each manage their own fleet through the same admin interface.
High - Circular imports in the admin scheduler (useStore.ts, types.ts, generals.tsx) make changes risky; extract shared types to break the cycle.
High - Hub modules: backend/src/config/env.config.ts has 64 dependents; keep it stable and small.
High - Duplicated code: 8,217 repeated 6-line blocks across 405 files, including deploy scripts and ESLint configs.
High - Oversized controllers: bookingController.ts and userController.ts exceed 800 lines each.
High - CI workflows use unpinned third-party actions (codecov/codecov-action@v5); pin to commit SHAs.
High - Wildcard CORS in backend/src/app.ts; replace with an explicit allow list.
High - bump-version.yml pushes directly to main; open a PR instead.
Medium - No Dependabot, no npm ci in CI, unpinned Docker base images, no non-root user in Dockerfiles, no dependency vulnerability scan.
The Bottom Line
BookCars is a complete, working car rental platform with real payment integration and a mobile app—substantial coverage for a single repository. The architecture is sound but the admin scheduler's circular dependencies and oversized controllers will make maintenance harder as the codebase grows. Suitable for operators who want a self-hosted platform rather than a SaaS subscription.
What the analyser found
Deployment readiness
7/7
✓Container image
✓CI pipeline
✓Lockfile committed
✓Test suite
✓README
✓License
✓No committed secrets
Composition
946 files
TSX327
TypeScript311
CSS142
JSON40
JavaScript16
YAML11
ReactExpressDocker
Module dependencies
The 10 most depended-upon modules of 654, from static import analysis. Red outline marks a module in an import cycle.
Ranked by severity × confidence × production reach. Reach is the honest discriminator across a collection that is mostly other people's code: the same finding matters more in something that ships.
high3
medium7
low2
Pin third-party GitHub Actions to a commit SHAhigh2 occurrences
A tag can be moved, so the action running with your token and secrets is whatever its owner last pushed; this is how tj-actions/changed-files leaked secrets from thousands of repos.
Fix: Replace each @vN with the 40-character commit SHA, keep # vN as a comment, and let Dependabot bump the SHAs.
Replace the wildcard CORS origin with an explicit allow listhigh
backend/src/app.ts
cors()
Any page on the internet can call the API with the browser's cookies attached, so a logged-in visitor to an unrelated site performs authenticated requests without knowing, and the wildcard combined with credentials is the exact configuration browsers refuse for that reason.
Fix: List the origins the API actually serves, and never pair a wildcard with credentials.
Open a pull request instead of pushing to the default branchhigh
.github/workflows/bump-version.yml
git push origin main
Automated commits land on the branch that deploys, with no test having run against the result.
Fix: Push to a bot branch and open a pull request, or restrict the push to a tag ref.
Declare least-privilege permissions for GITHUB_TOKENmedium2 occurrences
.github/workflows/build.yml
2 workflow(s) declare no permissions, 1 of them reference secrets
With no declaration the token inherits the repository default, so any injected step can push commits or mint releases from inside your own CI.
Fix: Add permissions: contents: read at the top of the workflow and widen per job only where needed.
Enable Dependabot or Renovatemedium
10 manifest(s), no update bot configured
Without a bot a published advisory sits unpatched until someone audits by hand, which across 1,322 repositories means never.
Fix: Commit .github/dependabot.yml covering the repo ecosystems plus github-actions.
Install from the lockfile in CImedium
.github/workflows
npm install with a committed package-lock.json
A fresh resolution in CI means the tested dependency set is not the locked one, so the failure only appears after merge.
Fix: Use npm ci, yarn install --immutable, or pnpm install --frozen-lockfile.
Pin the container base image by digestmedium2 occurrences
admin/Dockerfile
node:lts-alpine, nginx:stable-alpine
An untagged or mutable base means today's build and last month's contain different libc and a different CVE set, with no record of which shipped.
Fix: Use image:tag@sha256:<digest> and enable Dependabot's docker ecosystem.
Gate pull requests on a dependency vulnerability scanmedium
.github/workflows
no dependency scan in CI
This is the one gate that would catch a known-vulnerable package before it reaches a build, and no repository in the sample had it.
Fix: Add dependency-review-action on pull_request, or osv-scanner on push and a schedule.
Set persist-credentials: false on checkoutmedium
.github/workflows/build.yml
checkout keeps the token, then dependencies are installed
The token stays in .git/config for every later step, so a malicious postinstall script reads a pushable credential without one ever being passed to it.
Fix: Add with: persist-credentials: false, and pass an explicit token only to the step that pushes.
Add a non-root USER to the imagemedium
admin/Dockerfile
CMD or ENTRYPOINT with no USER directive
A process running as root in the container is root against every mounted volume, and it turns any container escape or writable-mount mistake from a contained problem into a host one.
Fix: Create an unprivileged user, chown what it needs, and end the Dockerfile with USER.
Set timeout-minutes on the workflow jobslow4 occurrences
.github/workflows/build.yml
4 workflow(s) declare no job timeout
A wedged step runs to the six-hour platform default, which on a two-hourly schedule means three runs overlap behind it.
Fix: Add timeout-minutes with a realistic bound to each job.
Add the repository convention files this project lackslow3 occurrences
missing .editorconfig, .gitattributes, a formatter config
Without them one contributor's editor writes tabs into a Python file, a shell script commits with CRLF and fails in the container, and a notebook diff is unreviewable.
Fix: Add .editorconfig, .gitattributes with text=auto eol=lf, and a formatter config.
Checked deterministically against the repository tree and a bounded set of its files: committed credentials, unpinned actions and base images, missing lockfiles and update bots, workflows that discard failures, published advisories against the declared dependencies, runtime configuration, licensing and notebook reproducibility. No language model is involved in this section.