From 593081a6201fd4b2554e5f89b2abde1e0dc4b25d Mon Sep 17 00:00:00 2001 From: DearMrFree Date: Tue, 19 May 2026 21:48:48 -0700 Subject: [PATCH] ci: comment Vercel preview URL on pull requests --- .github/workflows/vercel-deploy.yml | 85 ++++++++++++++++++ .gitignore | 8 ++ README.md | 45 ++++++++++ app/courses/deadlines/page.tsx | 61 +++++++++++++ app/courses/page.tsx | 134 ++++++++++++++-------------- lib/course-deadlines.ts | 93 +++++++++++++++++++ 6 files changed, 360 insertions(+), 66 deletions(-) create mode 100644 .github/workflows/vercel-deploy.yml create mode 100644 app/courses/deadlines/page.tsx create mode 100644 lib/course-deadlines.ts diff --git a/.github/workflows/vercel-deploy.yml b/.github/workflows/vercel-deploy.yml new file mode 100644 index 0000000..1fd50cb --- /dev/null +++ b/.github/workflows/vercel-deploy.yml @@ -0,0 +1,85 @@ +name: Deploy to Vercel + +on: + push: + branches: + - main + pull_request: + branches: + - main + +env: + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + +jobs: + deploy-preview: + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + - name: Install dependencies + run: pnpm install --frozen-lockfile + - name: Pull Vercel environment + run: npx vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} + - name: Build project artifacts + run: npx vercel build --token=${{ secrets.VERCEL_TOKEN }} + - name: Deploy preview + id: vercel_preview + run: | + PREVIEW_URL=$(npx vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }}) + echo "preview_url=$PREVIEW_URL" >> "$GITHUB_OUTPUT" + - name: Comment preview URL on PR + uses: actions/github-script@v7 + with: + script: | + const url = `${{ steps.vercel_preview.outputs.preview_url }}`.trim(); + const body = [ + "✅ Vercel preview deployment is ready.", + "", + `Preview URL: ${url}` + ].join("\n"); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body, + }); + + deploy-production: + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + - name: Install dependencies + run: pnpm install --frozen-lockfile + - name: Pull Vercel environment + run: npx vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} + - name: Build project artifacts + run: npx vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} + - name: Deploy production + run: npx vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }} diff --git a/.gitignore b/.gitignore index 91f74dc..9792101 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,11 @@ yarn-error.log* # ts *.tsbuildinfo +# python +__pycache__/ +*.py[cod] +*.egg-info/ +.venv/ +.pytest_cache/ +.mypy_cache/ + diff --git a/README.md b/README.md index fed1acc..5e2fec7 100644 --- a/README.md +++ b/README.md @@ -69,3 +69,48 @@ Cream paper · deep emerald · warm orange · amber gold. Editorial serif headlines for the manifesto register; clean Geist sans for everything else. The two sister schools each get their own gradient on `/` so the gateway never flattens them into a single voice. + + +## Repository map + +### Web app (Next.js / TypeScript) +- `app/`: App Router pages and API routes (site pages, auth, admin, chat, uploads). +- `components/`: UI, layout, and section-level building blocks. +- `lib/`: shared business logic (auth, SSO bridge, site config, profile utilities). +- `types/`: TypeScript type augmentations (for example NextAuth). + +### API service (FastAPI / Python) +- `src/sof_ai_api/main.py`: FastAPI entrypoint and router mounting. +- `src/sof_ai_api/routes/`: endpoint modules (health, progress, wallet, journals, challenges, pioneer applications). +- `src/sof_ai_api/models.py`: SQLModel entities and constraints. +- `src/sof_ai_api/ledger.py`: points/ledger domain logic. +- `src/sof_ai_api/integrations/`: external integrations (including OJS adapter/client). + +### Infra and tooling +- `Dockerfile`: container build definition. +- `fly.toml`: Fly.io deploy configuration. +- `pyproject.toml`: Python package and dependency settings. +- `package.json`: Node scripts and dependencies. + +## Suggested next build targets +1. **Contract tests between Next API routes and FastAPI endpoints** to prevent regressions across the TS/Python boundary. +2. **End-to-end auth flow tests** (magic link + SSO handoff/signout) to harden enrollment onboarding. +3. **Observability baseline** (request IDs, structured logs, health/readiness checks, error budget alerts). +4. **Data lifecycle docs** for progress/enrollment and ledger mutations to simplify contributor onboarding. + + + +## Vercel deployment (CI/CD) + +This repo now includes `.github/workflows/vercel-deploy.yml` for automatic deployments: + +- Pull requests to `main` create a **Preview** deployment. +- Pushes to `main` create a **Production** deployment. + +Configure these GitHub repository secrets before enabling the workflow: + +- `VERCEL_TOKEN` +- `VERCEL_ORG_ID` +- `VERCEL_PROJECT_ID` + +You can get these values from your Vercel account/project settings and by running `vercel link` locally. diff --git a/app/courses/deadlines/page.tsx b/app/courses/deadlines/page.tsx new file mode 100644 index 0000000..f090453 --- /dev/null +++ b/app/courses/deadlines/page.tsx @@ -0,0 +1,61 @@ +import type { Metadata } from "next" +import { MIT_COURSEWARE_DEADLINES, sortDeadlinesByDate } from "@/lib/course-deadlines" + +export const metadata: Metadata = { + title: "MIT Courseware Deadlines · The VR School", + description: + "Operational deadlines for enrollment, coursework, exam registration, portfolio checkpoints, and transcript closeout.", +} + +const CATEGORY_STYLE: Record = { + Enrollment: "bg-sky-100 text-sky-800 dark:bg-sky-950 dark:text-sky-300", + Coursework: "bg-violet-100 text-violet-800 dark:bg-violet-950 dark:text-violet-300", + Exams: "bg-rose-100 text-rose-800 dark:bg-rose-950 dark:text-rose-300", + Portfolio: "bg-emerald-100 text-emerald-800 dark:bg-emerald-950 dark:text-emerald-300", + Admin: "bg-amber-100 text-amber-800 dark:bg-amber-950 dark:text-amber-300", +} + +export default function CourseDeadlinesPage() { + const deadlines = sortDeadlinesByDate(MIT_COURSEWARE_DEADLINES) + + return ( +
+
+

