feat(ship): add project types#360
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR removes the project_categories field in favor of a single project_type, and introduces background/type inference + admin UI filtering to support the new workflow.
Changes:
- Drop
projects.project_categoriesfrom DB/schema and remove related model/view/test usages. - Add
SwAi::ProjectTypeService+ jobs to infer and backfillproject_type. - Enhance the admin certification ship queue with type breakdown/filtering and “own project” UX.
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
db/migrate/20260603180000_drop_project_categories_from_projects.rb |
Removes the project_categories column from projects. |
db/schema.rb |
Reflects dropping project_categories and bumps schema version. |
app/models/project.rb |
Removes validation tied to deleted project_categories. |
app/services/sw_ai/project_type_service.rb |
Adds service that calls SW-AI to infer a project’s type. |
config/initializers/sw_ai.rb |
Adds configuration for SW-AI URL + API key from credentials/env. |
app/jobs/project/type_check_job.rb |
Enqueues type inference and persists project_type. |
app/jobs/one_time/backfill_project_type_job.rb |
One-time enqueuer to backfill types for shipped projects. |
app/models/post/ship_event.rb |
Triggers type-check job after ship creation if project_type is nil. |
app/models/gorse/*_payload.rb |
Removes project_categories from Gorse categories/labels; uses project_type. |
app/controllers/admin/certification/ships_controller.rb |
Adds type filtering, type counts, and own-project marking data. |
app/policies/admin/certification/ship_policy.rb |
Changes reviewer scope and relaxes show? authorization. |
app/views/admin/certification/ships/index.html.erb |
Adds type breakdown chips/filter UI + “Your Project/Ship” UI changes. |
app/assets/stylesheets/pages/certification/ships/_index.scss |
Styles new type chips/tags. |
app/assets/stylesheets/components/_action_button.scss |
Makes “disabled” action buttons non-clickable via pointer-events. |
app/views/admin/projects/show.html.erb |
Removes admin display of removed project_categories. |
app/views/admin/certification/ysws/*.erb |
Switches from categories display to project_type. |
app/views/projects/show.html.erb |
Restricts “Add 15min (test)” button to members. |
test/services/sw_ai/project_type_service_test.rb |
Adds tests for new SW-AI type service behavior. |
test/models/gorse_payloads_test.rb |
Updates expectations to use project_type instead of categories. |
test/models/project_test.rb, test/fixtures/projects.yml |
Removes schema comment references to project_categories. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ff7e03e to
aba8459
Compare
|
Did you mean to add the test? |
|
Yep! Want me to remove them? |
23285f0 to
abefc5a
Compare
Merge identical &__label and &__filters label blocks into a single grouped selector, removing 7 duplicate lines.
a6d8c8a to
12fa5c4
Compare
|
You're deleting the old project_categories collum. Maybe you should Search the whole codebase for anywhere it's still used and make sure nothing's left. If something still uses it after it's deleteed, the app can break. just lmk if's no longer being used. |
|
Also, you wired up the new project "type" into Gorse, the recommendation system but type isn't supposed to touch recommendations (at least not for this PR), we're using it for it's own separate thing |
dhamariT
left a comment
There was a problem hiding this comment.
Read through the whole diff. The own-ships change is done right at the policy layer (show?/update? deny via not_own_project?, and available_for still excludes them from claiming), and the type plumbing into Gorse looks correct. One heads up for deploy: the migration drops project_categories for good, so once this runs the category data is gone. That's the point of the PR, just making sure it's deliberate. Left a few small notes inline, none of them blockers.
| count = 0 | ||
|
|
||
| scope.find_each do |project| | ||
| Project::TypeCheckJob.perform_later(project) |
There was a problem hiding this comment.
This enqueues one API call per shipped untyped project all at once, so the first run will hit the SW AI service with everything we have, throttled only by solid_queue worker concurrency. If the service rate limits, the 3-attempt retry will absorb some of it but some projects could end up unclassified until they ship again. Probably fine, just flagging it before someone runs the backfill.
| result = SwAi::ProjectTypeService.new(project).call | ||
| return unless result.ok && result.type.present? | ||
|
|
||
| project.update_column(:project_type, result.type) |
There was a problem hiding this comment.
update_column skips callbacks and paper_trail, so type changes won't show up in version history. Probably fine for a system-driven field, just noting it.
Ship the code changes first (expand/contract). The destructive remove_column migration is moved to a separate follow-up PR so the column is only dropped after this deploys and nothing references it. Restores the schema.rb column and model annotations in the meantime.
|
Heads up @Nullskulls — I pushed one commit to this branch ("defer project_categories column drop to follow-up"). It pulls the The column drop now lives in #549 (draft), which should merge after this one is deployed. The idea is expand/contract: ship the code that stops using the column first, then drop the column once nothing reads it, so the destructive part isn't coupled to this deploy and can't take the queue down if it needs backing out. Revert the commit if you'd rather keep it all in one PR. |
Follow-up to hackclub#360. That PR removes every code reference to project_categories (validation, Gorse payloads, admin/project views) but intentionally leaves the column in place. This migration drops the now-unused column. Must merge after hackclub#360 is deployed. Until hackclub#360 lands, main still reads project_categories at runtime, so dropping the column before then would break project saves.
Resolves the app/models/project.rb conflict from main's hardware_stage feature. Keeps the hardware_stage validations from main and drops the validate :validate_project_categories line (its method was already removed on this branch; project_categories is going away in hackclub#549).
what's this do?
Add type checking via external API and a job to backfill already existing projects also changing how own projects are treated when shipped no longer hiding them though still disallowing reviews.
show it works
ai?
Claude 🥀