build(deps): bump node from 20-alpine to 26-alpine#2
Closed
dependabot[bot] wants to merge 1 commit into
Closed
Conversation
Bumps node from 20-alpine to 26-alpine. --- updated-dependencies: - dependency-name: node dependency-version: 26-alpine dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com>
Author
LabelsThe following labels could not be found: Please fix the above issues or remove invalid values from |
Author
|
Looks like node is no longer a dependency, so this is no longer needed. |
DeveloperCodeBase
added a commit
that referenced
this pull request
May 22, 2026
Owner sent 5 screenshots after R1.3 failed manual smoke. Filled the audit table with concrete findings and authored the R1.4 spec. DEFINITIVELY CONFIRMED BUGS (3): Bug #1 (B4) — sidebar drawer renders as 3 horizontal pills instead of a vertical list. Root cause: styles.css:3598-3641 transforms `.side-nav` to horizontal flex with !important at <720px — designed for the legacy inline `.dash` sidebar, but the Sheet drawer's RoleSideNav inherits the rule. Fix: scope to `.dash .side-nav` + add `.appshell-sidebar-drawer .side-nav` override. Bug #2 (B5) — mock role-avatar "نر" leaks on landing + login for anonymous visitors. Phase 14.8 fixed user-name fallback but missed user-avatar. Fix: shared.tsx Nav user-btn — render generic icon when !auth.user, never the mock role.avatar. Bug #3 (Brand) — logos broken in screenshot 3 because the screenshot predates the logo file commit (deploy-timing artifact, not code). Fix: one fresh `up` to rebake nginx with the new public/ assets. UNVERIFIED (need more screenshots before action): B1 sticky navbar — no scroll-down screenshot. R1.3 assertion only checked computed style, never real iOS scroll behaviour. B2 login layout — chips ARE 2-col (works), but navbar visibility on /login is ambiguous from screenshot 5. B3 dashboard/profile responsive — not captured in this set. DEFERRED (per prior agreement): B6 classroom mobile — Phase D R1 (LiveKit ground-up rewrite). The R1.4 spec details for each confirmed bug: - exact screenshot link / evidence - what the R1.3 assertion verified (and why it missed the real issue) - exact file:line fix - D12 5-point assertion (DOM, computed style, viewport position, no overlap, pixel-diff ≤ 0.001) - visual baseline path PAUSING per D13. Three owner approvals requested in the spec before I write any code: 1. B4 CSS scoping approach (legacy `.dash` retain vs delete) 2. B5 avatar fallback design (icon vs glyph) 3. Visual baseline review workflow R2 stays gated until R1.3 + R1.4 finally pass owner manual smoke. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DeveloperCodeBase
added a commit
that referenced
this pull request
May 22, 2026
…nual smoke R1.4 closed 3 of the 6 bugs the owner manual-smoke found in R1.3: - Bug #1 (B4): sidebar drawer now renders vertically with section headers instead of 3 horizontal pills - Bug #2 (B5): anonymous avatar is a generic person icon, never leaks the role-mock initials "نر" / "AA" / etc. - Bug #3 (Brand): logos serve over HTTP 200 + decode (naturalWidth>0) Automated grid post-fix: R1.1 13/13 · R1.2 9/10+1 intentional skip · R1.3 17/17 · R1.4 7/7 → 46 pass, 1 skip, 0 fail across 4 specs Per R1.3-D13, automated green ≠ shipped. PAUSING for owner manual smoke on a real device + incognito tab. Six manual checks listed in the review (3 fixed, 3 still unverified): 1. drawer vertical with section headers 2. anon avatar = generic icon on / 3. anon avatar = generic icon on /login 4. JDO logo renders in footer (not broken-image) 5. sticky navbar on scroll (UNVERIFIED — no screenshot yet) 6. dashboard mobile reachable now that drawer works (UNVERIFIED) What's NOT done until owner says go: - R2 retire @ts-nocheck (gated) - Visual baselines committed (UPDATE_BASELINES=1 workflow exists, PNGs not yet owner-approved) - B1/B3 deeper fixes (gated on owner confirmation they're broken) - B6 classroom mobile (deferred to Phase D R1) D12 5-point contract satisfied for the 3 fixed bugs (point 5 gated). D13 (manual smoke is formal gate) honoured by stopping here. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DeveloperCodeBase
added a commit
that referenced
this pull request
May 24, 2026
…te-limit edge) R7.7 review doc filed this as a known follow-on. R7.3's regression sweep hit it (test #2 instead of the usual #7): prior visual specs in the same minute already consumed some of the api's 10/min login bucket, so the 7s-spaced 7th login landed in a contended window. Bumping to 7s gives 10 roles × 7s = 70s — pushes the 7th login outside the 60s rolling window even when the bucket has been touched by a prior spec. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DeveloperCodeBase
added a commit
that referenced
this pull request
May 24, 2026
…agnosis 3rd attempt at gate-a-role-routing failed at admin (test #3) after ~5 min cooldown. Failure point moves across attempts (#2 instructor, #1 student, #3 admin) but failure mode is identical (login form waitForURL timeout). Diagnosis: rate-limit bucket depletion from today's cumulative login-touching test runs — NOT a R7.3 regression. Verified R7.3 code is correct: - R7.3 per-fix spec A.1 authed test PASSES (same login helper) - Lighthouse /login re-measured to 100/100/96 - Production bundle contains both 'منوی حساب' + 'منوی کاربر' R7.3 verdict stays: functionally green, awaiting D13 + future cooldown re-run for the role-routing 10/10 confirmation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DeveloperCodeBase
added a commit
that referenced
this pull request
May 24, 2026
…d environmental Post-cooldown re-run of gate-a-role-routing alone: 10/10 PASS (student 2.2s, instructor through super_admin each ~8.9s). Confirms the spec is correct + R7.1+R7.2 didn't break the role-routing flow. The earlier failure during the regression sweep was the documented D32 rate-limit infra flake — cumulative login attempts within the 60s window depleted the api's 10/min bucket. The 7s inter-test pause (R7.3 silent-fix #2) is correct in isolation; only contended bucket state at the moment of sweep firing caused the 1/10 outcome. R7.1+R7.2 regression verdict: 7/8 specs clean + 1 environmental test fragility (R1.1 skip-link Tab focus, NOT a code regression — AppShell skip-link is unchanged + verified by curl). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DeveloperCodeBase
added a commit
that referenced
this pull request
May 26, 2026
D61 logged in PHASE_A_DECISIONS.md: - Workflow discipline reminder (retrospective lesson #1): every Phase B sub-R = memo → ack → code → spec → deploy → D29 → D13 → close, no skip - Performance budget reminder (retrospective lesson from R7.1.5): R1 admin pages lazy-loaded, admin-academic manualChunks bucket, main bundle delta < 50KB target, asset weight check in review doc R1 memo refactored with new «🚧 Binding constraints per D61» section: - Constraint #1 — workflow discipline (verbatim, no skipping) - Constraint #2 — performance budget (lazy + manualChunks + bundle delta < 50KB + R1.5 escape hatch if exceeded) - Notes what these constraints do NOT change (LoC estimate, locked Q-answers, timeline) NEW: docs/PHASE_B_R0_5_MEMO.md Short DRAFT memo for the docs-only R0.5 sub-R (MIGRATION_POLICY.md). Covers: - 11 sections of the policy doc with per-section LoC estimates (total target ~160 LOC, matches owner estimate) - What the doc INCLUDES (Phase A dormant-table caveat, R1 4-level hierarchy as greenfield illustration, code-shape pseudo-snippets, Phase A R4 enforcement note, 5-point migration commit checklist) - What the doc EXCLUDES (no migration files, no tooling impl, no API versioning strategy duplication, no backfill scripts) - Why R0.5 vs R1.A (Q1.a rationale + workflow discipline) - Verification plan (owner reads + acks; no Chrome Extension needed) No code starts until R0.5 doc owner-acked. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DeveloperCodeBase
added a commit
that referenced
this pull request
May 27, 2026
apps/web/src/api/endpoints.js:
- catalogApi.listSchools added; existing listFaculties gains optional
{schoolId} filter (additive — undefined arg behaves identically).
- NEW academicAdminApi block: full CRUD across all 4 levels:
listSchools / getSchool / createSchool / updateSchool / deleteSchool
listFaculties (with ?schoolId=) / getFaculty / create / update / delete
listDepartments (with ?facultyId=) / get / create / update / delete
listPrograms (with ?departmentId= & ?degreeLevel=) / get / create /
update / delete
19 entries total, mapping 1:1 to the NestJS endpoints from Commits B-D.
NEW apps/web/src/pages/admin/_shared/:
- CrudDialog.tsx: shared create/edit modal with form submission, busy
state, Escape key close, aria-modal a11y, backdrop click dismiss.
- FormField.tsx: text/number/date input with label-above-input layout,
helper text, error message slot, aria-invalid + aria-describedby
wiring. SelectField variant for FK pickers (schoolId on Faculty,
facultyId on Department, departmentId on Program).
- ConfirmDelete.tsx: alertdialog for soft-delete confirmation with
danger button styling.
Extracted to avoid 4× duplication across SchoolsPage, FacultiesPage,
DepartmentsPage, ProgramsPage (Commits G + H).
R1 chain: A → B → C → D → E (API e2e green) → F (this) → G+H+I+J+K
still ahead. Bundle impact: zero on / (admin routes will be
React.lazy() in Commit I per D61 Constraint #2).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DeveloperCodeBase
added a commit
that referenced
this pull request
May 27, 2026
apps/web/src/pages/admin/SchoolsPage.tsx (~250 LOC): - Lists all schools with name, nameEn, shortCode, slug, faculty count - Shows empty-state + "افزودن اولین دانشکده" CTA when no rows - + افزودن دانشکده button opens CrudDialog in create mode - Click pencil icon → CrudDialog in edit mode (pre-populated) - Click trash icon → ConfirmDelete modal → soft-delete with cascade warning if faculties exist underneath - All mutations refetch the list after success (kept consistent with server-side audit log) - isAdmin gate: only admin / super_admin sees the + / edit / delete buttons; non-admin viewers see read-only table Form fields (per Q4.a spirit dual-column design): - nameFa (required, max 160) — labeled "نام فارسی" - nameEn (optional, max 160, dir=ltr) — labeled "نام انگلیسی" - slug (required, max 64, dir=ltr) — labeled "شناسه" with helper - shortCode (optional, max 32, dir=ltr) — labeled "کد اختصاری" - sortOrder (number) — labeled "ترتیب نمایش" - description (optional, max 2000) — labeled "توضیحات" Validation: - nameFa + slug required (client-side check before submit) - Server errors surfaced via formError state (e.g., P2002 "slug already in use" maps to BadRequest with friendly message from Commit B) Uses _shared primitives from Commit F: - CrudDialog (modal + form wrapper) - FormField (label + input + helper + error) - ConfirmDelete (alertdialog for soft-delete) Bundle impact: zero on / (this page is React.lazy() in Commit I). Will land in admin-academic chunk per D61 Constraint #2. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DeveloperCodeBase
added a commit
that referenced
this pull request
May 27, 2026
…(D62)
Three full-CRUD admin pages mirroring the SchoolsPage shape:
FacultiesPage (~240 LOC):
- List + CRUD + soft-delete, with optional ?schoolId= filter chip
- SelectField for school FK picker (with emptyLabel "(بدون دانشکده)"
to support detach)
- Same fields as Faculty model: name (existing Persian SoT), nameEn,
shortCode, schoolId, slug (create-only), description
- Empty-state when no rows
- Read-only mode if non-admin
DepartmentsPage (~190 LOC):
- List + CRUD with optional ?facultyId= filter
- Required facultyId picker on create (Department.facultyId is NOT NULL)
- facultyId hidden after create (can't reparent existing rows in R1
per scope; admin must delete+recreate or PATCH via API)
- Same shape as Department: name, nameEn, shortCode, slug, description
ProgramsPage (~220 LOC):
- List + CRUD with optional ?departmentId= and ?degreeLevel= filters
- degreeLevel SelectField with 4 options (bachelor/master/phd/certificate)
labeled in Persian (کارشناسی/کارشناسی ارشد/دکتری/گواهینامه)
- Required departmentId picker on create
- durationSemesters number field (optional)
- Same additive cols + name + nameEn + shortCode + slug + description
All three use _shared/{CrudDialog, FormField, SelectField, ConfirmDelete}
from Commit F. Each page exports default for React.lazy() in Commit I.
Bundle impact stays on the admin-academic chunk (Commit I will wire
the manualChunks bucket). Main bundle delta target: < 50 KB per D61
Constraint #2.
R1 chain: A → ... → G (Schools) → H (this) → I (sidebar + router +
guard) → J (D12+D18 specs) → K (review doc + post-deploy smoke).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DeveloperCodeBase
added a commit
that referenced
this pull request
May 27, 2026
…(D62 + D61 Constraint #2) Router (apps/web/src/router.tsx): - 4 React.lazy() imports for SchoolsAdminPage / FacultiesAdminPage / DepartmentsAdminPage / ProgramsAdminPage (each their own chunk boundary) - 4 new route registrations at /admin/schools, /admin/faculties, /admin/departments, /admin/programs Vite config (apps/web/vite.config.js): - manualChunks switched from object form to function form. Function routes any file under /pages/admin/ to the "admin-academic" chunk (catches both the 4 page files + the _shared primitives from Commit F). React + radix vendor buckets preserved with id-pattern matching. - Per D61 Constraint #2: main bundle delta target < 50 KB. Admin pages now land in their own chunk separately, never loaded for students/instructors/other roles. Sidenav (apps/web/src/sidenav.tsx): - admin role gets a new "ساختار آکادمیک" section header + 4 items: admin/schools (دانشکدهها), admin/faculties (هیأتها), admin/departments (گروهها), admin/programs (برنامهها) - Existing pre-R1 "schools" + "faculty" items deprecated by name + route (replaced with admin/* equivalents that hit the new full-CRUD pages). Old marketing /schools + /faculty routes remain reachable via go() — not removed in R1 (out of scope). Access guard: not added as a separate middleware in this commit because the *server-side* @roles("admin") guard on every mutation endpoint (Commits B-D) already enforces. Client-side, the pages themselves render read-only mode for non-admin roles via useRole().role.id check at the top of each page. Defense in depth. R1 chain: A → ... → H (3 pages) → I (this) → J (D12+D18 specs next) → K (review doc + post-deploy smoke). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DeveloperCodeBase
added a commit
that referenced
this pull request
May 27, 2026
D64 logged: R1 D13 owner real-device smoke 8-step PASS, R1 closed. - Admin sidebar 4 items, full CRUD, cascade soft-delete, nested breadcrumb, access guard all verified - Bundle delta target met: admin-academic-DCwo3HC3.js = 37 KB separate chunk, main index-Bch2wDJC.js unaffected for non-admin NEW: docs/PHASE_B_R2_MEMO.md — Phase B R2 candidate scope memo. R1 lessons applied pre-memo-write: - Lesson #1 (schema discovery): inspected Cohort + Enrollment + Course existing models BEFORE writing the memo. Result: Cohort exists with slug/program/dates; CourseOffering truly greenfield; blast radius = 1 downstream model (Enrollment). - Lesson #2 (4-model assumption check): single-model migration confirmed, no surprise dependencies. - Lesson #3 (perf budget per D61 #2): extend existing admin-academic chunk (no new bucket); expected +10-15 KB admin / 0 main. R2 scope decision: Cohort → CourseOffering (vs Course/Module/Lesson or Profile/Student/Instructor alternatives). Rationale: 1. First practical MIGRATION_POLICY §3+§5 dual-write usage 2. Compass §Phase B-aligned 3. Reasonable single sub-R scope ~1,880 LOC / 5-7 days 4. Validates §10 rollback caveat discipline in advance 5. Doesn't block identity models (R3+ track) 4 open questions for owner ack (Q1 scope confirm, Q2 richer offering shape, Q3 dual-write timing all-vs-split, Q4 cohort UI dual-vs-merge). Defaults: Q1.a / Q2.b / Q3.a / Q4.a. 10 atomic commits planned A-J (one fewer than R1 by reusing R1's _shared admin components). NO R2 code starts until Q1-Q4 ack. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DeveloperCodeBase
added a commit
that referenced
this pull request
May 27, 2026
…achine controls (D65)
apps/web/src/pages/admin/OfferingsPage.tsx (380 LOC) — admin surface
for /admin/offerings. Routes lazy-loaded in Commit I (router.tsx) so
the chunk joins admin-academic.{hash}.js per D61 Constraint #2.
Reuses R1 _shared primitives (CrudDialog + ConfirmDelete + FormField)
with three R2-specific additions:
1) Status pill — renders the OfferingStatus enum as a colored pill
per row: SCHEDULED / OPEN / ACTIVE / COMPLETED / CANCELED with
Persian labels (زمانبندی شده / ثبتنام باز / در حال برگزاری /
پایانیافته / لغو شده). CSS classes pill-status pill-{status}
for theming (CSS lives in styles.css from Phase A).
2) Inline transition controls — buttons rendered per row showing
ONLY the legal next-states per ALLOWED_TRANSITIONS map (mirror
of CourseOfferingsService.ALLOWED_TRANSITIONS, kept in sync by
convention + Commit I spec assertion).
• SCHEDULED row: shows [→ ثبتنام باز] [→ لغو شده]
• OPEN row: shows [→ در حال برگزاری] [→ لغو شده]
• ACTIVE row: shows [→ پایانیافته] [→ لغو شده]
• COMPLETED + CANCELED rows: no transition buttons (terminal)
Click → ConfirmDelete-style confirmation modal (reused component
for symmetry) → POST /transition. Server-side state-machine still
enforces; client filter is UX prevention not security.
Illegal transition rejection message surfaced via window.alert
verbatim from server (the allowed-from-current list per D65
R2-Reminder-1).
3) Mode + capacity columns — mode rendered as Persian label
(همزمان / ناهمزمان / ترکیبی); capacity nullable.
Cohort linkage shown in «پیشینه» column: «از Cohort» pill if the
offering was minted by LegacySyncService (legacyCohortId present);
«—» if greenfield.
CRUD form: shared with create + edit. Create form prompts for
programId (dropdown from listPrograms) + slug + nameFa + nameEn? +
shortCode? + mode + startDate? + endDate? + capacity? + description?
Edit form omits programId + slug (immutable post-create).
Delete confirmation body explicitly mentions cascade to linked
Cohort soft-delete if legacyCohortId present (matches LegacySyncService
behavior verified in API smoke).
NEXT: Commit H — CohortsPage «Legacy» banner + warning + «migrate
to offering» CTA.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DeveloperCodeBase
added a commit
that referenced
this pull request
May 27, 2026
…(D65) apps/web/src/pages/admin/CohortsPage.tsx (175 LOC) — admin surface for /admin/cohorts. Lazy-loaded; joins admin-academic chunk per D61 Constraint #2. Per MIGRATION_POLICY §6 + D65, this surface stays alive during the Sunset window (drop no sooner than 2026-12-31) but is intentionally READ-ONLY in the admin UI: - no «+ افزودن» button (new cohorts still possible via API for back-compat but the admin UI pushes users toward Offerings) - no edit/delete buttons (existing CRUD still works via API; admin UI strips them to discourage continued use of the legacy surface) Three R2-specific bits: 1) Prominent «Legacy» banner — role="alert" so screen readers announce it on page load. Amber color scheme (var(--amber-600) left border + amber background) for visual urgency without being alarmist. Banner text: • Explains the migration (new structure: state machine + mode + capacity + future instructor link). • Counts: X of Y cohorts already linked, (Y - X) pending. • CTA: «رفتن به دورههای ارائهشده» → go("admin/offerings"). • Drop date callout: «پس از 2026-12-31 حذف میشود». 2) Migration status column — each row shows either: • «✓ منتقل شد» (linked: upgradedToOfferingId present) + «→ دورهی متناظر» button → /admin/offerings • «در انتظار انتقال» (orphan) + hint «اولین ویرایش، انتقال خودکار را فعال میکند» (matches LegacySyncService.onCohortUpdated behavior verified in API smoke step 5) 3) Empty state — encourages migration: if 0 cohorts left, button says «رفتن به ساختار جدید — دورههای ارائهشده» (only path). Banner styling uses inline style for brevity (one-off component; keeping it self-contained avoids polluting styles.css with banner classes that will be removed in 2027). data-legacy-banner="cohorts" attribute makes the banner addressable for the D12 spec assertion in Commit I. NEXT: Commit I — D12 + D18 specs (state machine flow assertion + dual-write trace + illegal-transition rejection + legacy banner visibility) + router.tsx registration for both new routes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DeveloperCodeBase
added a commit
that referenced
this pull request
May 27, 2026
…nder-1)
apps/web/src/router.tsx:
- Lazy imports for OfferingsAdminPage + CohortsAdminPage (joins
admin-academic chunk per D61 Constraint #2; main bundle delta
target 0 KB).
- Route registrations: /admin/offerings + /admin/cohorts via
<RouteShell Component={...} /> matching R1 pattern.
apps/web/tests/visual/phase-b-r2-course-offerings.spec.ts (NEW, ~330 LOC):
D12 visual contract (3 tests):
• /admin/offerings table renders status pill column header + the
seeded e2e offering row, with .pill-status pill visible carrying
Persian label «زمانبندی شده» and transition button .btn-transition-open
• /admin/cohorts renders [data-legacy-banner=cohorts] with
role="alert", containing «منسوخ» + «2026-12-31»
• Admin sidebar contains both new entries («دورههای ارائهشده»
+ «گروههای آموزشی (Legacy)»)
D18 flow assertions per D65 R2-Reminder-1 (5 tests):
1. Happy path SCHEDULED → OPEN → ACTIVE → COMPLETED chained
transitions all return 200, status field updates correctly
2. Illegal OPEN → SCHEDULED rejects 400 with backend's
"Allowed from OPEN: [ACTIVE, CANCELED]" message verbatim
(asserts presence of ACTIVE + CANCELED in message body)
3. Soft-delete allowed at any status — verifies both SCHEDULED and
ACTIVE delete return 200 (terminal COMPLETED implicitly covered
by happy-path test)
4. Dual-write: POST /v1/cohorts populates upgradedToOfferingId +
mints a CourseOffering with legacyCohortId backlink
5. Cascade: cohort soft-delete causes linked offering to also
soft-delete (GET offering returns 404 post-delete)
6. GET /v1/cohorts emits Sunset / Deprecation / Link headers
Spec tagged @phase-b-r2 for selective playwright filtering. Uses live
deployment (no API mocks); each test creates + cleans up its own row.
ADMIN_PASSWORD reads from SEED_ADMIN_PASSWORD env or falls back to
the seed default "ChangeMe!2026".
NEXT: Commit J — review doc + bundle delta measurement + final ping.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DeveloperCodeBase
added a commit
that referenced
this pull request
May 27, 2026
…hunk Per D66 owner directive. Path A surgical fix for D61 Constraint #2 violation detected post-Commits-F-I bundle measurement. Symptom (live, post-deploy blkyrr57e): admin-academic-DIYsnFTw.js: 37 KB → 416 KB (+379 KB) index-BSNY3WwB.js: 366 KB → 2 KB (shifted, main imports from admin) Critical: admin-academic-*.js is now <link rel="modulepreload"> in every served HTML — anonymous visitors download 416 KB of admin code on cold cache, undoing Phase A R7.1.5 image-optimization win. Root cause: manualChunks rule "any /pages/admin/* → admin-academic" matched /pages/admin/_shared/*.tsx primitives (CrudDialog + ConfirmDelete + FormField). Some _shared symbol or transitive utility ended up in both main's import graph + admin pages' import graph; Vite hoisted it into admin-academic to dedupe + made main eager-import from there, escalating admin-academic from lazy to eager. Fix (3 LOC effective change): if (id.includes("/pages/admin/_shared/")) return undefined; if (id.includes("/pages/admin/")) return "admin-academic"; _shared now falls through to Vite's default chunker — typically merged into main (small + shared) OR split into a small chunk based on optimal-shared-dep analysis. Either way, admin-academic returns to admin-page-only + lazy-loaded. Pass criteria (verified post-deploy): - main index-*.js delta < 50 KB vs pre-R2 (Constraint #2 budget) - admin-academic-*.js < 55 KB (proactive flag if 45-55) - admin-academic NOT in modulepreload on / + /login + /programs HTML If Path A fails to meet criteria (e.g., _shared bloats main >50KB), fallback Path B: 3-bucket split with explicit admin-shared chunk. Lesson per D66 directive: future Phase B sub-Rs that add admin pages MUST report post-deploy bundle measurement in their review doc. The manualChunks rule surface is fragile — small import graph changes can flip chunk boundaries dramatically. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DeveloperCodeBase
added a commit
that referenced
this pull request
May 27, 2026
…nt/Instructor + 2 state machines) D67 entry in PHASE_A_DECISIONS.md (R2 D13 PASS, 8-step owner smoke confirmed, R2 closed) + D66 entry filled in (R2 admin-academic chunk leak fix Path A→B→D iteration history with the hard lesson logged for Phase B+ sub-Rs). PHASE_B_R3_MEMO.md DRAFT (~280 LOC) — Phase B Identity track: SCHEMA DISCOVERY (R1 D63 + R2 lesson #1): - User EXISTS (basic identity from Phase A) - Profile/Student/Instructor/StudentApplication/InstructorApplication all GREENFIELD per MIGRATION_POLICY §2 - R2 CourseOffering.instructorId additive wire (§4) — finally wiring the R2 Q2 deferral SCOPE: - 5 new models + 4 enums (StudentStatus / InstructorStatus / InstructorRank / AppStatus) - 2 state machines (StudentApplication + InstructorApplication share AppStatus enum, parallel transition maps): SUBMITTED → UNDER_REVIEW → INTERVIEW → ACCEPTED → ENROLLED, with REJECTED/WITHDRAWN terminal - ACCEPTED → ENROLLED side effect: creates User (if not exists) + Student/Instructor + Enrollment row for default offering - 4 admin pages (Applications inbox / Students / Instructors / Profile) — each as own lazy chunk per R2 D66 Path D pattern - NotificationLog stub (Compass §Phase B minimal): logs notification events on key transitions; real sender deferred to R-Notif post-B R1+R2 LESSONS APPLIED: - Lesson #1 (schema discovery pre-memo): done, found all greenfield except R2 additive - Lesson #2 (bundle vigilance): per-route chunking mandatory, no admin manualChunks bucket. Post-deploy bundle measurement in review doc REQUIRED. Modulepreload verification on / + /login + /programs. - Lesson #3 (state machine pattern from R2): ALLOWED_TRANSITIONS map in service layer (not controller), isLegalTransition() exported for tests, illegal transition 400 with Allowed-from-current message, soft-delete legal at any status. 4 QUESTIONS for owner: - Q1: single R3 vs split R3.a (Identity models) + R3.b (state machines) RECOMMENDED Q1.b split — state machines deserve their own atomic shipping window for D18 coverage clarity (R2 lesson) - Q2: Profile cardinality 1:1 strict vs lazy 1:0..1 RECOMMENDED Q2.a strict — predictable invariants, O(N) backfill - Q3: CourseOffering instructor cardinality (single FK / array / junction table) RECOMMENDED Q3.a single instructorId now — junction additive in R4 if team-teaching becomes real - Q4: StudentApplication userId nullable until signup vs require- account-first RECOMMENDED Q4.a nullable — lower friction for Iranian applicants ESTIMATED: ~4,450 LOC if single R3; ~2,800 + ~1,650 if split. Timeline: 7-10 days single, 4-5 days each split. OUT OF SCOPE: actual email/SMS (NotificationLog stub only), avatar upload pipeline, OAuth/SSO, applicant-facing self-service form. No R3 code starts until owner Q1-Q4 answers. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DeveloperCodeBase
added a commit
that referenced
this pull request
May 28, 2026
Owner acked R4: Q0.a + Q1.a-Q5.a + dual-write forward-only. Locked + unaffected: Q0.a (nullable courseId widening, two-shape model), Q1.a (targetOfferingId), Q3.a (course-level + partial unique), Q4.a (full admin page), Q5.a (resultingEnrollmentId), dual-write forward-only (offeringId only, no cohort back-write — respects Sunset 2026-12-31).⚠️ Q2 implementation HOLD — Commit A paused (stop triggers #1/#2/#6): Schema + CODE discovery found the memo's Q2.a assumption «existing status values already match the enum» is incorrect: - Data: existing Enrollment.status is lowercase (active/completed/ dropped/withdrawn); Postgres enum is uppercase → direct cast fails - Code: existing enrollments.controller.ts (Phase-7, RBAC-gated) uses lowercase strings throughout — STATUSES const, @isin DTOs, self-enroll create, and the nuanced status-change RBAC (admin=any, instructor= completed-only, owner=withdrawn/dropped). Converting to Postgres enum rewrites all of it + needs a data migration. → Q2.a-as-stated (Postgres enum) is a §3 modification (existing-model change + data migration + existing-code rewrite), NOT the §4-additive «+60 LOC» the memo estimated. Trips #6 (existing-data migration ambiguity → STOP before proceeding) + #1 + #2. Recommended: Q2-via-service-layer — keep status as String (storage unchanged, zero migration, zero existing-code rewrite, zero prod-data risk); deliver the state-machine INTENT at the service layer in the new R4 transition endpoint (ALLOWED_TRANSITIONS + illegal-400, same as R2/R3.b LOGIC; the Postgres enum there was just greenfield storage). This is exactly what Phase B lesson #1 (schema discovery pre-code) + the D72 «ack ≠ ground truth on internals» lesson exist to catch — flagged before writing a migration that would fail on the owner's production data during their deploy step. Commit A paused pending owner Q2 confirm. Everything else ready. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
DeveloperCodeBase
added a commit
that referenced
this pull request
May 31, 2026
Starting Commit C surfaced a memo-missed dependency (stop-triggers #1+#2): the anon student form needs a program picker + a valid programId, but GET /v1/programs is authed and the /programs marketing page is static — no public source of real program IDs. Resolution (Option A): add @public @Throttle GET /v1/programs/public ?tenantSlug= -> [{id,slug,name,nameEn,degreeLevel}], active-only, tenant-scoped. ~20 LOC backend in the "frontend" Commit C (necessary, not optional — D49/D81-family exception). Public catalog data is non-sensitive by nature (unlike application PII). Reusable primitive for future dynamic marketing / catalog browse / deep-link apply. Lesson: anon/public-feature discovery must check ALL data dependencies for public-accessibility, not just the primary models. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bumps node from 20-alpine to 26-alpine.
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot show <dependency name> ignore conditionswill show all of the ignore conditions of the specified dependency@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)