Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
dee2445
chore: dev init
zzjc1234 Sep 25, 2025
d157917
feat: auto deploy
zzjc1234 Sep 25, 2025
ffb777b
fix: dev.sh
zzjc1234 Sep 25, 2025
60a0a99
feat: docker compose tested
zzjc1234 Sep 25, 2025
0cc296a
Merge branch 'dev' into feat/deployment-script
zzjc1234 Sep 27, 2025
18b0a45
chore: use polling instead of sleep and update doc
A-lexisL Sep 27, 2025
205fecc
chore(Dockerfile): Use Python 3.13 and Debian 13
PACHAKUTlQ Sep 28, 2025
b3a29d2
Merge branch 'dev' into feat/deployment-script
zzjc1234 Sep 29, 2025
0e53795
chore(scripts): reorganzie path of scripts
zzjc1234 Sep 29, 2025
e249863
fix(docker): backend deployment with docker
zzjc1234 Sep 29, 2025
62fee0c
Merge branch 'dev' into feat/deployment-script
zzjc1234 Sep 30, 2025
3c1be34
feat: podman support
zzjc1234 Oct 8, 2025
f9d855c
feat: deploy with wsgi
zzjc1234 Oct 9, 2025
6b8cd9e
feat: distroless support
zzjc1234 Oct 9, 2025
f937496
chore: rm old shell script
zzjc1234 Oct 9, 2025
a01539a
fix: dependency
zzjc1234 Feb 17, 2026
10ae7f8
fix: ruff check
zzjc1234 Feb 17, 2026
e24ef16
fix: make podman stack run backend and frontend
zzjc1234 Feb 18, 2026
197e794
chore: update dependencies
zzjc1234 Feb 18, 2026
3308db1
chore: rm docker compose
zzjc1234 Feb 19, 2026
28c5828
chore: upgrade container version
zzjc1234 Feb 19, 2026
0a49eea
fix: rm docker compability
zzjc1234 Feb 19, 2026
0975000
fix: rm docker keywords
zzjc1234 Feb 19, 2026
ce25e95
fix: rm non ascii
zzjc1234 Feb 19, 2026
8df3106
chore: use the setup on the dev branch
zzjc1234 Feb 19, 2026
a373e43
fix: use uv instead of python3
zzjc1234 Feb 19, 2026
2a2be4b
chore: rewind submodule
zzjc1234 Feb 19, 2026
597267f
chore: use uv instead of python 3
zzjc1234 Feb 19, 2026
2d65641
chore: migrate create_admin and entrypoint
zzjc1234 Feb 19, 2026
71e44ee
chore: update compose
zzjc1234 Feb 19, 2026
b3327c2
chore: add gunicorn
zzjc1234 Feb 19, 2026
c901e49
fix(podman)!: Use env for credentials
PACHAKUTlQ Feb 19, 2026
c5cb3f6
fix(setup): Change non-exist `is_admin` to `is_superuser`
PACHAKUTlQ Feb 19, 2026
f2e70ca
style(dev): Format dev.sh
PACHAKUTlQ Feb 19, 2026
e191212
fix: Use relative paths for entrypoint script as convention
PACHAKUTlQ Feb 19, 2026
309f8c3
feat(podman)!: Rename Dockerfile to Containerfile
PACHAKUTlQ Feb 19, 2026
cc42c81
chore(podman): Add .containerignore
PACHAKUTlQ Feb 19, 2026
cd02f26
fix(setup)!: Remove static file collections
PACHAKUTlQ Feb 20, 2026
48dd31b
fix(setup)!: Install all dependencies groups like dev and lint
PACHAKUTlQ Feb 20, 2026
4cc6fd6
fix(setup): Add executable permission to dev.sh
PACHAKUTlQ Feb 20, 2026
34e890e
chore: add STATIC_ROOT env
A-lexisL Feb 20, 2026
12c698d
revert: adding STATIC_ROOT
A-lexisL Feb 20, 2026
b1aebcc
chore: Remove unused podman-compose
PACHAKUTlQ Feb 21, 2026
c601933
feat(setup): Support redirecting all output to both stdout and a log …
PACHAKUTlQ Feb 21, 2026
20b8f6d
fix(podman): Set default `DB_HOST` as `localhost`
PACHAKUTlQ Feb 21, 2026
7a2fef3
fix(setup): Only copy .env when no existing one
PACHAKUTlQ Feb 21, 2026
5574396
fix(podman)!: Remove unused frontend container
PACHAKUTlQ Feb 21, 2026
9b44db1
fix(podman)!: Enable Containerfile in podman-compose.yaml
PACHAKUTlQ Feb 21, 2026
35a6eb0
fix(setup)!: Use `valkey-cli` instead of `redis-cli`
PACHAKUTlQ Feb 21, 2026
b4c25f8
fix(podman): Respect env in postgres healthcheck
PACHAKUTlQ Feb 21, 2026
f32e1fd
fix!: Use `REDIS__URL` instead of `REDIS_URL` for consistency
PACHAKUTlQ Feb 21, 2026
cc61c0c
style(podman): Use dictionary instead of list
PACHAKUTlQ Feb 21, 2026
3a92304
fix(podman): Run python in unbuffered output mode for real time logging
PACHAKUTlQ Feb 21, 2026
d02e998
Revert "fix(podman): Set default `DB_HOST` as `localhost`"
PACHAKUTlQ Feb 24, 2026
a314977
fix(podman)!: Postgres use data/ dir
PACHAKUTlQ Feb 22, 2026
e71f114
fix(podman)!: Remove unused database env variables
PACHAKUTlQ Feb 22, 2026
ad2ade8
fix!: Use container name as host in .env file to make postgres happy
PACHAKUTlQ Feb 22, 2026
b19e5ab
fix(podman): Create gunicorn socket in /tmp instead of /app due to pe…
PACHAKUTlQ Feb 22, 2026
17d9ca2
fix(podman): Use `python` instead of `python3`
PACHAKUTlQ Feb 22, 2026
72bcbe9
fix(podman): Use `python` instead of `python3`
PACHAKUTlQ Feb 22, 2026
d598370
fix(podman): Podman ignore config.yaml
PACHAKUTlQ Feb 22, 2026
3888efa
fix(podman)!: Build with uv trixie image
PACHAKUTlQ Feb 22, 2026
257493e
chore: Update dependencies
PACHAKUTlQ Feb 23, 2026
ed721fa
fix! Remove scripts/dev.sh and Makefile
PACHAKUTlQ Feb 23, 2026
aa293bb
fix! Rename manage.py to django_manage.py to avoid confusion
PACHAKUTlQ Feb 23, 2026
3e1b61c
fix(podman)!: Stop running migrations in podman entrypoint script
PACHAKUTlQ Feb 23, 2026
44a67aa
refactor(podman)!: Use different compose file for using podman in dev…
PACHAKUTlQ Feb 23, 2026
44a0818
feat: Use an unified script for managing everything
PACHAKUTlQ Feb 23, 2026
ece4880
ci: Ignore the control script
PACHAKUTlQ Feb 23, 2026
ba841d3
style(run): Add new line before return and after exception to satisfy…
PACHAKUTlQ Feb 23, 2026
8470be2
fix(run): Fix mixed program name
PACHAKUTlQ Feb 23, 2026
745c5d3
fix(run): Normalize host to adapt to both podman and django requirements
PACHAKUTlQ Feb 23, 2026
e053469
ci(hook)!: Add more git hooks
PACHAKUTlQ Feb 23, 2026
b082ef1
ci(hook): Update ruff pre-commit hook version
PACHAKUTlQ Feb 23, 2026
96123f4
fix(hook)!: Pin python version to 3.14 to force prek check 3.14 AST
PACHAKUTlQ Feb 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .containerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
config.yaml
run.py
.git
.venv
.env
.ruff_cache
frontend
.github
docs
Makefile
.pre-commit-config.yaml
LICENSE
.gitignore
.containerignore
.gitmodules
podman-compose.yaml
__pycache__
*.py[codz]
**/__pycache__
**/*.py[codz]
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ SECRET_KEY=django-insecure-my-local-dev-secret-key
# --- Infrastructure (REQUIRED) ---
# Use a single URL for database and Redis connections.
# Format: driver://user:password@host:port/dbname
DATABASE__URL=postgres://admin:test@127.0.0.1:5432/coursereview
REDIS__URL=redis://localhost:6379/0
DATABASE__URL=postgres://admin:test@db:5432/coursereview
REDIS__URL=redis://cache:6379/0

# --- External Services Secrets (REQUIRED) ---
TURNSTILE_SECRET_KEY=dummy0
Expand Down
23 changes: 18 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
repos:
default_language_version:
python: 3.14

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- id: check-ast
- id: check-builtin-literals
- id: check-case-conflict
- id: check-illegal-windows-names
- id: check-json
- id: check-merge-conflict
- id: check-toml
- id: check-yaml
- id: detect-private-key
- id: end-of-file-fixer
- id: no-commit-to-branch
- id: pretty-format-json
- id: requirements-txt-fixer
- id: trailing-whitespace

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.5
rev: v0.15.2
hooks:
- id: ruff-check
types_or: [python, pyi]
Expand Down
20 changes: 20 additions & 0 deletions Containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM ghcr.io/astral-sh/uv:python3.14-trixie-slim AS builder

WORKDIR /app

COPY . /app

RUN UV_PROJECT_ENVIRONMENT=/usr/local \
uv sync --project=/app --frozen --compile-bytecode --no-dev --no-editable --no-managed-python

FROM gcr.io/distroless/base-debian13:nonroot

COPY --from=builder /usr/local /usr/local

COPY --from=builder /app /app

WORKDIR /app

USER nonroot

ENTRYPOINT ["python", "scripts/entrypoint.py"]
81 changes: 0 additions & 81 deletions Makefile

This file was deleted.

2 changes: 1 addition & 1 deletion apps/auth/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def get_survey_details(action: str) -> dict[str, Any] | None:

try:
question_id = int(action_details.get("QUESTIONID"))
except (ValueError, TypeError):
except ValueError, TypeError:
logger.error(
"Could not parse 'QUESTIONID' for action '%s'. Check your settings.", action
)
Expand Down
4 changes: 2 additions & 2 deletions apps/auth/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ def verify_callback_api(request):
otp_data = json.loads(otp_data_raw.decode("utf-8"))
expected_temp_token = otp_data.get("temp_token")
initiated_at = otp_data.get("initiated_at")
except (json.JSONDecodeError, AttributeError):
except json.JSONDecodeError, AttributeError:
logger.error("Invalid OTP data format in verify_callback_api")
return Response({"error": "Invalid OTP data format"}, status=401)

Expand Down Expand Up @@ -268,7 +268,7 @@ def verify_callback_api(request):
status=401,
)

except (ValueError, TypeError):
except ValueError, TypeError:
logger.error("Error parsing submission timestamp")
return Response({"error": "Invalid submission timestamp"}, status=401)

Expand Down
2 changes: 1 addition & 1 deletion apps/web/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def _filter_by_score(self, queryset):
try:
threshold = int(param_value)
queryset = queryset.filter(**{f"{field_name}__gte": threshold})
except (ValueError, TypeError):
except ValueError, TypeError:
pass
return queryset

Expand Down
34 changes: 34 additions & 0 deletions compose.dev.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
services:
db:
ports:
- "5432:5432"

cache:
ports:
- "6379:6379"

backend:
build:
context: .
dockerfile: Containerfile
ports:
- "8000:8000"
env_file:
- .env
environment:
DATABASE__URL: ${DATABASE__URL:-postgres://admin:test@db:5432/coursereview}
REDIS__URL: ${REDIS__URL:-redis://cache:6379/0}
volumes:
- ./config.yaml:/app/config.yaml:ro

migrate:
build:
context: .
dockerfile: Containerfile
env_file:
- .env
environment:
DATABASE__URL: ${DATABASE__URL:-postgres://admin:test@db:5432/coursereview}
REDIS__URL: ${REDIS__URL:-redis://cache:6379/0}
volumes:
- ./config.yaml:/app/config.yaml:ro
20 changes: 20 additions & 0 deletions compose.prod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
services:
backend:
ports:
- "8000:8000"
env_file:
- /etc/coursereview/secrets.env
environment:
DATABASE__URL: ${DATABASE__URL:-postgres://admin:test@db:5432/coursereview}
REDIS__URL: ${REDIS__URL:-redis://cache:6379/0}
volumes:
- /etc/coursereview/config.yaml:/app/config.yaml:ro

migrate:
env_file:
- /etc/coursereview/secrets.env
environment:
DATABASE__URL: ${DATABASE__URL:-postgres://admin:test@db:5432/coursereview}
REDIS__URL: ${REDIS__URL:-redis://cache:6379/0}
volumes:
- /etc/coursereview/config.yaml:/app/config.yaml:ro
61 changes: 61 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
services:
db:
image: postgres:18-alpine
volumes:
- postgres18_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: ${POSTGRES_DB:-coursereview}
POSTGRES_USER: ${POSTGRES_USER:-admin}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-test}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-admin} -d ${POSTGRES_DB:-coursereview}"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped

cache:
image: valkey/valkey:9-alpine
healthcheck:
test: ["CMD", "valkey-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped

backend:
image: coursereview-backend
depends_on:
db:
condition: service_healthy
cache:
condition: service_healthy
environment:
PYTHONUNBUFFERED: "1"
GUNICORN_CMD_ARGS: "--control-socket /tmp/gunicorn.ctl --worker-tmp-dir /tmp"
healthcheck:
test:
[
"CMD",
"python",
"-c",
"__import__('urllib.request').request.urlopen('http://127.0.0.1:8000/api/user/status/',timeout=5)",
]
interval: 15s
timeout: 5s
retries: 5
start_period: 20s
restart: unless-stopped

migrate:
image: coursereview-backend
depends_on:
db:
condition: service_healthy
environment:
PYTHONUNBUFFERED: "1"
command: ["python", "django_manage.py", "migrate"]
restart: "no"

volumes:
postgres18_data:
File renamed without changes.
13 changes: 11 additions & 2 deletions docs/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

- Ubuntu Linux (most modern Linux distros and MacOS are supposedly supported.)

- Use your corresponding package manager. This guide uses ubuntu/debian's `apt`, python `uv`, modern javascript runtime and package manager `bun`.
- Use your corresponding package manager. This guide uses ubuntu/debian's `apt`, python `uv`, modern javascript runtime, package manager `bun` and `podman`.

- python 3.10 to 3.13

Expand Down Expand Up @@ -39,7 +39,9 @@
8. Build static files: `make collect`

9. Configure database

1. Install Postgres:

- `sudo apt update`

- `sudo apt install postgresql`
Expand All @@ -53,6 +55,7 @@
5. Switch to user postgres: `sudo -iu postgres`

6. `psql`

1. Initialize coursereview database, user and privileges

```sql
Expand Down Expand Up @@ -93,6 +96,7 @@
11. `make run` and visit <http://127.0.0.1:8000/>

12. Add local admin:

1. `make createsuperuser`. The email can be blank. Use a strong password in production.

2. Enter interactive python shell: `make shell`. (Different from directly running `python` from shell.)
Expand All @@ -104,11 +108,12 @@
u = User.objects.last()
u.is_active = True
u.is_staff = True
u.is_admin = True
u.is_superuser = True
u.save()
```

13. Crawl data from JI official website:

1. Edit `COURSE_DETAIL_URL_PREFIX` in `apps/spider/crawlers/orc.py`: Add a number after url param `id` like this: `...?id=23`, so only course id starting from 23 (e.g. 230-239, 2300) will be crawled, so as to save time during development. Remember not to commit this change.

2. Enter interactive python shell: `make shell`.
Expand All @@ -121,9 +126,11 @@
```

## Frontend

Two ways to run/develop the frontend:

1. Git submodule (in `CourseReview/frontend`):

- `cd CourseReview` and run `git submodule update --init --recursive`
- Dev server: `make dev-frontend` (visit http://127.0.0.1:5173/)
- Development workflow: `cd CourseReview/frontend` (treat it like a normal repo)
Expand All @@ -133,7 +140,9 @@ Two ways to run/develop the frontend:
- Dev server: `cd CourseFront` then `bun run dev` (visit http://127.0.0.1:5173/)

### Set up

From the frontend directory (`CourseReview/frontend` or `CourseFront`):

1. `cp .env.example .env`

2. `bun install`
Expand Down
Loading