MIT Courseware Deadlines

+

+ Single source of truth for 2026–27 operational milestones across enrollment, instruction, assessments, portfolio evidence, and final transcript closeout. +

+ +
+ + + + + + + + + + + {deadlines.map((item) => ( + + + + + + + ))} + +
DateMilestoneOwnerCategory
{item.date} +

{item.title}

+

{item.notes}

+
{item.owner} + + {item.category} + +
+
+
+
+ ) +} diff --git a/app/courses/page.tsx b/app/courses/page.tsx index 6943d67..6186dcd 100644 --- a/app/courses/page.tsx +++ b/app/courses/page.tsx @@ -13,6 +13,11 @@ export const metadata: Metadata = { const SECTIONS: UcSection[] = ["A", "B", "C", "D", "E", "F", "G"] +type CourseCatalogSearchParams = { + q?: string + honors?: string +} + function HonorsBadge() { return ( @@ -21,26 +26,55 @@ function HonorsBadge() { ) } -export default function CourseCatalog() { - const total = COURSES.length - const honors = COURSES.filter((c) => c.ucHonors).length +function matchesSearch(courseTitle: string, query: string) { + if (!query) return true + return courseTitle.toLowerCase().includes(query.toLowerCase()) +} + +export default async function CourseCatalog({ + searchParams, +}: { + searchParams?: Promise +}) { + const params = (await searchParams) ?? {} + const query = (params.q ?? "").trim() + const honorsOnly = params.honors === "1" + + const filtered = COURSES.filter((c) => matchesSearch(c.title, query) && (!honorsOnly || c.ucHonors)) + const total = filtered.length + const honors = filtered.filter((c) => c.ucHonors).length const sections = SECTIONS.slice(0, 6) - const gCourses = getCoursesBySection("G") + const gCourses = getCoursesBySection("G").filter((c) => matchesSearch(c.title, query) && (!honorsOnly || c.ucHonors)) return (
- {/* Hero */}

The VR School · Stanford, CA · College Board Code 170588

Course Catalog

-

2026–27 Academic Year · UC A-G Approved

+

2026–27 Academic Year · UC A-G Approved

+

Track milestone dates at /courses/deadlines.

+ +
+ + +
+
{total} - Total Courses + Visible Courses
{honors} @@ -50,19 +84,15 @@ export default function CourseCatalog() { 7 A-G Subject Areas
-
- Online - Delivery Mode -
- {/* A-F sections */}
{sections.map((sec) => { const meta = SECTION_META[sec] - const courses = getCoursesBySection(sec) + const courses = getCoursesBySection(sec).filter((c) => matchesSearch(c.title, query) && (!honorsOnly || c.ucHonors)) + if (courses.length === 0) return null return (
@@ -86,10 +116,7 @@ export default function CourseCatalog() { {courses.map((c) => ( - + {c.title} {c.ucHonors && } @@ -109,56 +136,31 @@ export default function CourseCatalog() { })}
-
- - {/* G: College-Prep Electives */} -
-
- G -
-

{SECTION_META.G.label}

-

{gCourses.length} courses

-
-
-
- {gCourses.map((c) => ( - - - - {c.title} - {c.ucHonors && ( - - HON + {gCourses.length > 0 && ( + <> +
+
+
+ G +
+

{SECTION_META.G.label}

+

{gCourses.length} courses

+
+
+
+ {gCourses.map((c) => ( + + + + {c.title} + {c.ucHonors && HON} - )} - - - ))} -
-
- -
- - {/* Jump nav */} -
-

Jump to section

-
- {SECTIONS.map((sec) => ( - - {sec} - {SECTION_META[sec].label} - - ))} -
-
+ + ))} +
+
+ + )}
) } diff --git a/lib/course-deadlines.ts b/lib/course-deadlines.ts new file mode 100644 index 0000000..e49e78e --- /dev/null +++ b/lib/course-deadlines.ts @@ -0,0 +1,93 @@ +export type DeadlineCategory = "Enrollment" | "Coursework" | "Exams" | "Portfolio" | "Admin" + +export interface CourseDeadline { + id: string + title: string + date: string + category: DeadlineCategory + owner: "Student" | "Teacher" | "Registrar" | "Admin" + notes: string +} + +/** + * Central deadline calendar for the 2026-27 catalog cycle. + * Dates are ISO-8601 so sorting and filtering are deterministic. + */ +export const MIT_COURSEWARE_DEADLINES: CourseDeadline[] = [ + { + id: "fall-enrollment-lock", + title: "Fall enrollment lock", + date: "2026-08-14", + category: "Enrollment", + owner: "Registrar", + notes: "Learner section placement and roster finalization for all A-G tracks.", + }, + { + id: "q1-syllabus-publish", + title: "Quarter 1 syllabus publish", + date: "2026-08-21", + category: "Coursework", + owner: "Teacher", + notes: "Publish objectives, pacing, and rubric checkpoints for each live course shell.", + }, + { + id: "q1-progress-check", + title: "Quarter 1 progress checkpoint", + date: "2026-10-02", + category: "Coursework", + owner: "Student", + notes: "All students submit first mastery artifacts and advisor conference notes.", + }, + { + id: "fall-midterm-window", + title: "Fall midterm assessment window", + date: "2026-10-23", + category: "Exams", + owner: "Teacher", + notes: "Standards-aligned midterm scoring posted for transcript preview.", + }, + { + id: "fall-portfolio-freeze", + title: "Fall portfolio evidence freeze", + date: "2026-11-20", + category: "Portfolio", + owner: "Student", + notes: "Evidence lock for semester 1 public profile publication.", + }, + { + id: "spring-enrollment-lock", + title: "Spring enrollment lock", + date: "2027-01-15", + category: "Enrollment", + owner: "Registrar", + notes: "Second-semester seat balancing and section transfer freeze.", + }, + { + id: "ap-registration-close", + title: "AP exam registration closes", + date: "2027-03-05", + category: "Exams", + owner: "Admin", + notes: "Final AP roster submission and accommodations verification.", + }, + { + id: "spring-capstone-review", + title: "Spring capstone review", + date: "2027-04-16", + category: "Portfolio", + owner: "Teacher", + notes: "Cross-disciplinary capstone review boards and remediation plans.", + }, + { + id: "final-grade-post", + title: "Final grade posting deadline", + date: "2027-06-04", + category: "Admin", + owner: "Registrar", + notes: "Final transcript grades, honors flags, and GPA exports finalized.", + }, +] + +export function sortDeadlinesByDate(deadlines: CourseDeadline[]): CourseDeadline[] { + return [...deadlines].sort((a, b) => a.date.localeCompare(b.date)) +}