Skip to content

Commit 8d8da16

Browse files
Finalize EduBuilder submission for EX1 EX2 and EX3
1 parent d5b233b commit 8d8da16

14 files changed

Lines changed: 777 additions & 1403 deletions

File tree

README.md

Lines changed: 82 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,78 @@
1-
# EduBuilder EX1 to EX3 Submission
1+
# EduBuilder - EX1 to EX3 Submission
22

3-
EduBuilder is a small, local-first product built around one consistent domain: **learning plans**.
3+
EduBuilder is a small, local-first product built around one consistent domain: **learning plans**. The same domain is reused through EX1, EX2, and EX3 so the repository can be graded as one incremental product.
44

5-
The repository is organized so you can present the project as three incremental exercises:
5+
## Quick setup
66

7-
- **EX1** — a clean FastAPI CRUD backend with in-memory storage
8-
- **EX2** — a lightweight Streamlit frontend that reuses the EX1 API as-is
9-
- **EX3** — a fuller local stack with SQLite/SQLModel persistence, JWT auth, Redis-backed rate limiting, a background worker, tests, Docker Compose, and runbooks
7+
### Create the `uv` environment
108

11-
> Older experimental files can remain as non-grading extras.
12-
> For grading, use the files listed below.
9+
```bash
10+
uv venv
11+
source .venv/bin/activate
12+
uv pip install -r requirements.txt
13+
```
1314

14-
---
15+
On Windows PowerShell:
1516

16-
## Assignment mapping
17+
```powershell
18+
uv venv
19+
.\.venv\Scripts\Activate.ps1
20+
uv pip install -r requirements.txt
21+
```
1722

18-
### EX1 – FastAPI Foundations
19-
Use these files for the EX1 grading scope:
23+
## Exercise map
24+
25+
### EX1 - FastAPI Foundations
26+
27+
Main files:
2028

2129
- `poseai_backend/main_ex1.py`
2230
- `tests/test_ex1_api.py`
2331
- `docs/EX1-notes.md`
2432

25-
What EX1 includes:
33+
Run EX1:
34+
35+
```bash
36+
uv run uvicorn poseai_backend.main_ex1:app --reload
37+
uv run pytest tests/test_ex1_api.py -q
38+
```
39+
40+
EX1 delivers:
2641

27-
- FastAPI backend
28-
- one core resource: `Plan`
42+
- FastAPI CRUD for one core resource: `Plan`
2943
- in-memory data layer
30-
- CRUD endpoints
3144
- Pydantic validation
32-
- pytest coverage using FastAPI `TestClient`
33-
- no authentication
34-
- local run instructions for the API and tests
45+
- pytest coverage with FastAPI `TestClient`
46+
- clear local run instructions
3547

36-
EX1 scope does **not** include authentication, JWT protection, role checks, token-expiry handling, or scope validation. Those capabilities are introduced in EX3 as part of the final multi-service project.
48+
### EX2 - Friendly Interface
3749

38-
### EX2 – Friendly Interface
39-
Use these files for the EX2 grading scope:
50+
Main files:
4051

4152
- `frontend/app_ex2.py`
4253
- `poseai_backend/main_ex1.py`
4354
- `docs/EX2-notes.md`
55+
- `tests/test_ex2_ui.py`
4456

45-
What EX2 includes:
57+
Run EX2:
4658

47-
- Streamlit interface
48-
- talks to the EX1 backend as-is
49-
- lists existing plans immediately
50-
- allows adding a new plan in one screen
59+
```bash
60+
uv run uvicorn poseai_backend.main_ex1:app --reload
61+
uv run streamlit run frontend/app_ex2.py
62+
```
63+
64+
EX2 delivers:
65+
66+
- Streamlit interface over the EX1 `/plans` API
5167
- no authentication or security prompts
52-
- one small extra: summary metrics + CSV export
68+
- list existing entries immediately
69+
- add a new entry through a lightweight chat-style flow
70+
- one small extra: summary metrics and CSV export
71+
- automated EX2 coverage for the prompt-to-plan flow and CSV export
72+
73+
### EX3 - Full-Stack Microservices Final Project
5374

54-
### EX3 – Full-Stack Microservices Final Project
55-
Use these files for the EX3 grading scope:
75+
Main files:
5676

5777
- `poseai_backend/main.py`
5878
- `poseai_backend/auth.py`
@@ -73,41 +93,50 @@ Use these files for the EX3 grading scope:
7393
- `tests/test_openapi.py`
7494
- `.github/workflows/ci.yml`
7595

76-
What EX3 includes:
96+
Run EX3 locally:
97+
98+
```bash
99+
uv run python -m scripts.migrate
100+
uv run python -m scripts.seed
101+
uv run uvicorn poseai_backend.main:app --reload
102+
uv run streamlit run frontend/app.py
103+
```
104+
105+
Run EX3 with Docker Compose:
106+
107+
```bash
108+
docker compose up --build
109+
```
110+
111+
EX3 delivers:
77112

