Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ When Codex substantially authors a Git commit in this repository:

## Project

Gapwise is a privacy-first web application for students at 13 supported Canadian universities, served from `https://gapwise.ca` and dedicated university subdomains. Timetable identity and source-backed building maps cover all supported editions. Pedestrian routing and entrance coverage vary by campus; UTM-specific places and ACORN import remain scoped to the University of Toronto edition.
Gapwise is a privacy-first web application for students at 14 supported Canadian universities, served from `https://gapwise.ca` and dedicated university subdomains. Timetable identity and source-backed building maps cover all supported editions. Pedestrian routing and entrance coverage vary by campus; UTM-specific places and ACORN import remain scoped to the University of Toronto edition.

The current product:

Expand Down
2 changes: 1 addition & 1 deletion docs/CAMPUS_DATA.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Campus data and documentation boundaries

Canonical public multi-university campus facts, geometry, provenance, and data-maintenance guidance live in [`GapwiseHQ/data`](https://github.com/GapwiseHQ/data). The dataset covers 13 universities (University of Toronto, Carleton University, Toronto Metropolitan University, Queen's University, Wilfrid Laurier University, York University, McMaster University, Western University, University of Guelph, University of Ottawa, Brock University, the University of British Columbia, and the University of Waterloo) across 15 campus models.
Canonical public multi-university campus facts, geometry, provenance, and data-maintenance guidance live in [`GapwiseHQ/data`](https://github.com/GapwiseHQ/data). The dataset covers 14 universities (University of Toronto, Carleton University, Toronto Metropolitan University, Queen's University, Wilfrid Laurier University, York University, McMaster University, Western University, University of Guelph, University of Ottawa, Brock University, the University of British Columbia, the University of Waterloo, and McGill University) across 16 campus models.

Public human-readable data documentation lives at **https://docs.gapwise.ca/data/**. The currently published raw distributions live at **https://data.gapwise.ca/datasets/**.

Expand Down
4 changes: 2 additions & 2 deletions docs/ECOSYSTEM_INTEGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ Gapwise is one product ecosystem implemented across seven product repositories a

| Repository | Owns | Consumes |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| `data` | Canonical multi-university campus facts and geometry across 13 universities; routing graphs and reviewed entrances | Reviewed public/field evidence; core consumer tests |
| `gapwise` | Web/PWA across 13 university editions and 15 campus models, timetable/gap/routing semantics, encrypted private state, API v1, OpenAPI and both SDKs | Validated build-time Data mirror; explicit AI delegation |
| `data` | Canonical multi-university campus facts and geometry across 14 universities; routing graphs and reviewed entrances | Reviewed public/field evidence; core consumer tests |
| `gapwise` | Web/PWA across 14 university editions and 16 campus models, timetable/gap/routing semantics, encrypted private state, API v1, OpenAPI and both SDKs | Validated build-time Data mirror; explicit AI delegation |
| `android` | Kotlin/Compose UX, Keystore persistence, native import and encrypted-sync adapter (focuses on U of T) | Core HTTP/crypto contracts and public campus APIs |
| `ios` | SwiftUI UX and portable local timetable foundation (focuses on U of T) | Campus-scoped identity; broader native campus/account integrations remain pending |
| `ai` | OAuth/MCP authorization, minimized snapshots and bounded preference actions | Core public API and browser-authoritative delegated snapshots |
Expand Down
2 changes: 1 addition & 1 deletion docs/INFRASTRUCTURE_COST_AND_SCALING_MODEL.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

Gapwise operates on an intensely disciplined **local-first, zero-unnecessary-cloud architecture**. Course schedules, `.ics` files, calendar parsing, timetable rendering, walking route graphs, gap detection, and campus building spatial indexes execute 100% client-side in the student's browser (WebAssembly and Web Crypto).

Because of this architectural posture, **Gapwise's current operational infrastructure cost is $0.00/month across all 13 supported universities**.
Because of this architectural posture, **Gapwise's current operational infrastructure cost is $0.00/month across all 14 supported universities**.

This document models the resource consumption, provider limits, financial projections, and explicit upgrade triggers across four growth stages:

Expand Down
61 changes: 61 additions & 0 deletions e2e/mcgill-university.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { expect, test } from "@playwright/test";
import { watchForAppFailures } from "./helpers";

test("McGill calendar import preserves downtown campus search and routing", async ({
page,
baseURL,
}) => {
test.skip(test.info().project.name !== "chromium");
if (!baseURL) throw new Error("Playwright baseURL is required");
const failures = watchForAppFailures(page, baseURL);

await page.goto("/?university=mcgill&campus=mcgill-downtown");
await expect(page.getByText("For McGill University", { exact: true })).toBeVisible();
await expect(page.locator(".brand-scope-pill").first()).toHaveText("McGill");

await page
.locator('input[name="ics-file"]')
.setInputFiles("tests/fixtures/mcgill-mycourses-sanitized.ics");
await expect(page).toHaveURL(/\/timetable$/);
await page
.getByRole("group", { name: "View mode" })
.getByRole("button", { name: "Weekly timetable" })
.click();
await expect(page.getByText("COMP 202").first()).toBeVisible();
await expect(page.getByText("CHEM 110").first()).toBeVisible();

await page
.getByRole("group", { name: "View mode" })
.getByRole("button", { name: "Day route" })
.click();
await page
.getByRole("group", { name: "Route weekday" })
.getByRole("button", { name: "Monday" })
.click();
const search = page.getByRole("searchbox", { name: "Search McGill buildings" });
await expect(search).toBeVisible();
await search.fill("LEA");
await expect(page.getByTestId("building-search-result").first()).toContainText("Leacock");

await page.goto("/route?university=mcgill&campus=mcgill-downtown");
await expect(page.locator(".brand-scope-pill").first()).toHaveText("McGill");
await expect(page.getByRole("searchbox", { name: "Search McGill buildings" })).toBeVisible();
failures.assertClean();
});

test("McGill demo remains usable on the mobile campus map", async ({ page, baseURL }) => {
test.skip(test.info().project.name !== "mobile-chromium");
if (!baseURL) throw new Error("Playwright baseURL is required");
const failures = watchForAppFailures(page, baseURL);

await page.goto("/?university=mcgill&campus=mcgill-downtown");
await page.getByRole("button", { name: "Try a demo" }).click();
await expect(page).toHaveURL(/\/timetable/);
await page.getByRole("group", { name: "Weekday" }).getByRole("button", { name: /Mon/ }).click();
await expect(page.getByText("COMP 202").first()).toBeVisible();

await page.getByRole("navigation", { name: "Main" }).getByRole("link", { name: "Map" }).click();
await expect(page.getByRole("searchbox", { name: "Search McGill buildings" })).toBeVisible();
await expect(page.getByRole("button", { name: "Options" })).toBeVisible();
failures.assertClean();
});
2 changes: 1 addition & 1 deletion public/institutional-brief.html
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ <h1 class="brand-title">
bridges the gap between official course schedules and physical campus navigation. It
connects class times to campus geometry—computing true usable break times, verified walking
paths, step-free navigation, and study destinations across
<strong>13 Canadian universities and 15 campus models</strong> with strict
<strong>14 Canadian universities and 16 campus models</strong> with strict
privacy-by-design.
</div>

Expand Down
Binary file added public/universities/mcgill/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/universities/mcgill/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/universities/mcgill/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/universities/mcgill/icon-192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/universities/mcgill/icon-512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions public/universities/mcgill/logo-mark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/universities/mcgill/og-card.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions public/universities/mcgill/site.webmanifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "Gapwise — McGill University",
"short_name": "Gapwise",
"icons": [
{ "src": "/universities/mcgill/icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/universities/mcgill/icon-512.png", "sizes": "512x512", "type": "image/png" }
],
"theme_color": "#0d1117",
"background_color": "#0d1117",
"display": "standalone",
"start_url": "/"
}
8 changes: 8 additions & 0 deletions scripts/generate-social-cards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,14 @@ const CARDS: CardConfig[] = [
tagline: "Make the time between classes count.",
detail: "University of Waterloo",
},
{
outputPath: "public/universities/mcgill/og-card.png",
accentColor: "#ED1B2F",
textColor: "#FCA5A5",
title: "Gapwise",
tagline: "Timetable and downtown campus navigation.",
detail: "McGill University · Downtown Campus",
},
// ── Root fallbacks (U of T default) ──────────────────────
{
outputPath: "public/og-card.png",
Expand Down
1 change: 1 addition & 0 deletions src/components/MarketingLandingImpl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const INSTITUTION_MARKETING_METRICS: Record<
brock: { count: 12, sampleCodes: ["ST", "TH", "MC", "GSB"] },
ubc: { count: 236, sampleCodes: ["ICCS", "BUCH", "PHRM", "LIFE"] },
waterloo: { count: 68, sampleCodes: ["MC", "DC", "QNC", "AL"] },
mcgill: { count: 49, sampleCodes: ["LEA", "MAASS", "RPHYS", "ARTS"] },
};

export function MarketingLandingImpl({
Expand Down
2 changes: 1 addition & 1 deletion src/content/public-feature-pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const PUBLIC_FEATURE_PAGES = {
},
{
title: "Made for multiple universities",
body: "Timetable identity and source-backed building maps are supported for all thirteen universities. Pedestrian routing, verified entrances, and campus places vary by campus and are shown only where supported.",
body: "Timetable identity and source-backed building maps are supported for all fourteen universities. Pedestrian routing, verified entrances, and campus places vary by campus and are shown only where supported.",
},
],
},
Expand Down
1 change: 1 addition & 0 deletions src/data/campuses/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ export function ensureCampusCatalog(campusId: string | null | undefined): Promis
const catalogLoaders: Record<string, () => Promise<{ default: string }>> = {
"ubc-vancouver": () => import("./ubc/catalog.json?raw"),
"waterloo-main": () => import("./waterloo/catalog.json?raw"),
"mcgill-downtown": () => import("./mcgill/catalog.json?raw"),
};
const loader = catalogLoaders[campusId];
const load = loader
Expand Down
Loading
Loading