{"id":43484509,"url":"https://github.com/edubertin/project_rented","last_synced_at":"2026-02-03T09:03:07.250Z","repository":{"id":335983659,"uuid":"1147718460","full_name":"edubertin/project_rentED","owner":"edubertin","description":null,"archived":false,"fork":false,"pushed_at":"2026-02-02T16:26:18.000Z","size":49,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-02T18:09:35.771Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/edubertin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","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-02-02T05:55:11.000Z","updated_at":"2026-02-02T16:29:12.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/edubertin/project_rentED","commit_stats":null,"previous_names":["edubertin/project_rented"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/edubertin/project_rentED","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edubertin%2Fproject_rentED","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edubertin%2Fproject_rentED/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edubertin%2Fproject_rentED/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edubertin%2Fproject_rentED/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/edubertin","download_url":"https://codeload.github.com/edubertin/project_rentED/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/edubertin%2Fproject_rentED/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29039341,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-03T08:41:49.363Z","status":"ssl_error","status_checked_at":"2026-02-03T08:40:19.255Z","response_time":96,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":[],"created_at":"2026-02-03T09:03:03.061Z","updated_at":"2026-02-03T09:03:07.245Z","avatar_url":"https://github.com/edubertin.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"frontend/public/brand/logo.png\" alt=\"rentED logo\" width=\"640\"\u003e\n\u003c/p\u003e\n\n![CI](https://github.com/edubertin/project_rentED/actions/workflows/ci.yml/badge.svg)\n![Secret Scan](https://github.com/edubertin/project_rentED/actions/workflows/secret-scan.yml/badge.svg)\n![Python](https://img.shields.io/badge/python-3.11%2B-3776AB)\n![License](https://img.shields.io/github/license/edubertin/project_rentED)\n![Release](https://img.shields.io/github/v/release/edubertin/project_rentED)\n\nrentED is a property management platform with AI-assisted document ingestion, structured data extraction,\nand operational workflows for properties, owners, and work orders. It combines a FastAPI backend,\nNext.js dashboard, and a review-first pipeline for contract data before it is confirmed.\n\n---\n\n## Table of Contents\n1. Overview\n2. Features\n3. Tech Stack\n4. Project Structure\n5. Quick Start (Docker)\n6. Environment Variables\n7. Database Migrations\n8. Seed Data\n9. API Usage (curl examples)\n10. Frontend Dashboard (Next.js)\n11. Document Extraction Pipeline (AI)\n12. Property Import (LLM)\n13. Sample Contracts for Testing\n14. Dashboard Docs and Swagger\n15. Testing\n16. Security Notes\n17. Troubleshooting\n18. Roadmap / Next Steps\n19. Contributing / Git Workflow\n20. License\n\n---\n\n## 1. Overview\nrentED API is a backend scaffold for property management operations. It includes:\n- Core data model with migrations\n- Session-based authentication (HTTP-only cookie)\n- CRUD endpoints for properties\n- Document upload and AI-backed extraction pipeline\n- Work orders endpoint\n- Custom documentation dashboard + Swagger\n\n---\n\n## 2. Features\n- Healthcheck endpoint: `GET /health`\n- Session login (username/password)\n- CRUD for properties\n- Property photos upload (local storage)\n- Document upload (local storage) + list by status\n- AI extraction pipeline (worker + Redis queue) with confidence scoring\n- Review screen to confirm extracted JSON\n- Import property data from rental contract (LLM prefill)\n- Work orders creation + listing\n- Activity log entries for document processing/review\n- Admin-only user management endpoints (`/users`) + Users dashboard\n- Alembic migrations\n- Dashboard docs at `/docs`\n- Swagger UI at `/swagger`\n\n---\n\n## 3. Tech Stack\n- FastAPI\n- SQLAlchemy\n- Alembic\n- PostgreSQL\n- Redis\n- RQ\n- LangChain (OpenAI)\n- pypdf + optional OCR\n- passlib (bcrypt)\n- Docker Compose\n\n---\n\n## 4. Project Structure\n```\nbackend/\n  app/\n    auth.py\n    db.py\n    deps.py\n    main.py\n    models.py\n    schemas.py\n    ai.py\n    storage.py\n    static/\n      docs.html\n      dashboard.css\n  alembic/\n  scripts/\n    seed.py\n  tests/\n  Dockerfile\n  requirements.txt\n\nfrontend/\n  components/\n    TopNav.js\n  pages/\n  styles/\n  lib/\n  next.config.js\n  package.json\n\ndocker-compose.yml\n.env.example\nREADME.md\nCONTRIBUTING.md\nCHANGELOG.md\nLICENSE\n```\n\n---\n\n## 5. Quick Start (Docker)\n### 5.1 Create env file\n```\ncopy .env.example .env\n```\n\n### 5.2 Build and start services\n```\ndocker compose up -d --build\n```\n\n### 5.3 Run migrations\n```\ndocker compose run --rm api alembic upgrade head\n```\n\n### 5.4 Start worker\n```\ndocker compose up -d worker\n```\n\n### 5.5 (Optional) Seed admin + 2 properties\n```\ndocker compose run --rm api python scripts/seed.py\n```\n\n### 5.6 Open the dashboard docs\n- `http://localhost:8000/docs`\n\n### 5.7 Open Swagger UI\n- `http://localhost:8000/swagger`\n\n---\n\n## 6. Environment Variables\nDefined in `.env.example`:\n- `POSTGRES_USER`\n- `POSTGRES_PASSWORD`\n- `POSTGRES_DB`\n- `DATABASE_URL`\n- `REDIS_URL`\n- `OPENAI_API_KEY`\n- `OPENAI_MODEL`\n- `OPENAI_TEMPERATURE`\n- `OPENAI_MAX_TOKENS` (default 1024)\n- `AI_MODE` (`live` or `mock`)\n- `AI_CONFIDENCE_THRESHOLD`\n- `OCR_MODE` (`none` or `tesseract`)\n- `AI_LLM_INPUT_MAX_CHARS` (max characters sent to the LLM)\n- `SESSION_TTL_MINUTES`\n- `SESSION_COOKIE_NAME`\n- `COOKIE_SECURE`\n- `SEED_ADMIN_USERNAME`\n- `SEED_ADMIN_PASSWORD`\n- `SEED_ADMIN_NAME`\n- `SEED_ADMIN_CELL`\n\nOptional:\n- `UPLOAD_DIR` (default: `/app/data/uploads`)\n- `NEXT_PUBLIC_API_BASE` (frontend, default: `http://localhost:8000`)\n\n---\n\n## 7. Database Migrations\nMigrations are managed by Alembic and should be the source of truth for schema.\n\nRun migrations:\n```\ndocker compose run --rm api alembic upgrade head\n```\n\nIf you need a new migration after editing models:\n```\ndocker compose run --rm api alembic revision --autogenerate -m \"describe_change\"\n```\n\n---\n\n## 8. Seed Data\nSeed script creates:\n- 1 admin user\n- 2 properties owned by admin\n\nDefaults (override in `.env`):\n- Username: `SEED_ADMIN_USERNAME` (default `admin`)\n- Password: `SEED_ADMIN_PASSWORD` (default `Admin123!`)\n\nRun:\n```\ndocker compose run --rm api python scripts/seed.py\n```\n\n---\n\n## 9. API Usage (curl examples)\n### Health\n```\ncurl http://localhost:8000/health\n```\n\n### Login\n```\ncurl -X POST http://localhost:8000/auth/login \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"username\":\"admin\",\"password\":\"Admin123!\"}'\n```\nUse cookies for authenticated calls:\n```\ncurl -c cookies.txt -X POST http://localhost:8000/auth/login \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"username\":\"admin\",\"password\":\"Admin123!\"}'\ncurl -b cookies.txt http://localhost:8000/properties\n```\n\n### Current User\n```\ncurl http://localhost:8000/auth/me\n```\n\n### Logout\n```\ncurl -X POST http://localhost:8000/auth/logout\n```\n\n### Create Property\n```\ncurl -X POST http://localhost:8000/properties \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"owner_user_id\":1,\"extras\":{\"label\":\"Main\"}}'\n```\n\n### Import Property From Contract (LLM)\n```\ncurl -X POST http://localhost:8000/properties/import \\\n  -F \"file=@./samples/contracts/rented_sample_rental_contract.pdf\"\n```\nThe extracted contract will be linked to the property when you create it in the UI.\n\n### Create User (admin-only)\nThis endpoint is admin-only. Do not expose it in production without proper auth controls.\n```\ncurl -X POST http://localhost:8000/users \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"username\":\"owner1\",\"password\":\"Owner123!\",\"role\":\"property_owner\",\"name\":\"Owner\",\"cell_number\":\"(111) 11111 1111\",\"extras\":{}}'\n```\n\nRoles:\n- `admin`\n- `real_estate`\n- `finance`\n- `service_provider`\n- `property_owner`\n\nUsername rules:\n- One word, letters and numbers only (3–80 chars).\n\nName rules:\n- Letters and spaces only (2–120 chars).\n\nPassword rules:\n- Min 8 chars, includes 1 uppercase, 1 number, 1 special.\n\nCell number format:\n- `(xxx) xxxxx xxxx`\n\n### Update User (admin-only)\n```\ncurl -X PUT http://localhost:8000/users/2 \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\":\"Owner Updated\",\"cell_number\":\"(111) 11111 1111\"}'\n```\n\n### Delete User (admin-only)\n```\ncurl -X DELETE http://localhost:8000/users/2\n```\nNote: admin users are protected from deletion.\n\n### List Properties\n```\ncurl http://localhost:8000/properties\n```\n\n### Update Property\n```\ncurl -X PUT http://localhost:8000/properties/1 \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"extras\":{\"label\":\"Updated\"}}'\n```\n\n### Upload Property Photos (max 10)\n```\ncurl -X POST http://localhost:8000/properties/1/photos \\\n  -F \"files=@./path/to/photo1.jpg\" \\\n  -F \"files=@./path/to/photo2.jpg\"\n```\n\n### Delete Property\n```\ncurl -X DELETE http://localhost:8000/properties/1\n```\n\n### Upload Document\n```\ncurl -X POST \"http://localhost:8000/documents/upload?property_id=1\" \\\n  -F \"file=@./path/to/file.pdf\"\n```\n\n### Download an Uploaded File\n```\ncurl -O http://localhost:8000/uploads/\u003cfilename\u003e\n```\n\n### List Documents by Status\n```\ncurl \"http://localhost:8000/documents?status=uploaded\"\n```\n\n### Process Document (enqueue)\n```\ncurl -X POST http://localhost:8000/documents/1/process\n```\n\n### Get Document Extraction\n```\ncurl http://localhost:8000/documents/1/extraction\n```\n\n### Confirm Document Review\n```\ncurl -X PUT http://localhost:8000/documents/1/review \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"extraction\":{\"doc_type\":\"contract\",\"fields\":{},\"summary\":\"ok\",\"alerts\":[],\"confidence\":0.9}}'\n```\n\n### Create Work Order\n```\ncurl -X POST http://localhost:8000/work-orders \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"property_id\":1,\"extras\":{\"title\":\"Fix leak\"}}'\n```\n\n### List Work Orders\n```\ncurl http://localhost:8000/work-orders\n```\n\n---\n\n## 10. Frontend Dashboard (Next.js)\nThe frontend is a minimal Next.js dashboard with login + screens:\n- Login (index)\n- Properties list + create + import\n- Property detail (documents + work orders)\n- Work orders list + create\n- Users (admin-only)\n\nRun it:\n```\ncd frontend\nnpm install\nnpm run dev\n```\n\nThen open:\n- `http://localhost:3000` (login)\n\nIf the API is on a different host/port:\n```\nset NEXT_PUBLIC_API_BASE=http://localhost:8000\n```\n\n---\n\n## 11. Document Extraction Pipeline (AI)\n### Flow\n1. Upload document -\u003e stored locally.\n2. Worker extracts text (PDF/text files; OCR optional for images).\n3. AI extracts `doc_type`, fields, summary, alerts, and confidence.\n4. Document status moves to `needs_review`.\n5. Review endpoint confirms and sets status to `confirmed`.\n\n### Notes\n- AI results are stored in `document_extractions.extras`.\n- Extracted text is always preserved in the extraction payload.\n- Low-confidence results add an alert and still require review.\n- Set `AI_MODE=mock` in dev/tests to disable API calls.\n- OCR for images uses Tesseract. In Docker it is installed via the API image. Set `OCR_MODE=tesseract` to enable it.\n- LLM input is capped by `AI_LLM_INPUT_MAX_CHARS` to avoid oversized responses.\n\n---\n\n## 12. Property Import (LLM)\nYou can upload a rental contract and prefill the Property form:\n- UI: Properties → Import Property\n- API: `POST /properties/import` (returns extracted fields and summary)\n\nThis uses the same extraction pipeline and respects:\n- `AI_MODE` (`live` or `mock`)\n- `OPENAI_API_KEY`, `OPENAI_MODEL`, `OPENAI_MAX_TOKENS`\n\nThe uploaded contract is attached to the Property as a document once the Property is created.\n\n---\n\n## 13. Sample Contracts for Testing\nSample contract PDF for local testing:\n- `samples/contracts/rented_sample_rental_contract.pdf`\n\nSuggested flow:\n1. Use **Import Property** and upload the sample contract.\n2. Review the prefilled fields.\n3. Add required photos and create the property.\n\n---\n\n## 14. Dashboard Docs and Swagger\n- `/docs` provides an interactive dashboard with inline test widgets.\n- `/swagger` provides full OpenAPI request/response schemas.\n- `/openapi.json` returns raw OpenAPI JSON.\n\n---\n\n## 15. Testing\nRun tests inside the container:\n```\ndocker compose run --rm api pytest\n```\n\n---\n\n## 16. Security Notes\n- All CRUD endpoints require an authenticated session cookie.\n- Non-admin users can only create and manage their own properties.\n- Default Postgres credentials are for local use only.\n- Uploads are stored locally in `./data/uploads` (bind-mounted into the container).\n- Exposed ports (Postgres/Redis) are open to the host. Restrict or remove in production.\n- Store `OPENAI_API_KEY` securely and never commit it.\n- Known advisory: Next.js has a high-severity advisory affecting Image Optimizer and Server Components. We keep Next 14.2.35 during development to avoid breaking changes and plan to upgrade to Next 16 before production.\n- Session cookies are httpOnly; set `COOKIE_SECURE=true` when using HTTPS.\n- Admin accounts cannot be deleted via the API.\n\n---\n\n## 17. Troubleshooting\n### Migration errors (missing revision)\nIf you see:\n`Can't locate revision identified by '0001_create_items'`\n\nRebuild the API image to ensure latest migrations are inside:\n```\ndocker compose build api\n```\n\n### Upload directory issues\nIf uploads fail, verify the container can write to `/app/data/uploads`.\nEnsure `./data/uploads` exists on the host when using the bind mount.\n\n### Redis warnings\nIf Redis logs warning about POST/Host commands, it is likely due to port exposure.\nFor local-only use, bind to 127.0.0.1 or remove the port mapping.\n\n---\n\n## 18. Roadmap / Next Steps\n- Define real user fields (email, name, password hash)\n- Add email and password reset flows\n- Expand document metadata beyond `extras`\n- Extend activity log coverage to more write operations\n- Add test coverage for error cases and auth\n\n---\n\n## 19. Contributing / Git Workflow\nSee `CONTRIBUTING.md` for the full workflow and expectations.\n\n---\n\n## 20. License\nMIT. See `LICENSE` for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedubertin%2Fproject_rented","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fedubertin%2Fproject_rented","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fedubertin%2Fproject_rented/lists"}