78113
- FastAPI backend with SQLite persistence through SQLModel
79114
- Alembic migrations and seed script
80-
- Streamlit interface
115+
- Streamlit interface with chat-style course creation, My Courses, Shared Courses, and Admin Panel
81116
- Redis-backed rate limiting
82-
- async refresh worker with retries + idempotency
117+
- async refresh worker with retries and idempotency
83118
- JWT authentication and admin role checks
84-
- automated tests including worker and OpenAPI checks
85-
- Docker Compose orchestration for API + frontend + Redis + worker
86-
- a small enhancement: weekly learning-plan digest generation
87-
88-
> Before the final submission, replace the placeholder trace block in `docs/EX3-notes.md` with a real excerpt captured locally.
89-
90-
---
119+
- automated tests including worker and OpenAPI coverage
120+
- Docker Compose orchestration for API, frontend, Redis, and worker
121+
- one enhancement: weekly learning-plan digest generation
91122

92123
## Domain model
93124

94-
The core product resource is a **learning plan**.
125+
The core resource is a **learning plan**.
95126

96-
A plan contains:
97-
- title
98-
- goal
99-
- cues
100-
- difficulty level
101-
- visibility (`is_public`)
127+
Core fields:
102128

103-
In EX3 each plan also stores:
104-
- owner
105-
- optional weekly digest generated by the background worker
129+
- `title`
130+
- `goal`
131+
- `cues`
132+
- `level`
133+
- `is_public`
106134

107-
This keeps the domain narrow and consistent through EX1–EX3.
135+
EX3 adds:
108136

109-
---
137+
- `owner`
138+
- `weekly_digest`
110139

111140
## AI Assistance
112141

113-
AI tools were used as pair-programming aids for structure, tests, and documentation. All outputs were reviewed and verified locally before submission.
142+
AI tools were used as pair-programming aids for code structure, debugging, tests, and documentation. Outputs were reviewed, edited, and verified locally before submission.

docs/EX2-notes.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
# EX2 Notes EduBuilder Frontend
1+
# EX2 Notes - EduBuilder Frontend
22

33
This file presents **EX2 separately** from the richer EX3 interface.
44

55
## Goal
6-
Show a lightweight Streamlit interface connected to the EX1 API as-is.
6+
Show a lightweight Streamlit interface connected to the EX1 API as-is, while keeping a chat-style creation flow.
77

