|
| 1 | +# Project Structure |
| 2 | + |
| 3 | +This document explains how the FireForm repository is organized and, when you add new code, where it should go. |
| 4 | + |
| 5 | +## Top-level layout |
| 6 | + |
| 7 | +``` |
| 8 | +FireForm/ |
| 9 | +├── app/ # Backend source code (FastAPI application) |
| 10 | +├── tests/ # Test suite (pytest) |
| 11 | +├── docker/ # Dockerfiles, compose files, env templates |
| 12 | +├── scripts/ # Shell scripts |
| 13 | +├── docs/ # Project documentation |
| 14 | +├── examples/ # Standalone demo scripts |
| 15 | +├── data/ # Local runtime data (gitignored contents) |
| 16 | +├── Makefile # Entry point for all dev commands (`make help`) |
| 17 | +└── requirements.txt # Python dependencies |
| 18 | +``` |
| 19 | + |
| 20 | +| You want to… | Go to | |
| 21 | +| -------------------------------- | ------------------------------------------------------- | |
| 22 | +| Change backend behavior | `app/` | |
| 23 | +| Add or fix tests | `tests/` | |
| 24 | +| Change container setup, env vars | `docker/` (see [docker/README.md](../docker/README.md)) | |
| 25 | +| Change setup/bootstrap scripts | `scripts/` | |
| 26 | +| Add documentation | `docs/` | |
| 27 | +| Add dev commands | `Makefile` | |
| 28 | + |
| 29 | +## Inside `app/` |
| 30 | + |
| 31 | +The backend follows a layered structure: **routes → services → repositories → database**. Requests enter through the API layer, business logic lives in services, and all database access goes through repositories. |
| 32 | + |
| 33 | +``` |
| 34 | +app/ |
| 35 | +├── main.py # App factory: creates FastAPI app, wires middleware and routers |
| 36 | +├── api/ # HTTP layer - request/response handling only, no business logic |
| 37 | +│ ├── router.py # Aggregates all route modules into one router; main.py mounts this |
| 38 | +│ ├── deps.py # Shared FastAPI dependencies (e.g. DB session injection) |
| 39 | +│ ├── routes/ # One module per feature (forms.py, templates.py, …) |
| 40 | +│ └── schemas/ # Pydantic request/response models, one module per feature |
| 41 | +├── core/ # App-wide infrastructure |
| 42 | +│ ├── config.py # All settings and env var reading nothing else reads os.environ |
| 43 | +│ ├── lifespan.py # Startup/shutdown logic (DB init, etc.) |
| 44 | +│ ├── logging.py # Logging configuration |
| 45 | +│ └── errors/ # Custom exception classes (base.py) and handlers (handlers.py) |
| 46 | +├── services/ # Business logic — LLM extraction, PDF filling, orchestration |
| 47 | +├── db/ # Database engine/session (database.py) and repositories.py |
| 48 | +├── models/ # SQLAlchemy ORM models |
| 49 | +└── utils/ # Small generic helpers with no business logic |
| 50 | +``` |
| 51 | + |
| 52 | +### Where does my new code go? |
| 53 | + |
| 54 | +**Adding a new API endpoint:** |
| 55 | + |
| 56 | +1. `app/api/schemas/<...>.py` - Pydantic models for the request and response bodies |
| 57 | +2. `app/api/routes/<...>.py` - the route handlers; keep them thin, delegate to a service |
| 58 | +3. `app/api/router.py` - register the new router (one `include_router` line) |
| 59 | +4. Business logic goes in `app/services/`, not in the route handler |
| 60 | + |
| 61 | +**Adding business logic:** `app/services/`. A service should not know about HTTP (no FastAPI imports) it takes plain data in and returns plain data, so it can be tested and reused independently. |
| 62 | + |
| 63 | +**Adding a database table:** define the ORM model in `app/models/models.py`, and add its query/persistence functions to `app/db/repositories.py`. Services call repositories; routes never touch the database directly. |
| 64 | + |
| 65 | +**Adding a setting or env var:** declare it in `app/core/config.py` and document it in `docker/.env.example`. Code elsewhere imports from `config`, never reads `os.environ` itself. |
| 66 | + |
| 67 | +**Adding a custom error:** subclass in `app/core/errors/base.py`; map it to an HTTP response in `app/core/errors/handlers.py`. |
| 68 | + |
| 69 | +## Tests |
| 70 | + |
| 71 | +Tests live in `tests/`, run with `make test` (pytest inside the app container). `conftest.py` holds shared fixtures. Name files `test_<area>.py` and mirror what you're testing: API endpoint tests alongside `test_api.py`, model/DB tests alongside `test_model.py`. |
| 72 | +Note: Tests will be undergoing many changes hence the docs can be outdated, Please raise issue if tests or docs are outdated. |
| 73 | + |
| 74 | +## Docker & scripts |
| 75 | + |
| 76 | +- `docker/dev/` - development image (hot reload, source mounted) and its compose file. This is what `make up` runs. |
| 77 | +- `docker/prod/` - production image (multi-stage build, gunicorn, no source mount). |
| 78 | +- `docker/.env.example` - template for env vars; copied to `.env.dev` by `make init`. |
| 79 | +- `scripts/` - shell scripts invoked by `make init` (dependency checks, env file creation, model selection) and by container startup. Not meant to be run directly. |
| 80 | + |
| 81 | +Full details: [docker/README.md](../docker/README.md). |
| 82 | + |
| 83 | +## Everything else |
| 84 | + |
| 85 | +- `examples/` - runnable demo scripts showing the pipeline end to end; not imported by the app. |
| 86 | +- `data/` - runtime working data on your machine; contents are not part of the codebase. |
| 87 | +- `src/`, `temp/` - scratch/legacy directories slated for cleanup; don't add new code here. |
0 commit comments