Skip to content

Commit 6e44ac5

Browse files
committed
Initial release
0 parents  commit 6e44ac5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1203
-0
lines changed

.env.example

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Database settings
2+
DB_NAME=fintech_db
3+
DB_USER=fintech_user
4+
DB_PASSWORD=fintech_password
5+
6+
# Application secret key
7+
SECRET_KEY=your-secret-key-for-security

.github/workflows/ci.yml

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
name: CI Pipeline
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
jobs:
10+
lint:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout code
14+
uses: actions/checkout@v4
15+
16+
- name: Set up Python
17+
uses: actions/setup-python@v5
18+
with:
19+
python-version: '3.11'
20+
21+
- name: Set up Node.js
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: '20'
25+
cache: 'npm'
26+
cache-dependency-path: 'frontend/package-lock.json'
27+
28+
- name: Install backend dependencies
29+
run: pip install -r ns-python-react-exercise/backend/requirements.txt
30+
31+
- name: Install frontend dependencies
32+
run: |
33+
cd ns-python-react-exercise/frontend
34+
npm ci
35+
36+
- name: Run backend linters
37+
run: |
38+
cd ns-python-react-exercise/backend
39+
flake8 .
40+
black --check .
41+
42+
- name: Run frontend linter
43+
run: |
44+
cd ns-python-react-exercise/frontend
45+
npm run lint
46+
47+
backend_tests:
48+
runs-on: ubuntu-latest
49+
needs: lint
50+
services:
51+
db:
52+
image: postgres:18.1
53+
env:
54+
POSTGRES_DB: fintech_db
55+
POSTGRES_USER: fintech_user
56+
POSTGRES_PASSWORD: fintech_password
57+
ports:
58+
- 5432:5432
59+
options: >-
60+
--health-cmd "pg_isready -U fintech_user -d fintech_db"
61+
--health-interval 5s
62+
--health-timeout 5s
63+
--health-retries 5
64+
65+
steps:
66+
- name: Checkout code
67+
uses: actions/checkout@v4
68+
69+
- name: Set up Python
70+
uses: actions/setup-python@v5
71+
with:
72+
python-version: '3.11'
73+
74+
- name: Install backend dependencies
75+
run: pip install -r ns-python-react-exercise/backend/requirements.txt
76+
77+
- name: Run backend tests
78+
run: |
79+
cd ns-python-react-exercise
80+
pytest
81+
env:
82+
DATABASE_URL: postgresql://fintech_user:fintech_password@localhost:5432/fintech_db
83+
SECRET_KEY: test-secret-key
84+
85+
frontend_e2e_tests:
86+
runs-on: ubuntu-latest
87+
needs: lint
88+
steps:
89+
- name: Checkout code
90+
uses: actions/checkout@v4
91+
92+
- name: Set up Node.js
93+
uses: actions/setup-node@v4
94+
with:
95+
node-version: '20'
96+
cache: 'npm'
97+
cache-dependency-path: 'frontend/package-lock.json'
98+
99+
- name: Install frontend dependencies
100+
run: |
101+
cd ns-python-react-exercise/frontend
102+
npm ci
103+
104+
- name: Install Playwright Browsers
105+
run: |
106+
cd ns-python-react-exercise/frontend
107+
npx playwright install --with-deps
108+
109+
- name: Build and start services
110+
run: |
111+
cd ns-python-react-exercise
112+
docker-compose up -d --build
113+
114+
- name: Run Playwright tests
115+
run: |
116+
cd ns-python-react-exercise/frontend
117+
npx playwright test

