|
| 1 | +--- |
| 2 | +name: load-universities |
| 3 | +description: Load structured university application data into the Solid Connection dev environment through admin APIs, with read-only preflight and row-level verification. |
| 4 | +--- |
| 5 | + |
| 6 | +# Load Universities |
| 7 | + |
| 8 | +Use this skill when the user asks to ingest or upsert Solid Connection university data from a CSV or XLSX file. |
| 9 | + |
| 10 | +## Scope |
| 11 | + |
| 12 | +- Target only the approved dev API: `https://stage.solid-connection.com`. |
| 13 | +- Use `/admin/**` APIs for authentication, entity reads, creation, update, and verification. |
| 14 | +- Never use the legacy Markdown import endpoint. |
| 15 | +- Never write credentials to repository files, reports, manifests, shell history examples, or final answers. |
| 16 | +- Do not target local, prod, or an arbitrary URL. |
| 17 | +- Do not mutate anything during preflight. |
| 18 | + |
| 19 | +## Files |
| 20 | + |
| 21 | +- Runner: `scripts/ingest_universities.py` |
| 22 | +- CSV template: `templates/university_ingestion_template.csv` |
| 23 | + |
| 24 | +The `.claude/skills/load-universities` and `.codex/skills/load-universities` copies must stay behaviorally identical. |
| 25 | + |
| 26 | +## Input Schema |
| 27 | + |
| 28 | +Required columns: |
| 29 | + |
| 30 | +- `term_name`: term name in `YYYY-N` format. |
| 31 | +- `home_university_name` |
| 32 | +- `home_max_choice_count`: required when the home university does not already exist. |
| 33 | +- `host_korean_name` |
| 34 | +- `host_english_name`: required when the host university does not already exist. |
| 35 | +- `host_format_name`: required when the host university does not already exist. |
| 36 | +- `country_code`: required when the host university does not already exist. |
| 37 | +- `region_code`: required when the host university does not already exist. |
| 38 | + |
| 39 | +Optional columns: |
| 40 | + |
| 41 | +- `univ_apply_info_id`: optional safety check. The runner primarily resolves existing rows by `termId + homeUniversityId + hostUniversityId`; when this ID is present it must match the resolved row. |
| 42 | +- `home_email_domain` |
| 43 | +- `student_capacity` |
| 44 | +- `semester_available_for_dispatch`: enum such as `ONE_SEMESTER`, `TWO_SEMESTER`, `ONE_OR_TWO_SEMESTER`, `ONE_YEAR`, `IRRELEVANT`, `NO_DATA`. |
| 45 | +- `semester_requirement` |
| 46 | +- `details_for_language` |
| 47 | +- `gpa_requirement` |
| 48 | +- `gpa_requirement_criteria` |
| 49 | +- `details_for_accommodation` |
| 50 | +- `extra_info`: JSON object, or `key=value;key2=value2`. |
| 51 | +- `language_requirements`: JSON array like `[{"languageTestType":"TOEFL_IBT","minScore":"80"}]`, JSON object like `{"TOEFL_IBT":"80"}`, or `TOEFL_IBT:80;IELTS:6.5`. |
| 52 | +- `homepage_url` |
| 53 | +- `english_course_url` |
| 54 | +- `accommodation_url` |
| 55 | +- `details_for_local` |
| 56 | +- `logo_file`: local path or assets-dir relative path for missing host creation. |
| 57 | +- `background_file`: local path or assets-dir relative path for missing host creation. |
| 58 | + |
| 59 | +## Commands |
| 60 | + |
| 61 | +Preflight only: |
| 62 | + |
| 63 | +```bash |
| 64 | +python3 .claude/skills/load-universities/scripts/ingest_universities.py \ |
| 65 | + --mode preflight \ |
| 66 | + --input path/to/universities.csv \ |
| 67 | + --assets-dir path/to/assets \ |
| 68 | + --admin-email "$SOLID_CONNECT_ADMIN_EMAIL" \ |
| 69 | + --admin-password "$SOLID_CONNECT_ADMIN_PASSWORD" |
| 70 | +``` |
| 71 | + |
| 72 | +Apply and verify: |
| 73 | + |
| 74 | +```bash |
| 75 | +python3 .claude/skills/load-universities/scripts/ingest_universities.py \ |
| 76 | + --mode apply \ |
| 77 | + --input path/to/universities.xlsx \ |
| 78 | + --assets-dir path/to/assets \ |
| 79 | + --admin-email "$SOLID_CONNECT_ADMIN_EMAIL" \ |
| 80 | + --admin-password "$SOLID_CONNECT_ADMIN_PASSWORD" |
| 81 | +``` |
| 82 | + |
| 83 | +Token-based authentication is also supported: |
| 84 | + |
| 85 | +```bash |
| 86 | +python3 .claude/skills/load-universities/scripts/ingest_universities.py \ |
| 87 | + --mode apply \ |
| 88 | + --input path/to/universities.csv \ |
| 89 | + --access-token "$SOLID_CONNECT_ADMIN_ACCESS_TOKEN" |
| 90 | +``` |
| 91 | + |
| 92 | +## Workflow |
| 93 | + |
| 94 | +1. Validate the input file and dev base URL before authenticating. |
| 95 | +2. Authenticate with either `--access-token` or admin email/password. |
| 96 | +3. Parse every CSV/XLSX row and validate all required fields before mutation. |
| 97 | +4. Read existing terms, home universities, and host universities through admin APIs. |
| 98 | +5. If a host university is missing and either required image is absent, stop with JSON status `needs-assets`. This is a successful preflight result and performs zero mutations. |
| 99 | +6. In `apply` mode, create missing terms, home universities, and host universities in dependency order. Existing terms, home universities, and host universities are reused and not modified. |
| 100 | +7. Resolve existing `UnivApplyInfo` records with `GET /admin/univ-apply-infos?termId=&homeUniversityId=&hostUniversityId=`. |
| 101 | +8. Fail on duplicate natural-key matches. Create absent `UnivApplyInfo` records and update existing records, including language requirements. |
| 102 | +9. Re-fetch every touched `UnivApplyInfo` with `GET /admin/univ-apply-infos/{id}` and compare relation IDs, host Korean name, core fields, `extraInfo`, and language requirements. |
| 103 | +10. Treat any mismatch as failure. Report created/reused/updated/failed counts and row-level failures. |
0 commit comments