88
## Files used for EX2
99
- `frontend/app_ex2.py`
@@ -19,8 +19,9 @@ uv run streamlit run frontend/app_ex2.py
1919
```
2020

2121
## What this version includes
22+
- reuses the EX1 `/plans` API as-is
2223
- lists existing plans immediately from the backend
23-
- allows adding a new plan in one screen
24+
- allows adding a new plan through a chat-style prompt in one screen
2425
- no authentication or security prompts
2526
- one small extra:
2627
- summary metrics for the current catalog
@@ -29,6 +30,6 @@ uv run streamlit run frontend/app_ex2.py
2930
## Expected quick flow
3031
1. Start the FastAPI backend.
3132
2. Start the Streamlit frontend.
32-
3. Open the page and view the current catalog.
33-
4. Add a new plan from the form.
33+
3. Open the page and view the current catalog immediately.
34+
4. Add a new plan from the chat prompt.
3435
5. Optionally export the catalog to CSV.

docs/EX3-notes.md

Lines changed: 59 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,65 @@
1-
# EX3 Notes EduBuilder
1+
# EX3 Notes - EduBuilder
22

33
## 1. Final EX3 shape
44

55
EduBuilder is the final EX3 submission of a small, local-first learning-plan product.
66
It keeps one narrow domain across the course exercises and combines:
77

8-
- a FastAPI backend,
9-
- SQLite persistence through SQLModel,
10-
- a Streamlit frontend,
11-
- optional Redis support for rate limiting and worker coordination,
12-
- and an async background worker for digest generation.
13-
14-
The project is intentionally scoped to run on one laptop with local tools only.
8+
- a FastAPI backend
9+
- SQLite persistence through SQLModel
10+
- a Streamlit frontend
11+
- Redis support for rate limiting and worker coordination
12+
- an async background worker for digest generation
1513

1614
## 2. Services in the local architecture
1715

18-
### 2.1 API service
16+
### API service
1917

2018
Implemented in `poseai_backend/main.py`.
2119

2220
Responsibilities:
2321

24-
- register and login users,
25-
- issue JWT access tokens,
26-
- expose public plan browsing routes,
27-
- expose authenticated plan-management routes,
28-
- expose admin-only routes,
29-
- return health information,
30-
- include rate-limit headers when Redis is available.
22+
- register and login users
23+
- issue JWT access tokens
24+
- expose public plan browsing routes
25+
- expose authenticated plan-management routes
26+
- expose admin-only routes
27+
- return health information
28+
- include rate-limit headers when Redis is available
3129

32-
### 2.2 Persistence layer
30+
### Persistence layer
3331

3432
Implemented with SQLite + SQLModel + Alembic.
3533

3634
Responsibilities:
3735

38-
- persist users and plans locally,
39-
- keep the schema reproducible through migrations,
40-
- allow clean local setup without committing a database artifact.
36+
- persist users and plans locally
37+
- keep the schema reproducible through migrations
38+
- allow clean local setup without committing a database artifact
4139

42-
### 2.3 Frontend service
40+
### Frontend service
4341

4442
Implemented in `frontend/app.py`.
4543

4644
Responsibilities:
4745

48-
- browse shared plans quickly,
49-
- register and sign in,
50-
- create, edit, and delete personal plans through the backend,
51-
- keep the user flow simple enough for a short demo.
46+
- browse shared plans quickly
47+
- register and sign in
48+
- create, edit, and delete personal plans through the backend
49+
- keep the user flow simple enough for a short demo
50+
- preserve the chat-style course creation experience
5251

53-
### 2.4 Worker service
52+
### Worker service
5453

5554
Implemented in `scripts/refresh.py`.
5655

5756
Responsibilities:
5857

59-
- scan public plans,
60-
- generate a weekly digest,
61-
- retry transient failures,
62-
- prevent duplicate work with Redis-backed idempotency keys when Redis is enabled,
63-
- keep concurrency bounded.
58+
- scan public plans
59+
- generate a weekly digest
60+
- retry transient failures
61+
- prevent duplicate work with Redis-backed idempotency keys
62+
- keep concurrency bounded
6463

6564
## 3. Compose orchestration
6665

@@ -71,31 +70,29 @@ The repository includes `compose.yaml` with these cooperating services:
7170
- `redis`
7271
- `worker`
7372

74-
This satisfies the EX3 requirement for a local multi-service stack that can be launched with Docker Compose.
75-
76-
For daily local development, the API can also run without Docker by setting `DISABLE_REDIS=1`.
73+
This satisfies the EX3 requirement for a local multi-service stack launched with Docker Compose.
7774

7875
## 4. Async refresher deliverable
7976

8077
The async refresher is implemented in `scripts/refresh.py`.
8178

8279
It includes:
8380

84-
- bounded concurrency via `anyio.CapacityLimiter`,
85-
- retry handling for transient failures,
86-
- Redis-backed idempotency keys,
87-
- worker settings through environment variables,
88-
- automated coverage with a `pytest.mark.anyio` worker test.
81+
- bounded concurrency via `anyio.CapacityLimiter`
82+
- retry handling for transient failures
83+
- Redis-backed idempotency keys
84+
- worker settings through environment variables
85+
- automated coverage with a `pytest.mark.anyio` worker test
8986

9087
## 5. Security baseline
9188

9289
The EX3 security baseline in this project includes:
9390

94-
- hashed credentials,
95-
- JWT-protected create / update / delete plan flows,
96-
- role-aware authorization for admin-only endpoints,
97-
- tests that cover expired tokens,
98-
- tests that cover missing scope / missing permissions.
91+
- hashed credentials
92+
- JWT-protected create, update, and delete plan flows
93+
- role-aware authorization for admin-only endpoints
94+
- tests that cover expired tokens
95+
- tests that cover missing scope and missing permissions
9996

10097
### JWT secret rotation steps
10198

@@ -131,21 +128,28 @@ uv run streamlit run frontend/app.py
131128

132129
## 9. Trace excerpt
133130

134-
Paste the real local excerpt below after running:
135-
136-
```bash
137-
uv run python scripts/capture_trace_excerpt.py
131+
The block below is intended to be refreshed locally with `uv run python scripts/capture_trace_excerpt.py`.
132+
It now records both the HTTP health checks and a small Redis trace tied to the worker/idempotency flow.
133+
134+
<!-- TRACE_EXCERPT_START -->
135+
```text
136+
# local-redis-trace
137+
GET /health -> 200
138+
GET /plans -> 200
139+
GET /plans/shared -> 200
140+
REDIS PING -> True
141+
REDIS SETEX trace:edubuilder:demo -> OK
142+
REDIS GET trace:edubuilder:demo -> worker-idempotency-ok
138143
```
139-
140-
[PASTE LOCAL TRACE EXCERPT HERE]
144+
<!-- TRACE_EXCERPT_END -->
141145

142146
## 10. Notes for the grader
143147

144148
EduBuilder is intentionally local-first and limited in scope.
145149
The goal is not production deployment, but a tidy demonstration of:
146150

147-
- backend + persistence + frontend integration,
148-
- one additional background microservice,
149-
- basic local security controls,
150-
- automated tests,
151-
- and reproducible local setup.
151+
- backend + persistence + frontend integration
152+
- one additional background microservice
153+
- basic local security controls
154+
- automated tests
155+
- reproducible local setup

0 commit comments

Comments
 (0)