{"id":51571865,"url":"https://github.com/mosalem149/constledger","last_synced_at":"2026-07-10T20:01:44.384Z","repository":{"id":363588653,"uuid":"1250383698","full_name":"MoSalem149/constledger","owner":"MoSalem149","description":"ConstLedger — AI-powered contract \u0026 project management system for construction. Built by Team Octagram as an ITI graduation project. Stack: Node.js, Express, TypeScript, React, MongoDB, OpenAI.","archived":false,"fork":false,"pushed_at":"2026-06-16T22:20:45.000Z","size":41359,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-16T22:24:31.755Z","etag":null,"topics":["constledger","construction-management","contract-management","docker","expressjs","graduation-project","iti","jwt","mern","mongodb","nodejs","octagram","openai","react","tailwindcss","typescript"],"latest_commit_sha":null,"homepage":"https://constledger-cpms.vercel.app","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MoSalem149.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-26T15:19:21.000Z","updated_at":"2026-06-15T16:33:09.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/MoSalem149/constledger","commit_stats":null,"previous_names":["mosalem149/constledger"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/MoSalem149/constledger","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MoSalem149%2Fconstledger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MoSalem149%2Fconstledger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MoSalem149%2Fconstledger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MoSalem149%2Fconstledger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MoSalem149","download_url":"https://codeload.github.com/MoSalem149/constledger/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MoSalem149%2Fconstledger/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35341768,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-10T02:00:06.465Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["constledger","construction-management","contract-management","docker","expressjs","graduation-project","iti","jwt","mern","mongodb","nodejs","octagram","openai","react","tailwindcss","typescript"],"created_at":"2026-07-10T20:01:39.364Z","updated_at":"2026-07-10T20:01:44.376Z","avatar_url":"https://github.com/MoSalem149.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# ConstLedger\n\n**AI-assisted contract extraction, finance planning, and reporting**\n\n\u003e Graduation Project — Information Technology Institute (ITI) · May 2026\n\n[![Node.js](https://img.shields.io/badge/Node.js-20-339933?logo=node.js\u0026logoColor=white)](https://nodejs.org)\n[![React](https://img.shields.io/badge/React-18-61DAFB?logo=react\u0026logoColor=black)](https://react.dev)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5-3178C6?logo=typescript\u0026logoColor=white)](https://www.typescriptlang.org)\n[![MongoDB](https://img.shields.io/badge/MongoDB-7-47A248?logo=mongodb\u0026logoColor=white)](https://www.mongodb.com)\n[![Docker](https://img.shields.io/badge/Docker-Compose-2496ED?logo=docker\u0026logoColor=white)](https://www.docker.com)\n\n\u003c/div\u003e\n\n---\n\n## What is ConstLedger?\n\nConstLedger currently has two implemented backend services and a React frontend\nscaffold. Backend AI handles S3 uploads, PDF parsing, AI extraction, validation,\nand contract storage. Backend Core handles authentication, users, finance\nplanning, reporting, and XLSX exports.\n\nThe frontend currently contains routing, API clients, authentication state, and\nplaceholder pages. Its service modules still include endpoints from an older\nAPI design and need alignment before the UI is fully functional.\n\n---\n\n## Team Octagram\n\n| Name                             | Role                 |\n| -------------------------------- | -------------------- |\n| Yousef Hany Mahmoud              | MERN Stack Developer |\n| Mohamed Elshahat Amer            | MERN Stack Developer |\n| Mohamed Nasr Mansour El Khoreby  | MERN Stack Developer |\n| Abdalla Mohamed Ragheb Elhagar   | MERN Stack Developer |\n| Mohamed Wael Mohamed Salem       | MERN Stack Developer |\n| Nagwa Mahmoud Roshdy             | Testing \u0026 QA         |\n| Sarah Tarek Mohamed              | Testing \u0026 QA         |\n| Rahma Emad Mohamed Mohamed Farid | UI/UX Design         |\n\n---\n\n## Architecture\n\n```\nconstledger/\n├── frontend/          React 18 + Vite (JSX)   →  port 5173\n├── backend-core/      Node/Express (JS)        →  port 3000\n├── backend-ai/        Node/Express (TS)        →  port 5000\n├── docker-compose.yml Local dev orchestration\n└── README.md\n```\n\n### Service Communication\n\nThe browser talks to both backend services. Core owns `/api/auth`,\n`/api/users`, `/api/finance`, and `/api/reports`; AI owns `/api/uploads` and\n`/api/contracts`. Both services use the same MongoDB database and verify the\nsame HTTP-only JWT cookie. There is no active `x-internal-secret` service call\nbetween them.\n\n```\nBrowser\n  ├── /api/auth, /api/users, /api/finance, /api/reports\n  │      └── backend-core :3000\n  └── /api/uploads, /api/contracts\n         └── backend-ai :5000\n\nbackend-core ──┐\n              ├── shared MongoDB :27017\nbackend-ai  ───┘\n      └── Amazon S3\n      └── Gemini, OpenRouter, or Groq\n```\n\n---\n\n## Modules\n\n| Module                    | Description                                                                                 | AI?                 |\n| ------------------------- | ------------------------------------------------------------------------------------------- | ------------------- |\n| **Contracts** | Direct-to-S3 upload, background PDF extraction, validation, human review, editing, and re-analysis | Gemini, OpenRouter, or Groq |\n| **Finance** | Straight-line, S-curve, and milestone-weighted plans; manual edits; confirmation; payment schedule | Deterministic |\n| **Reports** | Contract, planned-budget, payment-schedule, and project-summary JSON/XLSX reports | Aggregation |\n| **Frontend** | React/Vite routes and service scaffold; page implementations are placeholders | Not complete |\n\n---\n\n## User Roles\n\n| Role               | Permissions                                                 |\n| ------------------ | ----------------------------------------------------------- |\n| `contract_manager` | Upload contracts, review AI extractions, edit contract data |\n| `pmo`              | Everything above + manage users and all finance operations  |\n| `finance_team`     | Read finance plans and reports                              |\n| `top_management`   | Read finance plans and reports                              |\n\n---\n\n## Tech Stack\n\n| Layer             | Technology                                    |\n| ----------------- | --------------------------------------------- |\n| Frontend          | React 18, Vite, Tailwind CSS, React Router v6 |\n| Core Backend      | Node.js, Express, Mongoose                    |\n| AI Backend        | Node.js, Express, TypeScript                  |\n| Database          | MongoDB (Mongoose ODM)                        |\n| File Storage      | Amazon S3                                     |\n| LLM               | Gemini, OpenRouter, or Groq                   |\n| Auth              | JWT in HTTP-only cookie + RBAC                |\n| Testing           | Vitest                                        |\n| Dev Orchestration | Docker Compose                                |\n\n---\n\n## Quick Start\n\n### Option A — Docker (recommended)\n\n**Prerequisites:** Docker Desktop, an Amazon S3 bucket, and at least one\nGemini, OpenRouter, or Groq API key.\n\n```bash\n# 1. Clone\ngit clone https://github.com/your-org/constledger.git \u0026\u0026 cd constledger\n\n# 2. Create env files\ncp frontend/.env.example        frontend/.env.local\ncp backend-core/.env.example    backend-core/.env\ncp backend-ai/.env.example      backend-ai/.env\n\n# 3. Fill in secrets\n#    use the same JWT_SECRET in both backend env files\n#    backend-core/.env  → MONGODB_URI, JWT_SECRET\n#    backend-ai/.env    → MONGODB_URI, JWT_SECRET, AWS_*, S3_BUCKET,\n#                         and at least one AI provider API key\n\n# 4. Start everything\ndocker-compose up --build\n```\n\n| Service      | URL                            |\n| ------------ | ------------------------------ |\n| Frontend     | http://localhost:5173          |\n| Backend Core | http://localhost:3000          |\n| Backend AI   | http://localhost:5000          |\n| MongoDB      | mongodb://localhost:27017/cpms |\n\n---\n\n### Option B — Local (no Docker)\n\n**Prerequisites:** Node.js 20+, MongoDB running locally.\n\n#### 1. MongoDB\n\n```bash\nmongod --dbpath ~/data/db\n# or use a MongoDB Atlas free cluster\n```\n\n#### 2. backend-core (port 3000)\n\n```bash\ncd backend-core\ncp .env.example .env        # set MONGODB_URI=mongodb://localhost:27017/cpms\nnpm install\nnpm run dev\n```\n\n#### 3. backend-ai (port 5000)\n\n```bash\ncd backend-ai\ncp .env.example .env        # set MONGODB_URI=mongodb://localhost:27017/cpms\n                             # configure JWT_SECRET, S3, and an AI provider key\nnpm install\nnpm run dev\n```\n\n#### 4. frontend (port 5173)\n\n```bash\ncd frontend\ncp .env.example .env.local  # already set for localhost\nnpm install\nnpm run dev\n```\n\n\u003e Start order: MongoDB → backend-core and backend-ai → frontend\n\n---\n\n## Health Checks\n\n```bash\ncurl http://localhost:3000/health   # {\"status\":\"ok\",\"service\":\"cpms-core\"}\ncurl http://localhost:5000/health   # {\"status\":\"ok\",\"service\":\"cpms-ai\"}\n```\n\n---\n\n## Backend Tests\n\nFocused Vitest suites cover the main backend business logic without requiring\nMongoDB, AWS, OCR, or AI provider credentials.\n\n```bash\ncd backend-core \u0026\u0026 npm test\ncd ../backend-ai \u0026\u0026 npm test\ncd ../frontend \u0026\u0026 npm run build\n```\n\nUse `npm run test:watch` inside either backend while developing. Docker files\ndo not need test-specific changes because Vitest is a development dependency\nand the runtime images continue to install production dependencies only.\n\n---\n\n## API Ownership\n\n| Service | Mounted API prefixes |\n|---|---|\n| Backend Core | `/api/auth`, `/api/users`, `/api/finance`, `/api/reports` |\n| Backend AI | `/api/uploads`, `/api/contracts` |\n\nSee [backend-core/README.md](backend-core/README.md) and\n[backend-ai/README.md](backend-ai/README.md) for the current endpoints,\nauthorization rules, request shapes, and environment variables.\n\n---\n\n## Fixed: Frontend couldn't reach Backend AI under Docker Compose\n\n`docker-compose up` used to bring up all four containers successfully, but\nthe frontend couldn't actually reach `backend-ai` once you started clicking\naround (contract list, upload, analysis all failed) — even though\n`npm run dev` for each service on the host (Option B) worked fine. Two\nstacked issues caused it, and both are now fixed in `vite.config.js` and\n`docker-compose.yml`:\n\n1. **`vite.config.js`'s dev-server proxy targets were hardcoded to\n   `localhost`.** That proxy runs *inside* whichever process is running\n   Vite. When that process is the `frontend` container, `localhost`\n   resolves to the container itself — not to `backend-core` or `backend-ai`,\n   which are only reachable from `frontend` via their Compose service names\n   (`http://backend-core:3000`, `http://backend-ai:5000`) on the `cpms-net`\n   network. Running all three as plain host processes has no such\n   isolation, so the same hardcoded targets happened to be correct there.\n\n   **Fix:** the proxy targets are now read from `CORE_PROXY_TARGET` /\n   `AI_PROXY_TARGET` env vars, defaulting to `localhost` for local dev.\n   `docker-compose.yml` sets them to the service names instead.\n\n2. **`docker-compose.yml` overrode `VITE_API_URL` to an absolute URL**\n   (`http://localhost:3000/api`) instead of the relative `/api` default in\n   `frontend/.env.example`. `frontend/.dockerignore` excludes `.env.local`\n   from the build context, so inside the container that Compose value was\n   the *only* value Vite ever saw. Because `services/api.js` has a single\n   Axios instance whose `baseURL` is `VITE_API_URL` — and `VITE_AI_API_URL`\n   (also set in the old `docker-compose.yml`) was never read anywhere in the\n   frontend code — every request, including ones for `/api/contracts` and\n   `/api/uploads`, got sent to `backend-core`, which doesn't mount those\n   routes, so they 404'd.\n\n   In local/standalone dev, `VITE_API_URL` stayed relative (`/api`), so\n   requests went through the Vite proxy from issue #1 instead — and that\n   proxy *did* correctly split traffic by path between `:3000` and `:5000`,\n   because in that mode `localhost` was unambiguous. That's why\n   contracts/uploads worked outside Docker even though the frontend only\n   ever had one configured API base URL.\n\n   **Fix:** `docker-compose.yml` now sets `VITE_API_URL=/api` (relative,\n   matching local dev), so every request goes through the now-correctly-\n   targeted Vite proxy from fix #1. `VITE_AI_API_URL` was removed since\n   nothing reads it.\n\nIf you pulled this repo before this fix landed: `docker-compose up --build`\nagain to pick up the new `frontend` environment variables, no other changes\nneeded.\n\n---\n\n## Current Limitations\n\n- All frontend page components are placeholders.\n- The frontend authentication client expects a response token and sends bearer\n  tokens, while the backends use only an HTTP-only cookie. Axios also needs\n  `withCredentials: true`.\n- Several frontend finance and report URLs belong to an older API and are not\n  mounted by the current backends.\n- Upload signing accepts PDF, DOC, and DOCX MIME types, but active analysis\n  supports PDF only. Word uploads currently end in `analysis_failed`.\n- AI extraction always finishes in `pending_review`; a manager must activate\n  the contract before finance-plan generation.\n- `docker-compose.yml` still sets `AI_SERVICE_URL` / `CORE_SERVICE_URL` on\n  the backends, and both `.env.example` files document `AI_SERVICE_SECRET` /\n  an `x-internal-secret` header. None of these are read anywhere in `src/`\n  for either backend — there is no service-to-service HTTP call today\n  (matches the \"Service Communication\" note above). Safe to ignore or\n  remove until that call is actually built.\n- There are no automated frontend tests yet.\n\nSee [frontend/README.md](frontend/README.md) for the frontend integration work\nthat remains.\n\n---\n\n## Deployment\n\n### Frontend → Vercel\n\n```bash\ncd frontend \u0026\u0026 npm run build\nnpx vercel --prod\n# Set in Vercel dashboard:\n#   VITE_API_URL = https://your-core-service.run.app/api\n#   VITE_AI_API_URL = https://your-ai-service.run.app/api\n```\n\n### Backends → Google Cloud Run\n\n```bash\n# backend-core\ncd backend-core\ngcloud builds submit --tag gcr.io/YOUR_PROJECT/constledger-backend-core\ngcloud run deploy constledger-backend-core \\\n  --image gcr.io/YOUR_PROJECT/constledger-backend-core \\\n  --platform managed --region us-central1 \\\n  --set-env-vars MONGODB_URI=...,JWT_SECRET=...\n\n# backend-ai\ncd backend-ai\ngcloud builds submit --tag gcr.io/YOUR_PROJECT/constledger-backend-ai\ngcloud run deploy constledger-backend-ai \\\n  --image gcr.io/YOUR_PROJECT/constledger-backend-ai \\\n  --platform managed --region us-central1 \\\n  --allow-unauthenticated \\\n  --set-env-vars MONGODB_URI=...,JWT_SECRET=...,S3_BUCKET=...,AWS_REGION=...\n```\n\nThe browser currently calls Backend AI directly, so a private Cloud Run\nservice would require an additional authenticated proxy architecture. Inject\nJWT, database, S3, and AI-provider secrets through Secret Manager in production.\n\n---\n\n\u003cdiv align=\"center\"\u003e\nMade with ❤️ by \u003cstrong\u003eTeam Octagram\u003c/strong\u003e · ITI Graduation Project 2026\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmosalem149%2Fconstledger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmosalem149%2Fconstledger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmosalem149%2Fconstledger/lists"}