# naina-sriv/ftp architecture

> Architecture diagram of the GitHub repository naina-sriv/ftp, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-25). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/naina-sriv/ftp
- Repository: https://github.com/naina-sriv/ftp

## Overview

1. **Overall shape**  
   This is a single FastAPI backend for civic issue reporting. It is organized as a layered monolith: HTTP routers at the edge, service-like auth/dependency helpers in `app/core`, SQLAlchemy ORM models in `app/models`, and Pydantic schemas in `app/schema`.

2. **Request entrypoint**  
   `app/main.py` is the application bootstrap. It creates the FastAPI app and wires in the route modules under `app/routers`, so all client traffic enters through one API process.

3. **API boundary**  
   The functional API is split by concern:
   - `auth.py` for registration and login
   - `issue.py` for issue CRUD
   - `comments.py` for issue comments
   - `votes.py` for voting and escalation logic  
   This separation is important for diagramming because each router maps to a distinct user action and resource type.

4. **Identity and access control**  
   Authentication is JWT-based, backed by password hashing in `app/core/security.py`. The `get_current_user` dependency in `app/core/dependencies.py` is the main enforcement point for protected routes. The README indicates the token also carries constituency information, which scopes what each user can see and modify.

5. **Domain model and persistence**  
   The database layer centers on five core entities in `app/models`: `User`, `Constituency`, `Issue`, `Comment`, and `Vote`. These form the persistent domain graph:
   - users belong to a constituency
   - issues are reported within a constituency
   - comments attach to issues
   - votes attach to issues and are used for threshold validation

6. **Data validation layer**  
   `app/schema` contains the Pydantic request/response contracts for each domain object, plus token schemas. This is the boundary between external JSON and internal ORM objects, and it is where API payload shape and response serialization are enforced.

7. **Database infrastructure**  
   `app/db.py` is the database/session boundary. The repository is designed to run against PostgreSQL in normal use, but the tests use SQLite. This makes the persistence layer portable while keeping local and test execution lightweight.

8. **Issue lifecycle and escalation**  
   The key business rule is threshold-based escalation. Issues start as `open`; when enough unique users vote, the issue transitions to `escalated` and a threshold flag is set. The vote endpoint triggers this check asynchronously via FastAPI `BackgroundTasks`, so the API response returns immediately while the status update happens after the write.

9. **Constituency scoping as a system-wide constraint**  
   Constituency is not just metadata; it is a hard access boundary. Reads and writes for issues, comments, and votes are constrained to the user’s constituency, which prevents cross-constituency interaction and keeps the data model aligned with the product goal.

10. **Testing architecture**  
   `tests/conftest.py` provides an in-memory SQLite fixture, and `tests/test_routes.py` exercises the API end-to-end. The tests cover auth, CRUD, comment flows, voting rules, duplicate vote prevention, and threshold escalation, so the test suite validates the full request-to-database path rather than isolated units.

11. **Configuration and runtime inputs**  
   `app/core/config.py` centralizes environment-driven settings such as database URL, secret key, signing algorithm, and token expiry. That makes runtime behavior configurable without changing application code, which is important for diagramming deployment dependencies.

12. **External-facing interfaces**  
   The only externally visible interface is the HTTP API. There are no queues, caches, or separate worker services in the current implementation; async behavior is handled in-process with FastAPI background tasks, and persistence is the database.

13. **Practical architecture summary**  
   The clearest diagram is: client → FastAPI routers → auth/dependency layer → ORM/models → SQLAlchemy session/database, with background tasks branching off from voting to perform escalation checks. The main cross-cutting concerns are JWT auth, constituency scoping, and schema validation.

Main entry points: [`app/routers/auth.py`](https://github.com/naina-sriv/ftp/blob/main/app/routers/auth.py) (Auth API), [`tests/test_routes.py`](https://github.com/naina-sriv/ftp/blob/main/tests/test_routes.py) (Route tests), [`app/routers/issue.py`](https://github.com/naina-sriv/ftp/blob/main/app/routers/issue.py) (Issue API), [`app/routers/votes.py`](https://github.com/naina-sriv/ftp/blob/main/app/routers/votes.py) (Vote API)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_app["Application"]
  node_main["App startup<br/>FastAPI bootstrap<br/>[main.py]"]
  node_auth_router["Auth API<br/>router<br/>[auth.py]"]
  node_issue_router["Issue API<br/>router<br/>[issue.py]"]
  node_comments_router["Comment API<br/>router<br/>[comments.py]"]
  node_votes_router["Vote API<br/>router<br/>[votes.py]"]
end

subgraph group_core["Core"]
  node_config["Settings<br/>config<br/>[config.py]"]
  node_security["Security<br/>auth utils<br/>[security.py]"]
  node_dependencies["Auth guard<br/>dependency<br/>[dependencies.py]"]
end

subgraph group_domain["Domain"]
  node_user_model["User<br/>ORM model<br/>[user.py]"]
  node_constituency_model["Constituency<br/>ORM model<br/>[constituency.py]"]
  node_issue_model["Issue<br/>ORM model<br/>[issue.py]"]
  node_comment_model["Comment<br/>ORM model<br/>[comment.py]"]
  node_vote_model["Vote<br/>ORM model<br/>[vote.py]"]
end

subgraph group_schema["Schemas"]
  node_user_schema["User schema<br/>Pydantic schema<br/>[user.py]"]
  node_constituency_schema["Constituency schema<br/>Pydantic schema<br/>[constituency.py]"]
  node_issue_schema["Issue schema<br/>Pydantic schema<br/>[issue.py]"]
  node_comment_schema["Comment schema<br/>Pydantic schema<br/>[comment.py]"]
  node_vote_schema["Vote schema<br/>Pydantic schema<br/>[vote.py]"]
  node_token_schema["Token schema<br/>Pydantic schema<br/>[token.py]"]
end

subgraph group_infra["Persistence"]
  node_db[("DB session<br/>database<br/>[db.py]")]
end

subgraph group_tests["Tests"]
  node_routes_tests["Route tests<br/>integration tests<br/>[test_routes.py]"]
  node_test_fixtures[("Test DB<br/>test fixture<br/>[conftest.py]")]
end

node_main -->|"includes"| node_auth_router
node_main -->|"includes"| node_issue_router
node_main -->|"includes"| node_comments_router
node_main -->|"includes"| node_votes_router
node_auth_router -->|"hash/sign"| node_security
node_auth_router -->|"reads/writes"| node_db
node_issue_router -->|"protects"| node_dependencies
node_issue_router -->|"reads/writes"| node_db
node_comments_router -->|"protects"| node_dependencies
node_comments_router -->|"reads/writes"| node_db
node_votes_router -->|"protects"| node_dependencies
node_votes_router -->|"reads/writes"| node_db
node_votes_router -->|"escalates"| node_issue_model
node_dependencies -->|"loads"| node_user_model
node_dependencies -->|"scopes"| node_constituency_model
node_issue_model -->|"belongs to"| node_constituency_model
node_comment_model -->|"attaches to"| node_issue_model
node_vote_model -->|"attaches to"| node_issue_model
node_user_model -->|"belongs to"| node_constituency_model
node_auth_router -->|"serializes"| node_user_schema
node_issue_router -->|"serializes"| node_issue_schema
node_comments_router -->|"serializes"| node_comment_schema
node_votes_router -->|"serializes"| node_vote_schema
node_auth_router -->|"issues"| node_token_schema
node_issue_router -->|"serializes"| node_constituency_schema
node_auth_router -->|"configures"| node_config
node_db -->|"configured by"| node_config
node_routes_tests -->|"uses"| node_test_fixtures
node_routes_tests -->|"covers"| node_auth_router
node_routes_tests -->|"covers"| node_issue_router
node_routes_tests -->|"covers"| node_comments_router
node_routes_tests -->|"covers"| node_votes_router
node_routes_tests -->|"verifies"| node_db

click node_main "https://github.com/naina-sriv/ftp/blob/main/app/main.py"
click node_auth_router "https://github.com/naina-sriv/ftp/blob/main/app/routers/auth.py"
click node_issue_router "https://github.com/naina-sriv/ftp/blob/main/app/routers/issue.py"
click node_comments_router "https://github.com/naina-sriv/ftp/blob/main/app/routers/comments.py"
click node_votes_router "https://github.com/naina-sriv/ftp/blob/main/app/routers/votes.py"
click node_config "https://github.com/naina-sriv/ftp/blob/main/app/core/config.py"
click node_security "https://github.com/naina-sriv/ftp/blob/main/app/core/security.py"
click node_dependencies "https://github.com/naina-sriv/ftp/blob/main/app/core/dependencies.py"
click node_db "https://github.com/naina-sriv/ftp/blob/main/app/db.py"
click node_user_model "https://github.com/naina-sriv/ftp/blob/main/app/models/user.py"
click node_constituency_model "https://github.com/naina-sriv/ftp/blob/main/app/models/constituency.py"
click node_issue_model "https://github.com/naina-sriv/ftp/blob/main/app/models/issue.py"
click node_comment_model "https://github.com/naina-sriv/ftp/blob/main/app/models/comment.py"
click node_vote_model "https://github.com/naina-sriv/ftp/blob/main/app/models/vote.py"
click node_user_schema "https://github.com/naina-sriv/ftp/blob/main/app/schema/user.py"
click node_constituency_schema "https://github.com/naina-sriv/ftp/blob/main/app/schema/constituency.py"
click node_issue_schema "https://github.com/naina-sriv/ftp/blob/main/app/schema/issue.py"
click node_comment_schema "https://github.com/naina-sriv/ftp/blob/main/app/schema/comment.py"
click node_vote_schema "https://github.com/naina-sriv/ftp/blob/main/app/schema/vote.py"
click node_token_schema "https://github.com/naina-sriv/ftp/blob/main/app/schema/token.py"
click node_routes_tests "https://github.com/naina-sriv/ftp/blob/main/tests/test_routes.py"
click node_test_fixtures "https://github.com/naina-sriv/ftp/blob/main/tests/conftest.py"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_main,node_auth_router,node_issue_router,node_comments_router,node_votes_router toneBlue
class node_config,node_security,node_dependencies toneAmber
class node_user_model,node_constituency_model,node_issue_model,node_comment_model,node_vote_model toneMint
class node_user_schema,node_constituency_schema,node_issue_schema,node_comment_schema,node_vote_schema,node_token_schema toneRose
class node_db toneIndigo
class node_routes_tests,node_test_fixtures toneTeal
```

## Components

### Application

FastAPI app bootstrap and HTTP entrypoints

- [App startup](https://github.com/naina-sriv/ftp/blob/main/app/main.py): FastAPI bootstrap · Creates the FastAPI application and wires routers. · `app/main.py`
- [Auth API](https://github.com/naina-sriv/ftp/blob/main/app/routers/auth.py): router · Registration and login endpoints. · `app/routers/auth.py`
- [Issue API](https://github.com/naina-sriv/ftp/blob/main/app/routers/issue.py): router · Issue CRUD endpoints. · `app/routers/issue.py`
- [Comment API](https://github.com/naina-sriv/ftp/blob/main/app/routers/comments.py): router · Issue comment endpoints. · `app/routers/comments.py`
- [Vote API](https://github.com/naina-sriv/ftp/blob/main/app/routers/votes.py): router · Voting and escalation endpoints. · `app/routers/votes.py`

### Core

Auth, config, and request dependencies

- [Settings](https://github.com/naina-sriv/ftp/blob/main/app/core/config.py): config · Environment-driven runtime settings. · `app/core/config.py`
- [Security](https://github.com/naina-sriv/ftp/blob/main/app/core/security.py): auth utils · Password hashing and JWT handling. · `app/core/security.py`
- [Auth guard](https://github.com/naina-sriv/ftp/blob/main/app/core/dependencies.py): dependency · Current-user dependency and access enforcement. · `app/core/dependencies.py`

### Domain

Persistent business entities

- [User](https://github.com/naina-sriv/ftp/blob/main/app/models/user.py): ORM model · Authenticated user records. · `app/models/user.py`
- [Constituency](https://github.com/naina-sriv/ftp/blob/main/app/models/constituency.py): ORM model · Scoping boundary for users and issues. · `app/models/constituency.py`
- [Issue](https://github.com/naina-sriv/ftp/blob/main/app/models/issue.py): ORM model · Reported civic issues and status. · `app/models/issue.py`
- [Comment](https://github.com/naina-sriv/ftp/blob/main/app/models/comment.py): ORM model · Comments attached to issues. · `app/models/comment.py`
- [Vote](https://github.com/naina-sriv/ftp/blob/main/app/models/vote.py): ORM model · Issue votes used for threshold checks. · `app/models/vote.py`

### Schemas

Pydantic request and response contracts

- [User schema](https://github.com/naina-sriv/ftp/blob/main/app/schema/user.py): Pydantic schema · User request and response payloads. · `app/schema/user.py`
- [Constituency schema](https://github.com/naina-sriv/ftp/blob/main/app/schema/constituency.py): Pydantic schema · Constituency payload contracts. · `app/schema/constituency.py`
- [Issue schema](https://github.com/naina-sriv/ftp/blob/main/app/schema/issue.py): Pydantic schema · Issue payload contracts. · `app/schema/issue.py`
- [Comment schema](https://github.com/naina-sriv/ftp/blob/main/app/schema/comment.py): Pydantic schema · Comment payload contracts. · `app/schema/comment.py`
- [Vote schema](https://github.com/naina-sriv/ftp/blob/main/app/schema/vote.py): Pydantic schema · Vote payload contracts. · `app/schema/vote.py`
- [Token schema](https://github.com/naina-sriv/ftp/blob/main/app/schema/token.py): Pydantic schema · JWT and auth token payloads. · `app/schema/token.py`

### Persistence

Database/session boundary

- [DB session](https://github.com/naina-sriv/ftp/blob/main/app/db.py): database · SQLAlchemy session and database boundary. · `app/db.py`

### Tests

End-to-end API coverage

- [Route tests](https://github.com/naina-sriv/ftp/blob/main/tests/test_routes.py): integration tests · End-to-end API and persistence coverage. · `tests/test_routes.py`
- [Test DB](https://github.com/naina-sriv/ftp/blob/main/tests/conftest.py): test fixture · SQLite test database fixture. · `tests/conftest.py`

## Connections

- App startup → Auth API: includes · Registers auth routes.
- App startup → Issue API: includes · Registers issue routes.
- App startup → Comment API: includes · Registers comment routes.
- App startup → Vote API: includes · Registers vote routes.
- Auth API → Security: hash/sign · Uses JWT and password utilities.
- Auth API → DB session: reads/writes · Persists and validates user records.
- Issue API → Auth guard: protects · Enforces authenticated and scoped access.
- Issue API → DB session: reads/writes · Persists issue changes.
- Comment API → Auth guard: protects · Uses current-user dependency.
- Comment API → DB session: reads/writes · Persists comments.
- Vote API → Auth guard: protects · Uses current-user dependency.
- Vote API → DB session: reads/writes · Persists votes and status updates.
- Vote API → Issue: escalates · Triggers threshold-based issue escalation.
- Auth guard → User: loads · Resolves the authenticated user.
- Auth guard → Constituency: scopes · Constrains access by constituency.
- Issue → Constituency: belongs to · Issues are reported within a constituency.
- Comment → Issue: attaches to · Comments belong to issues.
- Vote → Issue: attaches to · Votes belong to issues.
- User → Constituency: belongs to · Users are assigned to a constituency.
- Auth API → User schema: serializes · Uses user payload contracts.
- Issue API → Issue schema: serializes · Uses issue payload contracts.
- Comment API → Comment schema: serializes · Uses comment payload contracts.
- Vote API → Vote schema: serializes · Uses vote payload contracts.
- Auth API → Token schema: issues · Returns JWT/token payloads.
- Issue API → Constituency schema: serializes · Uses constituency payload contracts.
- Auth API → Settings: configures · Uses secret, algorithm, and expiry settings.
- DB session → Settings: configured by · Database URL comes from settings.
- Route tests → Test DB: uses · Runs against SQLite test database.
- Route tests → Auth API: covers · Exercises auth endpoints.
- Route tests → Issue API: covers · Exercises issue CRUD.
- Route tests → Comment API: covers · Exercises comment flows.
- Route tests → Vote API: covers · Exercises voting and escalation.
- Route tests → DB session: verifies · Validates request-to-database behavior.