README.md

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# Welcome, Future Teammate!
2+
3+
Hey there! Thanks for taking the time to do this exercise. We've designed it to be a fun and challenging way to get a feel for the kind of work we do here. It's a chance for you to showcase your skills as a builder, problem-solver, and mentor across the full stack.
4+
5+
This isn't a typical coding test with a single right answer. We're much more interested in your thought process, how you handle trade-offs, and your ability to navigate a pre-existing (and slightly imperfect) codebase using a realistic Git workflow.
6+
7+
**A Quick Note on Time:** We estimate this exercise could take between 2 to 4 hours. However, we've intentionally included more work than can be done in that time. **Please do not feel pressured to complete everything.** Prioritization is a key skill, and we want to see how you approach a task with real-world time constraints.
8+
9+
## The Scenario: A FinTech Transaction Dashboard
10+
11+
You've just joined a new team building a dashboard for visualizing financial transactions. The application is composed of a Python (FastAPI) backend and a React (TypeScript) frontend. Your mission is to get familiar with the codebase, review a teammate's contribution, fix some underlying issues, and then build out a new feature.
12+
13+
---
14+
15+
## Your Mission: A Three-PR Workflow
16+
17+
**Important First Step:** Before you begin, please **fork this repository**. You will work entirely on your own fork, creating pull requests within that repository. **Do not create any pull requests to the original upstream repository.**
18+
19+
Your work will be organized into three separate pull requests within your own repository. We recommend following these steps in order.
20+
21+
### A Quick Glossary of Branches
22+
23+
* **`main`**: The initial state of the codebase. You will branch from here.
24+
* **`fix-bug-666`**: A simulated PR from a junior developer. This branch contains their work for you to review.
25+
* **`fix/haunted-codebase`**: The branch you will create from `main` to fix the existing technical debt (the N+1 and re-render bugs).
26+
* **`feature/transaction-tags-grid`**: The branch you will create from `fix/haunted-codebase` for the new feature (database migration and data grid).
27+
28+
29+
### Step 0: Getting Up and Running
30+
31+
1. **Clone Your Fork:** Clone your newly forked repository to your local machine.
32+
2. **Set Up Environment:** We've included a `docker-compose.yml` file for setup. You'll need to create a `.env` file from the `.env.example` template.
33+
3. **Launch the App:** Run `docker-compose up --build`. This will spin up the backend, frontend, and database. The database will be automatically seeded with initial data the first time it starts.
34+
4. **Explore:** The frontend is at `http://localhost:3000` and the API docs are at `http://localhost:8000/docs`. Get a feel for the app and the code on the `main` branch.
35+
36+
### Running Tests
37+
38+
We have set up a comprehensive testing suite for this project. A helper script is provided to run all tests and install any necessary dependencies automatically.
39+
40+
From the root of the `ns-python-react-exercise` directory, run the test script:
41+
```bash
42+
./run-tests.sh
43+
```
44+
This will execute the backend tests (unit, integration, E2E) and the frontend Playwright E2E tests.
45+
46+
### PR #1: The Code Review
47+
48+
Your first task is to act as a mentor and review a "PR" from a junior developer.
49+
50+
1. **Understand the Context:** The junior dev's work is on the `fix-bug-666` branch. On that branch, read the `BUG-666.md` file to understand the original problem.
51+
2. **Open the PR:** In your own repository, open a pull request from `fix-bug-666` to your `main` branch. Use the PR description template below.
52+
3. **Perform the Review:** Go to the "Files Changed" tab of the PR you just created. Leave comments directly on the code, providing a mix of high-level architectural feedback and specific line-by-line notes.
53+
4. **Abandon the PR:** Once your review is complete, **close the pull request without merging.**
54+
55+
#### PR #1 Description Template
56+
```md
57+
### What I Did
58+
This PR fixes the transaction display bug by filtering transactions on the frontend to only show relevant entries. I've also implemented server-side pagination for better performance.
59+
60+
### How to Test
61+
1. Checkout this branch.
62+
2. Run `docker-compose up --build`.
63+
3. Navigate to the frontend at `http://localhost:3000`.
64+
4. Observe that only relevant transactions are displayed.
65+
5. Verify that pagination controls are now active and functional.
66+
67+
### Architectural Decision Record (ADR)
68+
To address the display bug, I decided to handle filtering directly in the frontend component. This approach simplifies the backend and leverages the client's processing power for a snappier user experience. For pagination, I added a new `GET` parameter `page` and `page_size` to the existing `/api/v1/transactions/` endpoint, and updated the frontend to send these parameters.
69+
70+
### AI Usage Summary
71+
I used AI tools for minor code refactoring and to generate some boilerplate for the frontend pagination component.
72+
```
73+
74+
### PR #1: The Code Review
75+
76+
Your first task is to act as a mentor and review a "PR" from a junior developer.
77+
78+
1. **Understand the Context:** The junior dev's work is on the `fix-bug-666` branch. On that branch, read the `BUG-666.md` file to understand the original problem.
79+
2. **Open the PR:** In your own repository, open a pull request from `fix-bug-666` to your `main` branch. Use the PR description template below.
80+
3. **Perform the Review:** Go to the "Files Changed" tab of the PR you just created. Leave comments directly on the code, providing a mix of high-level architectural feedback and specific line-by-line notes.
81+
4. **Abandon the PR:** Once your review is complete, **close the pull request without merging.**
82+
83+
#### PR #1 Description Template
84+
```md
85+
### What I Did
86+
This PR fixes the transaction display bug by filtering transactions on the frontend to only show relevant entries. I've also implemented server-side pagination for better performance.
87+
88+
### How to Test
89+
1. Checkout this branch.
90+
2. Run `docker-compose up --build`.
91+
3. Navigate to the frontend at `http://localhost:3000`.
92+
4. Observe that only relevant transactions are displayed.
93+
5. Verify that pagination controls are now active and functional.
94+
95+
### Architectural Decision Record (ADR)
96+
To address the display bug, I decided to handle filtering directly in the frontend component. This approach simplifies the backend and leverages the client's processing power for a snappier user experience. For pagination, I added a new `GET` parameter `page` and `page_size` to the existing `/api/v1/transactions/` endpoint, and updated the frontend to send these parameters.
97+
98+
### AI Usage Summary
99+
I used AI tools for minor code refactoring and to generate some boilerplate for the frontend pagination component.
100+
```
101+
102+
### PR #2: Fixing Technical Debt
103+
104+
Now, it's time to fix the *other* bugs lurking in the `main` branch.
105+
106+
1. **Create a Branch:** From your `main` branch, create a new branch. We suggest `fix/haunted-codebase`.
107+
2. **Hunt the Bugs:** Investigate the following reports:
108+
* **Backend Report:** "Users are reporting that the main transaction list is loading very slowly, especially for users with many transactions. Our initial investigation suggests the API endpoint might be making an excessive number of database calls."
109+
* **Frontend Report:** "The product owner noticed that when they hover over their user profile icon in the header, the main data grid seems to flicker and re-render, even though the data hasn't changed. This is causing a sluggish feel on the dashboard. The React Profiler might be useful for confirming this."
110+
3. **Open the PR:**
111+
* Open a new pull request in your repository from `fix/haunted-codebase` to `main`.
112+
* Use the PR description template for PRs #2 and #3 below.
113+
* **Leave this pull request open** for us to review.
114+
115+
### PR #3: New Feature Development (Stacked PR)
116+
117+
With the codebase stabilized, you can now build the new feature. This PR will be "stacked" on top of PR #2, meaning it builds directly on the changes made in `fix/haunted-codebase`.
118+
119+
1. **Create a Branch:** From your `fix/haunted-codebase` branch, create a new branch. We suggest `feature/transaction-tags-grid`.
120+
* *Note: Because this is a "stacked" PR, you will see the commits from your `fix/haunted-codebase` branch also included in this pull request. This is expected.*
121+
2. **The "Twist":** The new feature requires a database change. The current schema has a one-to-one relationship, but the feature needs a **one-to-many relationship**. Design and execute this migration first.
122+
3. **Build the Feature:**
123+
* **Backend:** Create a new API endpoint that uses a **raw SQL query with a multi-table `JOIN`**.
124+
* **Frontend:** Build a **data grid** with **server-side sorting and pagination**.
125+
4. **Open the PR:**
126+
* Open a new pull request from `feature/transaction-tags-grid` to your `main` branch.
127+
* Use the PR description template for PRs #2 and #3 below. In your description, please explicitly mention that this PR builds on `fix/haunted-codebase` and link to PR #2.
128+
* **Leave this pull request open** for us to review.
129+
130+
---
131+
132+
## The Deliverable
133+
134+
The final deliverable is **a link to your forked repository.** When you submit it, we expect to see the following:
135+
136+
* **PR #1 (Code Review):** A **closed** pull request from `fix-bug-666` to `main`, containing your review comments.
137+
* **PR #2 (Bug Fixes):** An **open** pull request from `fix/haunted-codebase` to `main`, containing the fixes for the N+1 and re-render bugs.
138+
* **PR #3 (New Feature):** An **open** pull request from `feature/transaction-tags-grid` to `main`, containing the database migration and the new data grid feature. This PR will implicitly include the commits from PR #2 as its base.
139+
140+
### PR Description Template for PRs #2 and #3
141+
142+
For PRs #2 and #3, please use this template:
143+
144+
```md
145+
### What I Did
146+
(A brief summary of the changes in this PR.)
147+
148+
### Depends On
149+
(If this PR builds on another, like PR #3 builds on PR #2, link it here.)
150+
151+
### How to Test
152+
(Clear instructions on how to test the changes in this PR.)
153+
154+
### Architectural Decision Record (ADR)
155+
(A short explanation of significant decisions. For PR #3, this should cover the DB migration and state management.)
156+
157+
### AI Usage Summary
158+
(A high-level summary of how you used AI tools.)
159+
```
160+
161+
---
162+
163+
Good luck, and have fun! We're excited to see your work.

backend/Dockerfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
FROM python:3.11-slim
2+
3+
WORKDIR /app
4+
5+
COPY requirements.txt .
6+
RUN pip install --no-cache-dir -r requirements.txt
7+
8+
COPY . .
9+
10+
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

backend/app/__init__.py

Whitespace-only changes.

backend/app/api/__init__.py

Whitespace-only changes.

backend/app/api/v1/__init__.py

Whitespace-only changes.

backend/app/api/v1/endpoints/__init__.py

Whitespace-only changes.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from typing import List
2+
from fastapi import APIRouter, Depends, HTTPException, status
3+
from sqlalchemy.orm import Session
4+
5+
from app.crud import crud_transaction
6+
from app.schemas.transaction import TransactionCreate, TransactionUpdate, TransactionInDB
7+
from app.db.session import get_db
8+
9+
router = APIRouter()
10+
11+
@router.post("/transactions/", response_model=TransactionInDB)
12+
def create_new_transaction(transaction: TransactionCreate, db: Session = Depends(get_db)):
13+
return crud_transaction.create_transaction(db=db, transaction=transaction, user_id=1)
14+
15+
@router.get("/transactions/", response_model=List[TransactionInDB])
16+
def read_transactions(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
17+
transactions = crud_transaction.get_transactions(db, skip=skip, limit=limit)
18+
return transactions
19+
20+
@router.get("/transactions/{transaction_id}", response_model=TransactionInDB)
21+
def read_transaction(transaction_id: int, db: Session = Depends(get_db)):
22+
transaction = crud_transaction.get_transaction(db, transaction_id=transaction_id)
23+
if transaction is None:
24+
raise HTTPException(status_code=404, detail="Transaction not found")
25+
return transaction
26+
27+
@router.put("/transactions/{transaction_id}", response_model=TransactionInDB)
28+
def update_existing_transaction(
29+
transaction_id: int, transaction: TransactionUpdate, db: Session = Depends(get_db)
30+
):
31+
db_transaction = crud_transaction.update_transaction(db, transaction_id, transaction)
32+
if db_transaction is None:
33+
raise HTTPException(status_code=404, detail="Transaction not found")
34+
return db_transaction
35+
36+
@router.delete("/transactions/{transaction_id}", response_model=TransactionInDB)
37+
def delete_existing_transaction(transaction_id: int, db: Session = Depends(get_db)):
38+
db_transaction = crud_transaction.delete_transaction(db, transaction_id)
39+
if db_transaction is None:
40+
raise HTTPException(status_code=404, detail="Transaction not found")
41+
return db_transaction

backend/app/core/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)