Compare commits

..

107 Commits

Author SHA1 Message Date
kschappell 4bddd74c8e use central cloudflared tunnel
CI / Backend (push) Failing after 15s
CI / Frontend (push) Successful in 1m37s
CI / Docker Build (push) Has been skipped
2025-09-14 20:33:15 +01:00
kschappell daf7218f87 uk spelling: visualisation 2025-09-14 19:58:37 +01:00
kschappell aee22755b7 uk spelling: labelled 2025-09-14 19:36:14 +01:00
kschappell 66151ad3c3 fix: API_URL env for server-side fetches 2025-09-14 19:24:31 +01:00
kschappell a93589ce81 fix(docker): API URL as build arg 2025-09-14 18:25:50 +01:00
kschappell 9cdc8b86de fix: empty public folder in frontend build 2025-09-14 17:28:26 +01:00
kschappell e5a6db99b1 update changelog 2025-09-12 16:29:54 +01:00
kschappell 6f0d143c6e viz primitives for data structures 2025-09-12 15:26:17 +01:00
kschappell b61c6d1613 feat(viz): trie visualisation 2025-09-12 15:08:18 +01:00
kschappell f23455c481 chore(deploy): prod deploy config 2025-09-12 14:57:04 +01:00
kschappell c7233e6917 learning progression + completion tracking 2025-09-12 14:12:38 +01:00
kschappell f579868d44 feat(progress): spaced repetition dashboard 2025-09-12 13:15:06 +01:00
kschappell 3c1535ed89 feat(content): pattern comparisons 2025-09-10 18:46:50 +01:00
kschappell 0ee388c420 migrate 392 questions to pattern format 2025-09-10 18:05:55 +01:00
kschappell 91e48f5239 feat(patterns): pattern taxonomy + is_optimal 2025-09-08 16:03:14 +01:00
kschappell 291b4aabd6 fix: single number → bit-manipulation pattern 2025-09-08 15:49:57 +01:00
kschappell 7bb600f898 feat(viz): wire up bit manipulation 2025-09-08 14:50:57 +01:00
kschappell 340aa6b9af feat(content): bit manipulation pattern 2025-09-08 14:46:22 +01:00
kschappell 8e31fc3cb5 single number algorithm def 2025-09-08 14:00:13 +01:00
kschappell 83dd6cbf19 feat(viz): bit manipulation algorithm component 2025-09-08 13:32:40 +01:00
kschappell 164fb212ef feat(viz): bit manipulation view 2025-09-04 00:36:55 +01:00
kschappell 4d1b84661a feat(viz): bit display primitive 2025-09-04 00:22:32 +01:00
kschappell eae444df77 feat(viz): bit manipulation types 2025-09-03 23:27:24 +01:00
kschappell 97f479a5cc feat(viz): union-find 2025-09-03 22:44:24 +01:00
kschappell 89164a031c feat(viz): backtracking, greedy, intervals, matrix 2025-09-03 21:47:33 +01:00
kschappell 4311e97d24 feat(viz): heap pattern with kth largest 2025-09-03 21:30:46 +01:00
kschappell cf0c2153db feat(viz): dp coin change 2025-09-01 21:29:23 +01:00
kschappell ed03d3251e feat(viz): tree/BFS/DFS patterns 2025-09-01 20:49:11 +01:00
kschappell ffecb9e591 fix viz layout stability 2025-08-24 17:43:46 +01:00
kschappell 45105e0b77 feat(viz): monotonic stack viz 2025-08-24 17:32:27 +01:00
kschappell e7ba79e49c linked list visualisations 2025-08-24 16:33:51 +01:00
kschappell f528d832c5 feat(viz): sprint 1 - array visualisations 2025-08-24 16:09:24 +01:00
kschappell 6fc2133238 feat(viz): two pointers narrative 2025-08-24 15:30:46 +01:00
kschappell f33dddfb4c feat(viz): interactive algorithm viz system 2025-08-23 20:28:22 +01:00
kschappell 5fa210cc8e feat(patterns): strategy tutorials 2025-08-23 19:58:33 +01:00
kschappell 7bf6d1f472 feat(patterns): data structure tutorials 2025-08-23 19:25:47 +01:00
kschappell f105ffa677 feat(patterns): pointer/array tutorials 2025-08-18 22:15:43 +01:00
kschappell c49042e242 feat(patterns): graph/tree traversal tutorials 2025-08-18 22:00:08 +01:00
kschappell deb2f64ea7 feat(patterns): tutorial system 2025-08-07 00:41:51 +01:00
kschappell 3fd3021d6e fix(frontend): make stats pages dynamic 2025-08-07 00:07:22 +01:00
kschappell 2727c053bb update changelog 2025-08-06 23:54:33 +01:00
kschappell e0bf8cda01 feat(content): hidden test cases 2025-08-06 23:21:42 +01:00
kschappell 8544efb5bf seo: sitemap, robots, og tags 2025-08-06 22:38:22 +01:00
kschappell 1e0cca1ef3 feat(frontend): big O complexity estimator 2025-07-31 15:05:41 +01:00
kschappell 9cf69e2c7e fix(backend): CORS and API URL fixes 2025-07-31 14:52:27 +01:00
kschappell 9b66718c29 submit ux improvements 2025-07-31 13:53:39 +01:00
kschappell 72ebe1c59f feat(frontend): add progress tracking 2025-07-31 13:23:11 +01:00
kschappell 0262ca8bf6 feat(content): function signatures + test cases 2025-07-13 19:53:34 +01:00
kschappell d65ccf7dc2 nit 2025-07-13 19:36:07 +01:00
kschappell 16b02451d0 feat(content): more test cases 2025-07-13 19:25:39 +01:00
kschappell 98ebb1600f update .env.example and docker config 2025-06-27 20:52:16 +01:00
kschappell 933b4cb5a6 fix(frontend): handle API errors gracefully 2025-06-27 20:27:54 +01:00
kschappell a4189ddeb8 remove duplicate question file 2025-06-20 16:05:43 +01:00
kschappell 3ad336caad feat(content): add new patterns 2025-06-20 16:02:40 +01:00
kschappell 3b2c882bb1 extend complexity fields to text 2025-06-20 15:10:37 +01:00
kschappell a5dbb2765f bump frontend deps 2025-06-20 14:40:28 +01:00
kschappell d93aec1443 feat(frontend): markdown and detail components 2025-06-20 13:53:44 +01:00
kschappell 33332439ac vitest setup + component tests 2025-05-30 21:16:27 +01:00
kschappell 2cf1ac3237 loading skeletons 2025-05-30 20:34:31 +01:00
kschappell 8ecb700316 fix docker build missing readme 2025-05-30 20:00:49 +01:00
kschappell 37f9102d80 feat(frontend): add question search 2025-05-30 19:27:31 +01:00
kschappell f7e491f1e8 questions S-W 2025-05-30 19:18:33 +01:00
kschappell 68699f35ec questions M-R 2025-05-25 12:43:25 +01:00
kschappell 917c371529 questions F-L 2025-05-25 11:47:04 +01:00
kschappell ecf95bd23d questions D-E 2025-05-25 11:08:40 +01:00
kschappell e6a22f98f8 questions C 2025-05-25 10:16:13 +01:00
kschappell 1e0aebfbfd questions B (backspace - burst-balloons) 2025-05-24 22:06:49 +01:00
kschappell 9eaafe4649 questions A (01-matrix - avoid-flood) 2025-05-24 21:40:39 +01:00
kschappell 9fc5da3a54 feat(content): test cases batch 2 2025-05-24 21:00:16 +01:00
kschappell 9b8f91ab19 feat(content): test cases batch 1 2025-05-24 20:55:37 +01:00
kschappell 1def615b9e feat(frontend): integrate editor into question page 2025-05-24 20:06:43 +01:00
kschappell 1078fdec8b submission api client 2025-05-24 19:33:40 +01:00
kschappell ec5cf52ce1 feat(frontend): add code editor 2025-05-21 21:48:52 +01:00
kschappell d62159e57c pyodide hook for python execution 2025-05-21 21:03:28 +01:00
kschappell 4784e55af8 feat(backend): data loader handles test cases 2025-05-21 20:41:04 +01:00
kschappell e53c0b854f feat(backend): test cases migration 2025-05-21 19:49:22 +01:00
kschappell a6313eed14 difficulty filters and clickable badges 2025-05-21 18:52:44 +01:00
kschappell 05a55d2288 badge colour variants 2025-05-07 23:23:35 +01:00
kschappell b091512c7d feat(frontend): visual improvements for content 2025-05-07 23:01:33 +01:00
kschappell 2c8b217e1f security and accessibility pass 2025-05-07 22:15:29 +01:00
kschappell e7c31c3ece ci pipeline and prod compose 2025-04-29 21:36:54 +01:00
kschappell 4e1158f6b5 frontend dockerfile 2025-04-29 21:28:45 +01:00
kschappell 874e8b8958 wire up pages 2025-04-29 21:06:13 +01:00
kschappell b62cf74e2a feat(frontend): add UI components 2025-04-29 20:51:49 +01:00
kschappell d29b1d9772 types and api client 2025-04-29 19:57:31 +01:00
kschappell 62d87efb66 frontend scaffold 2025-04-28 23:50:56 +01:00
kschappell a2ecd6aa85 hard questions 2025-04-28 23:19:49 +01:00
kschappell 877ef2fe30 medium tree, graph, dp questions 2025-04-28 23:04:27 +01:00
kschappell 9e04184b40 medium array/string questions 2025-04-28 22:51:54 +01:00
kschappell 2014689c5a easy questions 2025-04-28 21:47:07 +01:00
kschappell 7282fedebe chore(backend): add aiosqlite dep 2025-04-28 20:54:39 +01:00
kschappell e47ceca19a test(backend): add unit tests 2025-04-26 17:55:18 +01:00
kschappell f2945e12d9 feat(backend): add data loading scripts 2025-04-26 17:39:10 +01:00
kschappell 7552c059ef init files and module stubs 2025-04-21 22:51:36 +01:00
kschappell ec477a2fa7 backend dockerfile 2025-04-21 22:17:16 +01:00
kschappell 21d927f488 feat(content): initial question set 2025-04-21 21:17:13 +01:00
kschappell 72bea62663 feat(content): add categories and patterns 2025-04-21 20:44:21 +01:00
kschappell f7f2ab5a3e feat(backend): add API routes 2025-04-20 17:52:49 +01:00
kschappell 6e7131b84a feat(backend): add service layer 2025-04-20 16:56:56 +01:00
kschappell 1e4ba3bb93 feat(backend): add Pydantic schemas 2025-04-15 22:57:23 +01:00
kschappell 00a5b736f9 feat(backend): add Alembic migrations 2025-04-15 22:47:23 +01:00
kschappell 75d0d096df feat(backend): db session config 2025-04-15 21:54:14 +01:00
kschappell 02ee0c219f feat(backend): add database models 2025-04-11 00:02:04 +01:00
kschappell b6f1dd8942 feat(backend): add FastAPI app entry point 2025-04-10 23:30:50 +01:00
kschappell a5853d50fc backend config 2025-04-10 23:04:51 +01:00
kschappell 5ee9ac05f0 docker compose for dev 2025-04-10 22:48:45 +01:00
kschappell 7b9cadee9d initial project setup 2025-04-10 22:02:21 +01:00
2 changed files with 0 additions and 138 deletions
-89
View File
@@ -177,92 +177,3 @@ async def test_get_stats(client: AsyncClient, db_session: AsyncSession) -> None:
assert data["by_difficulty"]["easy"] == 1
assert len(data["by_category"]) == 1
assert len(data["by_pattern"]) == 1
async def test_get_pattern_tutorial(client: AsyncClient, db_session: AsyncSession) -> None:
await create_sample_data(db_session)
response = await client.get("/api/patterns/two-pointers/tutorial")
assert response.status_code == 200
data = response.json()
assert data["name"] == "Two Pointers"
assert data["learning_progression"]["warmup"][0]["title"] == "Two Sum"
assert len(data["learning_progression"]["core"]) == 0
async def test_get_pattern_tutorial_not_found(client: AsyncClient) -> None:
response = await client.get("/api/patterns/nonexistent/tutorial")
assert response.status_code == 404
async def test_submit_passing(client: AsyncClient, db_session: AsyncSession) -> None:
data = await create_sample_data(db_session)
q = data["question"]
q.test_cases = {
"visible": [{"input": {"nums": [2, 7], "target": 9}, "expected": [0, 1]}],
"hidden": [{"input": {"nums": [3, 2, 4], "target": 6}, "expected": [1, 2]}],
}
await db_session.commit()
response = await client.post(
"/api/questions/two-sum/submit",
json={
"code": "def solve(nums, t): pass",
"hidden_outputs": [{"test_id": 1, "output": [1, 2]}],
},
)
assert response.status_code == 200
result = response.json()
assert result["passed"] is True
assert result["total_passed"] == 1
async def test_submit_wrong_output(client: AsyncClient, db_session: AsyncSession) -> None:
data = await create_sample_data(db_session)
data["question"].test_cases = {
"visible": [],
"hidden": [{"input": {"nums": [1, 2], "target": 3}, "expected": [0, 1]}],
}
await db_session.commit()
response = await client.post(
"/api/questions/two-sum/submit",
json={
"code": "def solve(nums, t): pass",
"hidden_outputs": [{"test_id": 0, "output": [9, 9]}],
},
)
assert response.status_code == 200
assert response.json()["passed"] is False
async def test_submit_missing_output(client: AsyncClient, db_session: AsyncSession) -> None:
data = await create_sample_data(db_session)
data["question"].test_cases = {
"visible": [],
"hidden": [{"input": {"nums": [1, 2], "target": 3}, "expected": [0, 1]}],
}
await db_session.commit()
response = await client.post(
"/api/questions/two-sum/submit",
json={"code": "def solve(nums, t): pass", "hidden_outputs": []},
)
assert response.status_code == 200
assert response.json()["hidden_results"][0]["error"] == "No output provided"
async def test_submit_no_test_cases(client: AsyncClient, db_session: AsyncSession) -> None:
await create_sample_data(db_session)
response = await client.post(
"/api/questions/two-sum/submit",
json={"code": "pass", "hidden_outputs": []},
)
assert response.status_code == 400
async def test_submit_not_found(client: AsyncClient) -> None:
response = await client.post(
"/api/questions/nonexistent/submit",
json={"code": "pass", "hidden_outputs": []},
)
assert response.status_code == 404
-49
View File
@@ -215,55 +215,6 @@ class TestPatternService:
assert result is None
async def test_get_tutorial(self, db_session: AsyncSession) -> None:
related = Pattern(name="BFS", slug="bfs", description="Breadth-first search")
pattern = Pattern(
name="Two Pointers",
slug="two-pointers",
description="Two pointer technique",
common_mistakes=[
{"title": "Off by one", "description": "Wrong bounds", "fix": "Use <="}
],
variations=[{"name": "Fast/slow", "description": "Different speeds"}],
related_patterns=["bfs"],
visualization_examples=[{"id": "ex1", "title": "Basic", "code": "x=1", "steps": []}],
)
db_session.add_all([related, pattern])
await db_session.flush()
q1 = Question(
title="Easy Q", slug="easy-q", difficulty=Difficulty.EASY, description="Easy."
)
q2 = Question(title="Med Q", slug="med-q", difficulty=Difficulty.MEDIUM, description="Med.")
q3 = Question(
title="Hard Q", slug="hard-q", difficulty=Difficulty.HARD, description="Hard."
)
q1.patterns = [pattern]
q2.patterns = [pattern]
q3.patterns = [pattern]
db_session.add_all([q1, q2, q3])
await db_session.commit()
service = PatternService(db_session)
result = await service.get_pattern_tutorial("two-pointers")
assert result is not None
assert result.name == "Two Pointers"
assert len(result.common_mistakes) == 1
assert len(result.variations) == 1
assert len(result.related_patterns) == 1
assert result.related_patterns[0].slug == "bfs"
assert len(result.learning_progression.warmup) == 1
assert len(result.learning_progression.core) == 1
assert len(result.learning_progression.challenge) == 1
assert len(result.visualization_examples) == 1
async def test_get_tutorial_not_found(self, db_session: AsyncSession) -> None:
service = PatternService(db_session)
result = await service.get_pattern_tutorial("nonexistent")
assert result is None
class TestStatsService:
async def test_get_stats(self, db_session: AsyncSession) -> None: