Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
29068c3
docs: define full-stack completion architecture
computersciencefreshmen Jul 19, 2026
6c0048e
feat(server): add persistent API and secure auth
computersciencefreshmen Jul 19, 2026
de8f142
feat(domain): add course review and booking workflows
computersciencefreshmen Jul 19, 2026
96cacc5
feat(homework): add submission and grading workflow
computersciencefreshmen Jul 19, 2026
6c49837
feat(platform): add notifications files and dialogue services
computersciencefreshmen Jul 19, 2026
73cc8e2
feat(profile): add teacher professional settings
computersciencefreshmen Jul 19, 2026
ce5720c
feat(auth): deliver verification codes through SMTP
computersciencefreshmen Jul 19, 2026
d40f378
feat(classroom): add ticketed realtime collaboration
computersciencefreshmen Jul 19, 2026
0d6c221
fix(appointments): complete notification and classroom links
computersciencefreshmen Jul 19, 2026
6ed9717
fix(database): add ordered legacy-safe migrations
computersciencefreshmen Jul 19, 2026
3ddc657
feat(operations): add secure administrator bootstrap
computersciencefreshmen Jul 19, 2026
88825c9
feat(workflows): close classroom and assignment lifecycles
computersciencefreshmen Jul 19, 2026
78ed15d
feat(frontend): connect secure role workspaces
computersciencefreshmen Jul 19, 2026
4fc45ab
feat(workflows): connect complete teaching journeys
computersciencefreshmen Jul 19, 2026
91fc94d
feat(classroom): connect realtime and dialogue experiences
computersciencefreshmen Jul 19, 2026
5cf3325
feat(deploy): add hardened container operations
computersciencefreshmen Jul 19, 2026
ebb6092
fix(deps): resolve production security advisories
computersciencefreshmen Jul 19, 2026
a3208af
feat(security): harden production trust boundaries
computersciencefreshmen Jul 20, 2026
8836a37
test(e2e): verify four cross-role workflows
computersciencefreshmen Jul 20, 2026
c7d7bdc
docs: present the complete full-stack platform
computersciencefreshmen Jul 20, 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
27 changes: 27 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.git
.github
.agents
.codex
.vscode
.idea

node_modules
.pnpm-store
dist
.data
coverage
playwright-report
test-results

.env
.env.*
*.log
pnpm-debug.log*

docs
e2e
server/test
README.md
README.en.md
SECURITY.md
docker-compose*.yml
34 changes: 28 additions & 6 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,8 +1,30 @@
# REST API origin. Do not include a trailing slash.
VITE_API_BASE_URL=http://localhost:7777
# The browser uses the same-origin API path in development and production.
# Override only when a reverse proxy exposes this service at another path.
VITE_API_BASE_URL=/api/v1

# Full endpoint used by the forum/keyword-processing feature.
VITE_FORUM_API_URL=http://localhost:5002/process_words
# API server settings. The database and uploads stay local unless explicitly changed.
HOST=127.0.0.1
PORT=7777
DATABASE_PATH=.data/platform.db
UPLOAD_DIR=.data/uploads
# Per-account quota defaults to 250 MiB; the platform cap defaults to 5 GiB.
UPLOAD_OWNER_QUOTA_BYTES=262144000
UPLOAD_TOTAL_QUOTA_BYTES=5368709120
UPLOAD_MAX_CONCURRENT=4
APP_ORIGIN=http://localhost:5173
SESSION_TTL_HOURS=12
VERIFICATION_CODE_SECRET=

# WebSocket endpoint used by chat and live-class signaling.
VITE_WEBSOCKET_URL=ws://localhost:7788/websocket
# One-time production administrator bootstrap (pnpm admin:bootstrap).
ADMIN_EMAIL=
ADMIN_PASSWORD=
ADMIN_DISPLAY_NAME=平台管理员

# Optional external adapters. Core demo flows work without these values.
SMTP_URL=
MAIL_FROM=International Chinese Platform <no-reply@example.com>
AI_API_URL=
AI_API_KEY=
TURN_URL=
TURN_USERNAME=
TURN_CREDENTIAL=
95 changes: 88 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,104 @@ jobs:
- name: Set up pnpm
uses: pnpm/action-setup@v4
with:
version: 8.15.9
version: 11.9.0
run_install: false

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
node-version: 24
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Lint
run: pnpm lint:check
- name: Validate source, API and production build
run: pnpm check
env:
NODE_ENV: test
CI: true

- name: Check formatting
run: pnpm format:check
- name: Upload production bundle
uses: actions/upload-artifact@v4
with:
name: international-chinese-platform-dist
path: dist
if-no-files-found: error
retention-days: 7

e2e:
name: Cross-role browser E2E
runs-on: ubuntu-latest
timeout-minutes: 20

steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Build
- name: Set up pnpm
uses: pnpm/action-setup@v4
with:
version: 11.9.0
run_install: false

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: pip
cache-dependency-path: e2e/requirements.txt

- name: Install application dependencies
run: pnpm install --frozen-lockfile

- name: Build production application
run: pnpm build

- name: Install browser test dependencies
run: |
python -m pip install --requirement e2e/requirements.txt
python -m playwright install --with-deps chromium

- name: Start isolated production service
env:
NODE_ENV: production
SEED_ON_START: 'true'
SECURE_COOKIES: 'false'
APP_ORIGIN: http://localhost:7777
VERIFICATION_CODE_SECRET: e2e-only-verification-secret-32-characters
DATABASE_PATH: .data/e2e.db
run: |
mkdir -p test-results/e2e .data
rm -f .data/e2e.db .data/e2e.db-shm .data/e2e.db-wal
pnpm start > test-results/e2e/service.log 2>&1 &
echo $! > test-results/e2e/service.pid

- name: Run cross-role browser workflows
env:
E2E_BASE_URL: http://localhost:7777
run: python e2e/test_workflows.py

- name: Upload E2E failure artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: international-chinese-platform-e2e-failure
path: |
test-results/e2e
.data/e2e.db
if-no-files-found: warn
retention-days: 7

- name: Stop production service
if: always()
run: |
if [ -f test-results/e2e/service.pid ]; then
kill "$(cat test-results/e2e/service.pid)" || true
fi
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,20 @@ pnpm-debug.log*
lerna-debug.log*

node_modules
.pnpm-store/
.DS_Store
dist
dist-ssr
coverage
*.local
.env
.env.*
!.env.example
.data/
playwright-report/
test-results/
__pycache__/
*.py[cod]

/cypress/videos/
/cypress/screenshots/
Expand Down
63 changes: 63 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# syntax=docker/dockerfile:1.7

FROM node:24-bookworm-slim AS build

ARG PNPM_VERSION=11.9.0
ARG VITE_API_BASE_URL=/api/v1

ENV PNPM_HOME=/pnpm \
PATH=/pnpm:$PATH \
VITE_API_BASE_URL=${VITE_API_BASE_URL}

RUN corepack enable \
&& corepack prepare "pnpm@${PNPM_VERSION}" --activate \
&& apt-get update \
&& apt-get install --yes --no-install-recommends python3 make g++ \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store \
pnpm install --frozen-lockfile

COPY . .
RUN pnpm build && pnpm prune --prod


FROM node:24-bookworm-slim AS runtime

LABEL org.opencontainers.image.title="International Chinese Platform" \
org.opencontainers.image.description="Self-contained international Chinese education platform" \
org.opencontainers.image.source="https://github.com/computersciencefreshmen/International_Chinese_Platform"

ENV NODE_ENV=production \
HOST=0.0.0.0 \
PORT=7777 \
DATABASE_PATH=/app/data/platform.db \
UPLOAD_DIR=/app/uploads \
DIST_DIR=/app/dist \
SEED_ON_START=false

RUN groupadd --system --gid 10001 platform \
&& useradd --system --uid 10001 --gid platform --home-dir /app --shell /usr/sbin/nologin platform \
&& mkdir -p /app/data /app/uploads \
&& chown -R platform:platform /app

WORKDIR /app

COPY --from=build --chown=platform:platform /app/package.json ./package.json
COPY --from=build --chown=platform:platform /app/node_modules ./node_modules
COPY --from=build --chown=platform:platform /app/server ./server
COPY --from=build --chown=platform:platform /app/dist ./dist

USER 10001:10001

EXPOSE 7777
VOLUME ["/app/data", "/app/uploads"]
STOPSIGNAL SIGTERM

HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD ["node", "-e", "fetch('http://127.0.0.1:7777/api/v1/ready').then((response) => { if (!response.ok) process.exit(1) }).catch(() => process.exit(1))"]

CMD ["node", "server/index.js"]
Loading
Loading