Review plan for complete HTTP-level API coverage (GraphQL + REST + scheduler) so changes are safer. Not an AI-adoption exercise — a verification harness. Evidence from live code · TEMP-app + findTEMP-webapp clients · 2026-08-06. No changes to the hime repo yet.
Mapped against the existing hime/spec suite (2026-08-06).
Missing no automated test ·
Logic form/service/HimeSchema.execute (not HTTP) ·
Controller controller spec (scheduler X-Secret usually stubbed) ·
HTTP real Rack E2E — none yet.
Hover a pill for the evidence path. Journeys: 9 missing · 15 logic · 6 controller.
Tasks: 66 missing · 14 logic · 4 controller.
hime has 153 RSpec files but zero HTTP-level API tests.
Every GraphQL spec calls HimeSchema.execute with a forged
current_user, skipping JWT, App-Name context, role extensions,
complexity limits, and the hand-rolled operation-name parser in
GraphQLController. CI deploys Docker images and never runs tests.
This page is the backlog to build an additive spec/e2e/ layer that
drives the real Rack stack, covers every client + scheduler use case, and runs
in parallel via Testcontainers + parallel_tests (pinned for Ruby 2.7).
scheduler/* endpoints that advance job / wallet / attendance lifecycle have contract specs; payment callbacks covered.bin/e2e -n 4 completes under an agreed wall-clock budget on CI with WebMock blocking real egress.unit.yml + e2e.yml are required checks on master.S / M / L are relative sizing hints. They are not commitments. Waves 0–1 should be single-owner (harness). Waves 2–3 are shaped for parallel hand-off (contracts + journeys). Treat tiers as capacity guidance given product work.
| Finding | Evidence | Why it matters |
|---|---|---|
| GraphQL specs skip HTTP | spec/graphql/** — HimeSchema.execute(…, context: {current_user:}) | JWT, App-Name, role extensions, Student-Unbanned-At header never exercised. |
| Fragile operation-name parser | graph_q_l_controller.rb — query.split('{')[1].split('(')[0] | Breaks on atypical documents; only visible over real HTTP. |
| No CI test job | deploy-to-staging.yml · bitbucket-pipelines.yml | Deploy-only; suite can rot unnoticed. |
| Fixtures only · no factory_bot | spec/fixtures/*.yml (~44) · no spec/factories | Multi-state E2E scenarios become brittle YAML. |
| No WebMock / VCR | Gemfile :test | Nothing blocks real GB Prime Pay / SMS / Discord / FCM calls. |
| Global Timecop at load | spec/support/timecop.rb → 2025-07-01 08:00 | Pricing/holiday logic sensitive; e2e needs explicit baseline. |
| Attendance photos force S3 | storage.yml student_job_hiring_attendance · JobHiringAttendance | Parallel workers need Disk roots + TEST_ENV_NUMBER. |
| RabbitMqProducer connects in initialize | app/utils/rabbit_mq_producer.rb | WebMock cannot see Bunny; needs explicit fake. |
| APNS key at class body | PushNotificationSender::APNS_KEY = OpenSSL::PKey::EC.new(…) | CI needs dummy EC key in .env.test or boot fails. |
| .ruby-version stale | .ruby-version 2.6.4 vs Gemfile 2.7.7 | Local/CI reproducibility noise before e2e work. |
| Lifecycle advances via cron | routes.rb scheduler/* (~42) · aws_lambda/ | Client-only tests cannot cover debit / auto-hire / attendance approve. |
| 26 model observers | app/utils/observer/* | Side effects (outbox, mail, Discord) are the assertion seam for journeys. |
153 files under spec/ using fixtures + HimeSchema.execute. Untouched. Fast feedback for pure logic.
One template × ~181 operations over HTTP. Happy / unauth / wrong-role / validation. Produces the coverage guarantee.
~30 multi-actor flows. Handwritten. Assert wallet + outbox. What actually catches refactors.
spec/e2e/ contracts/graphql/queries|mutations/ contracts/rest/ | scheduler/ | callbacks/ journeys/single_job|period_job|money|lifecycle_edges/ documents/temp_app/ | findtemp_webapp/ support/actor.rb scenario/ stubs/ matchers/ coverage_recorder.rb spec/factories/ bin/e2e
ActiveAdmin HTML (admin/kami/sale/accounts), visual/UI of mobile apps, real provider sandboxes, load/performance, Ruby/Rails upgrade itself (this suite is the safety net before that upgrade).
One PostGIS container, N databases — not one container per worker (kartoza/postgis:17-3.5 is heavy).
E2E_REUSE_DB=1 → compose db).hime-test once; CREATE DATABASE hime-testN TEMPLATE hime-test.parallel_rspec -n N (pin 5.3.0 — 5.3.1 dropped Ruby 2.7). Each worker gets its DB + TEST_ENV_NUMBER storage root.use_transactional_fixtures — Rack::Test is in-process; rollback stays valid.| Shared state | Isolation |
|---|---|
| Postgres | hime-test / hime-test2… per worker |
| ActiveStorage Disk | tmp/storage$TEST_ENV_NUMBER |
| Attendance S3 service | Redirect to Disk in test env |
| PDF / xlsx exports | tmp/e2e-exports$TEST_ENV_NUMBER |
| Singletons (Bunny, FCM) | Fake before first reference |
Real POST /users/sign_in, capture access-token / refresh-token, replay client headers.
| Actor | Auth | App-Name | Used for |
|---|---|---|---|
| student | JWT | TEMP | apply, attend, campaigns |
| restaurant | JWT | findTEMP | createJob, accept, top-up |
| guest | none | findTEMP / TEMP | Fast Track, sample_jobs, registration |
| scheduler | X-Secret | — | debit, auto-hire, notify bots |
| Provider | Mechanism | Stub strategy |
|---|---|---|
| GB Prime Pay | HTTParty | WebMock fixtures |
| THSMS | HTTParty | WebMock + SmsSender recorder |
| SNS / Pinpoint SMS | AWS SDK | stub_responses: true |
| Flowaccount | Faraday/HTTParty | stub client / WebMock |
| Discord | Faraday | WebMock + recorder |
| Google Maps | upstream HTTP | WebMock fixtures |
| FCM / Expo / APNS | SDK / HTTP2 | no-op send_*; enqueue writes outbox |
| S3 / SES / Connect | AWS SDK | stub_responses |
| RabbitMQ | Bunny | Fake singleton (not HTTP) |
| Makro SFTP | Net::SFTP | Fake (not HTTP) |
documents_valid_spec runs HimeSchema.validate on each.
“Every use case” is only meaningful if measurable. An RSpec hook records GraphQL
operationName and controller#action per example into
tmp/e2e_coverage-<worker>.json. A rake task merges workers and diffs
against this inventory + Rails.application.routes. CI fails below
E2E_COVERAGE_MIN (start ~40%, ratchet toward 90%).
Inventory counts: 43 GraphQL queries · 60 mutations · 29 REST · 42 scheduler · 7 callbacks · 30 journeys.
bin/e2e -n 2.Eleven categories. Today shows what the current suite already covers for that work. Size = S/M/L indicative. Checkboxes persist in localStorage. Click a task ID/title to open its markdown from /hime-tasks/.
Gems, bin/e2e, e2e_helper, .env.test. Wave 0 single-owner.
| Done | ID | Task | Today | Size | Tier | Wave | Agent? | Evidence | Acceptance |
|---|---|---|---|---|---|---|---|---|---|
| Missing | S | 1 | 0 | Yes | Gemfile | webmock, factory_bot_rails, testcontainers-core, parallel_tests=5.3.0 in :test; bundle installs on 2.7.7 | |||
| Missing | S | 1 | 0 | Yes | spec/e2e/ | e2e_helper loads Rails; rails_helper untouched; existing 153 specs still green | |||
| Missing | M | 1 | 0 | Partial | bin/e2e | starts PostGIS via testcontainers, loads schema, runs parallel_rspec, tears down | |||
| Missing | S | 1 | 0 | Yes | bin/e2e | E2E_REUSE_DB=1 skips container start and uses compose db:5432 | |||
| Missing | M | 1 | 0 | Yes | bin/e2e | hime-test schema loaded once; hime-test2..N created via CREATE DATABASE TEMPLATE | |||
| Missing | S | 1 | 0 | Yes | .rspec / rails_helper | bundle exec rspec excludes e2e; bin/e2e includes only e2e | |||
| Missing | S | 1 | 0 | Partial | .env.test | SCHEDULER_KEY, dummy AWS, valid dummy APNS P8; PushNotificationSender loads | |||
| Missing | S | 1 | 0 | Yes | .ruby-version | matches Gemfile.lock ruby 2.7.7 |
Per-worker DB clones, ActiveStorage roots, cache_classes.
| Done | ID | Task | Today | Size | Tier | Wave | Agent? | Evidence | Acceptance |
|---|---|---|---|---|---|---|---|---|---|
| Missing | S | 1 | 0 | Yes | config/storage.yml | test + student_job_hiring_attendance use Disk with TEST_ENV_NUMBER suffix | |||
| Missing | S | 1 | 0 | Yes | config/storage.yml / test.rb | JobHiringAttendance photo attach works without AWS | |||
| Missing | S | 1 | 0 | Yes | spec/e2e/support | export paths include TEST_ENV_NUMBER; no cross-worker collisions | |||
| Missing | S | 1 | 0 | Yes | config/environments/test.rb | matches Rails parallel guidance; suite boots once per worker | |||
| Missing | S | 1 | 1 | Yes | AGENTS.md / README | table of DB / storage / tmp / Timecop / singletons per worker | |||
| Missing | S | 1 | 0 | Partial | bin/e2e -n 2 | launcher completes; both DBs exist; exit 0 |
WebMock + provider stubs + non-HTTP fakes.
| Done | ID | Task | Today | Size | Tier | Wave | Agent? | Evidence | Acceptance |
|---|---|---|---|---|---|---|---|---|---|
| Missing | S | 1 | 1 | Yes | spec/e2e/e2e_helper.rb | any unstubbed HTTP raises; localhost/Testcontainers allowed | |||
| Missing | S | 1 | 1 | Yes | spec/e2e/support/stubs/gb_prime_pay.rb | charge + QR endpoints return fixture payloads | |||
| Missing | S | 1 | 1 | Yes | stubs/sms.rb | SmsSender records messages; no real network | |||
| Missing | S | 1 | 1 | Yes | stubs/flowaccount.rb | invoice calls recorded; HTTParty never hits network | |||
| Missing | S | 1 | 1 | Yes | stubs/discord.rb | webhooks and bot API recorded | |||
| Missing | S | 1 | 1 | Yes | stubs/google_maps.rb | geocode/autocomplete/details return fixtures | |||
| Missing | S | 1 | 1 | Yes | stubs/push.rb | PushNotificationSender send_* no-ops; enqueue still writes outbox | |||
| Missing | S | 1 | 1 | Yes | stubs/aws.rb | S3 upload, SES, Connect clients stubbed | |||
| Missing | M | 1 | 1 | Yes | stubs/rabbitmq.rb | publish records payloads; initialize does not open connection | |||
| Missing | S | 2 | 1 | Yes | stubs/sftp.rb | upload_makro_* specs do not open SSH | |||
| Missing | S | 1 | 1 | Yes | spec/e2e/support | intentional unstubbed call fails the example |
Four roles over real HTTP with client headers.
| Done | ID | Task | Today | Size | Tier | Wave | Agent? | Evidence | Acceptance |
|---|---|---|---|---|---|---|---|---|---|
| Missing | M | 1 | 1 | Yes | spec/e2e/support/actor.rb | Actor#post/#get/#gql send App-Name/App-Version | |||
| Missing | S | 1 | 1 | Yes | actor.rb | captures access-token + refresh-token; Authorization Bearer set | |||
| Missing | S | 1 | 1 | Yes | actor.rb | App-Name findTEMP; IsFindTemp-equivalent user with chain_id | |||
| Missing | S | 1 | 1 | Yes | actor.rb | guest requests work for Fast Track + sample_jobs | |||
| Missing | S | 1 | 1 | Yes | actor.rb | POST /scheduler/* authorized with SCHEDULER_KEY | |||
| Missing | S | 1 | 1 | Yes | actor.rb | refresh! hits POST /users/tokens and rotates headers | |||
| Missing | S | 1 | 1 | Yes | support/matchers | expect_gql_unauthorized / wrong_role helpers |
factory_bot + Scenario builders; fixtures untouched.
| Done | ID | Task | Today | Size | Tier | Wave | Agent? | Evidence | Acceptance |
|---|---|---|---|---|---|---|---|---|---|
| Missing | S | 1 | 1 | Yes | spec/factories / e2e_helper | factories load only for e2e; fixtures remain for old specs | |||
| Missing | M | 1 | 1 | Yes | factories/users.rb | student user signs in; is_student? true | |||
| Missing | M | 1 | 1 | Yes | factories/chains.rb | restaurant user with chain_id and permissions | |||
| Missing | M | 1 | 1 | Yes | factories/jobs.rb | open job with positions; period job with children | |||
| Missing | M | 1 | 1 | Yes | factories/wallets.rb | funded chain + student wallets for money journeys | |||
| Missing | M | 2 | 1 | Yes | factories/* | enough traits for inventory tiers 1–2 | |||
| Missing | M | 1 | 1 | Yes | support/scenario/ | one call yields employer+student+matched JobHiring | |||
| Missing | S | 1 | 1 | Yes | support/scenario/ | confirmed hiring in operable time window | |||
| Missing | S | 1 | 1 | Yes | support/scenario/ | chain ready for QR / card top-up | |||
| Missing | S | 1 | 2 | Yes | scenario docs | createJob via Actor when testing apply; document exceptions |
Vendor TEMP-app + findTEMP documents; validate against HimeSchema.
| Done | ID | Task | Today | Size | Tier | Wave | Agent? | Evidence | Acceptance |
|---|---|---|---|---|---|---|---|---|---|
| Missing | M | 1 | 1 | Yes | spec/e2e/documents/temp_app/ | all 75 client operations present as .graphql | |||
| Missing | M | 1 | 1 | Yes | spec/e2e/documents/findtemp_webapp/ | all 56 client operations present | |||
| Missing | S | 1 | 1 | Yes | documents_valid_spec.rb | any removed/renamed field fails CI | |||
| Missing | S | 2 | 1 | Yes | README | how to re-vendor after client codegen changes | |||
| Missing | S | 1 | 1 | Yes | support/coverage | JSON map used by coverage recorder |
Outbox, mail, SMS, wallet matchers + e2e clock.
| Done | ID | Task | Today | Size | Tier | Wave | Agent? | Evidence | Acceptance |
|---|---|---|---|---|---|---|---|---|---|
| Missing | S | 1 | 1 | Yes | support/matchers/notify.rb | assert message_type / channel / user_id | |||
| Missing | S | 1 | 1 | Yes | matchers/mail.rb | ActionMailer::Base.deliveries filtered | |||
| Missing | S | 1 | 1 | Yes | matchers/sms.rb | reads SmsSender stub recorder | |||
| Missing | S | 1 | 1 | Yes | matchers/wallet.rb | balance + txn type/amount assertions | |||
| Missing | S | 1 | 1 | Yes | support/time.rb | e2e uses own Timecop; does not rely on global travel | |||
| Missing | S | 2 | 1 | Yes | stubs + matchers | journeys can assert Discord/IVR intents fired |
Breadth: one template × ~182 operations, grouped by feature.
| Done | ID | Task | Today | Size | Tier | Wave | Agent? | Evidence | Acceptance |
|---|---|---|---|---|---|---|---|---|---|
| Logic | M | 1 | 2 | Yes | contracts/graphql/queries | jobsV2, job, jobApplicantsV2, jobHiring, enums, sample_jobs REST | |||
| Logic | M | 1 | 2 | Yes | contracts/graphql/queries | jobs, incomingJobs, pendingJobHiringJobs, jobHiringsV2, permissions, pricing | |||
| Logic | S | 1 | 2 | Yes | contracts/ | notifications, markRead, register/unregister push | |||
| Logic | M | 2 | 2 | Yes | contracts/ | student engagement query+mutation fields | |||
| Missing | M | 1 | 2 | Yes | contracts/ | topup*, chargeGbPrimePay, transactions | |||
| Logic | M | 1 | 2 | Yes | contracts/mutations | happy + wrong-role + validation + idempotency header | |||
| Logic | M | 1 | 2 | Yes | contracts/mutations | accept, dislike, settle, getOffWork, review, tips, attendances | |||
| Logic | M | 1 | 2 | Yes | contracts/mutations | applyJob, checkIn/Out, confirmWork, cancel, leave, ban edges | |||
| Missing | S | 1 | 2 | Yes | contracts/ | createRestaurant, editRestaurantV2, contact, image upload | |||
| Logic | M | 2 | 2 | Yes | contracts/ | editStudent, training, tutorial, survey, certificate | |||
| Logic | M | 1 | 2 | Yes | contracts/rest | sign_in/out, tokens, passwords, reset, registration, PDPA, OTP | |||
| Missing | S | 2 | 2 | Yes | contracts/rest | geocode/autocomplete/details stubbed upstream | |||
| Logic | M | 1 | 2 | Yes | contracts/ | create_guest_job, discounts, charge_699, gb_prime callbacks | |||
| Controller | M | 2 | 2 | Yes | contracts/scheduler | X-Secret auth, empty-input no-op, idempotent re-run | |||
| Controller | M | 1 | 2 | Yes | contracts/scheduler | auto-hire, confirm notify, claw, auto-approve | |||
| Controller | M | 1 | 2 | Yes | contracts/scheduler | student_debit_v4 primary; older debit versions smoke |
Depth: multi-actor flows that catch real regressions.
| Done | ID | Task | Today | Size | Tier | Wave | Agent? | Evidence | Acceptance |
|---|---|---|---|---|---|---|---|---|---|
| Logic | L | 1 | 2 | Partial | journeys/single_job/ | full lifecycle green under parallel_rspec | |||
| Logic | L | 1 | 3 | Partial | journeys/lifecycle_edges/ | wallet + outbox assertions hold | |||
| Controller | L | 1 | 3 | Partial | journeys/period_job/ | bot auto-hire + cancel + idempotent create | |||
| Logic | L | 1 | 3 | Partial | journeys/money/ | QR, card, Fast Track; callbacks credit wallets | |||
| Logic | L | 2 | 3 | Partial | journeys/ | registration, PDPA, OTP, campaigns, push, wrong-role | |||
| Missing | M | 1 | 1 | Partial | journeys/single_job/happy_path_spec.rb | bin/e2e -n 2 passes with J01 only |
Make 'every use case' a CI-enforced number.
| Done | ID | Task | Today | Size | Tier | Wave | Agent? | Evidence | Acceptance |
|---|---|---|---|---|---|---|---|---|---|
| Missing | M | 1 | 2 | Yes | support/coverage_recorder.rb | per-worker JSON under tmp/e2e_coverage-*.json | |||
| Missing | M | 1 | 2 | Yes | lib/tasks/e2e_coverage.rake | prints uncovered ops vs schema+routes | |||
| Missing | S | 1 | 2 | Partial | e2e.yml | fails below E2E_COVERAGE_MIN; bump documented | |||
| Missing | S | 2 | 3 | Yes | e2e.yml | job summary shows % and top gaps |
Required checks, README, AGENTS.md.
| Done | ID | Task | Today | Size | Tier | Wave | Agent? | Evidence | Acceptance |
|---|---|---|---|---|---|---|---|---|---|
| Missing | S | 1 | 2 | Yes | .github/workflows/unit.yml | rspec green required on PR | |||
| Missing | M | 1 | 2 | Partial | .github/workflows/e2e.yml | Docker available; PostGIS via testcontainers; required check | |||
| Missing | S | 1 | 1 | Yes | hime/README.md | how to run locally with reuse and parallel | |||
| Missing | S | 1 | 1 | Yes | AGENTS.md | layers, actors, stubs, what-not-to-test, coverage | |||
| Missing | S | 1 | 2 | No | GitHub branch protection | human: enable required checks on master |
One row per operation. Today = existing suite coverage (hover for evidence). Cases matrix: Happy · Unauth · wrong-Role · Validation · Side-effect. Checkboxes track E2E completion progress (separate from Today).
| Done | ID | Surface | Operation | Today | Role | Clients | Cases | Journey | Task | Tier |
|---|---|---|---|---|---|---|---|---|---|---|
| Q01 | GQL Q | enumJobTypesAndDuties | Missing | any | temp | HURVS | — | 1 | ||
| Q02 | GQL Q | jobCreatingOption | Missing | restaurant | findtemp | HURVS | J01 | 1 | ||
| Q03 | GQL Q | jobPricing | Logic | restaurant | findtemp | HURVS | J01 | 1 | ||
| Q04 | GQL Q | notifications | Logic | any | both | HURVS | J20 | 1 | ||
| Q05 | GQL Q | restaurantCategories | Missing | any | none | HURVS | — | 2 | ||
| Q06 | GQL Q | campaignTickets | Logic | student | temp | HURVS | J18 | 2 | ||
| Q07 | GQL Q | chainJobs | Missing | student | temp | HURVS | — | 2 | ||
| Q08 | GQL Q | challenges | Missing | any | temp | HURVS | J19 | 2 | ||
| Q09 | GQL Q | getGbPrimePayQrCode | Missing | restaurant | findtemp | HURVS | J12 | 1 | ||
| Q10 | GQL Q | getTutorial | Logic | any | temp | HURVS | J17 | 2 | ||
| Q11 | GQL Q | incomingJobs | Missing | any | findtemp | HURVS | — | 1 | ||
| Q12 | GQL Q | job | Logic | any | both | HURVS | J01 | 1 | ||
| Q13 | GQL Q | jobApplicants | Missing | any | none | HURVS | — | 3 | ||
| Q14 | GQL Q | jobApplicantsV2 | Missing | any | both | HURVS | J01 | 1 | ||
| Q15 | GQL Q | jobHiring | Missing | any | temp | HURVS | J01 | 1 | ||
| Q16 | GQL Q | jobHiringAttendances | Missing | restaurant | none | HURVS | J01 | 2 | ||
| Q17 | GQL Q | jobHirings | Missing | any | temp | HURVS | — | 2 | ||
| Q18 | GQL Q | jobHiringsV2 | Missing | restaurant | findtemp | HURVS | J01 | 1 | ||
| Q19 | GQL Q | jobs | Logic | restaurant | findtemp | HURVS | J01 | 1 | ||
| Q20 | GQL Q | pendingJobHiringJobs | Missing | restaurant | findtemp | HURVS | J01 | 1 | ||
| Q21 | GQL Q | periodJobs | Logic | restaurant | findtemp | HURVS | J08 | 1 | ||
| Q22 | GQL Q | permissions | Missing | restaurant | findtemp | HURVS | — | 1 | ||
| Q23 | GQL Q | reward | Missing | any | temp | HURVS | J19 | 2 | ||
| Q24 | GQL Q | rewards | Missing | any | temp | HURVS | J19 | 2 | ||
| Q25 | GQL Q | skills | Missing | any | temp | HURVS | J16 | 2 | ||
| Q26 | GQL Q | survey | Missing | any | temp | HURVS | J17 | 2 | ||
| Q27 | GQL Q | tips | Missing | any | temp | HURVS | — | 2 | ||
| Q28 | GQL Q | topupInfo | Missing | any | findtemp | HURVS | J12 | 1 | ||
| Q29 | GQL Q | topupItems | Missing | any | findtemp | HURVS | J12 | 1 | ||
| Q30 | GQL Q | topupStatus | Missing | any | findtemp | HURVS | J12 | 1 | ||
| Q31 | GQL Q | trainingQuestions | Missing | student | temp | HURVS | J17 | 2 | ||
| Q32 | GQL Q | trainings | Missing | student | temp | HURVS | J17 | 2 | ||
| Q33 | GQL Q | transactions | Missing | any | both | HURVS | J12 | 1 | ||
| Q34 | GQL Q | user | Missing | any | both | HURVS | J01 | 1 | ||
| Q35 | GQL Q | challengeScoreTransactions | Missing | student | temp | HURVS | J19 | 2 | ||
| Q36 | GQL Q | enumCovid19Vaccines | Missing | student | none | HURVS | — | 3 | ||
| Q37 | GQL Q | jobsV2 | Missing | student | temp | HURVS | J01 | 1 | ||
| Q38 | GQL Q | latestStudentReview | Missing | student | none | HURVS | — | 3 | ||
| Q39 | GQL Q | pendingStudentLeaveJobHirings | Missing | student | temp | HURVS | J15 | 1 | ||
| Q40 | GQL Q | skillRequests | Logic | student | temp | HURVS | J16 | 2 | ||
| Q41 | GQL Q | studentsCampaigns | Missing | student | temp | HURVS | J18 | 2 | ||
| Q42 | GQL Q | uniform | Logic | student | temp | HURVS | — | 2 | ||
| Q43 | GQL Q | uniforms | Logic | student | temp | HURVS | — | 2 |
| Done | ID | Surface | Operation | Today | Role | Clients | Cases | Journey | Task | Tier |
|---|---|---|---|---|---|---|---|---|---|---|
| M01 | GQL M | acceptAppliedStudent | Missing | restaurant | findtemp | HURVS | J01 | 1 | ||
| M02 | GQL M | approveJobHiringAttendances | Logic | restaurant | none | HURVS | J01 | 1 | ||
| M03 | GQL M | banStudent | Logic | restaurant | findtemp | HURVS | J15 | 1 | ||
| M04 | GQL M | bulkCreateTips | Missing | restaurant | findtemp | HURVS | J01 | 2 | ||
| M05 | GQL M | chargeGbPrimePay | Missing | restaurant | findtemp | HURVS | J13 | 1 | ||
| M06 | GQL M | closeJob | Missing | restaurant | none | HURVS | J14 | 2 | ||
| M07 | GQL M | createJob | Logic | restaurant | findtemp | HURVS | J01 | 1 | ||
| M08 | GQL M | createJobs | Logic | restaurant | findtemp | HURVS | J08 | 1 | ||
| M09 | GQL M | createRestaurant | Missing | restaurant | findtemp | HURVS | — | 1 | ||
| M10 | GQL M | dislikeAppliedStudent | Missing | restaurant | findtemp | HURVS | J01 | 1 | ||
| M11 | GQL M | editRestaurantV2 | Missing | restaurant | findtemp | HURVS | — | 1 | ||
| M12 | GQL M | exportJobHirings | Missing | restaurant | findtemp | HURVS | — | 2 | ||
| M13 | GQL M | getOffWork | Logic | restaurant | findtemp | HURVS | J01 | 1 | ||
| M14 | GQL M | rejectJobHiringAttendances | Logic | restaurant | none | HURVS | J01 | 2 | ||
| M15 | GQL M | reportJobHiringAbsent | Logic | restaurant | findtemp | HURVS | J15 | 1 | ||
| M16 | GQL M | reviewStudent | Missing | restaurant | findtemp | HURVS | J01 | 1 | ||
| M17 | GQL M | settleJob | Logic | restaurant | findtemp | HURVS | J01 | 1 | ||
| M18 | GQL M | startWork | Missing | restaurant | none | HURVS | J01 | 2 | ||
| M19 | GQL M | updateJobHiringAttendances | Logic | restaurant | none | HURVS | J01 | 2 | ||
| M20 | GQL M | updateJobHiringStatus | Missing | restaurant | none | HURVS | — | 3 | ||
| M21 | GQL M | updateJobRestaurantBidPrice | Missing | restaurant | findtemp | HURVS | J01 | 1 | ||
| M22 | GQL M | upsertUserRestaurantContact | Missing | restaurant | findtemp | HURVS | — | 1 | ||
| M23 | GQL M | cancelPeriodJob | Logic | restaurant | findtemp | HURVS | J09 | 1 | ||
| M24 | GQL M | allowNotification | Missing | student | temp | HURVS | — | 2 | ||
| M25 | GQL M | answerTrainingQuestion | Missing | student | temp | HURVS | J17 | 2 | ||
| M26 | GQL M | answerTutorialQuestion | Missing | student | temp | HURVS | J17 | 2 | ||
| M27 | GQL M | applyJob | Logic | student | temp | HURVS | J01 | 1 | ||
| M28 | GQL M | applyPeriodJobs | Logic | student | temp | HURVS | J08 | 1 | ||
| M29 | GQL M | checkIn | Logic | student | temp | HURVS | J01 | 1 | ||
| M30 | GQL M | checkOut | Logic | student | temp | HURVS | J01 | 1 | ||
| M31 | GQL M | confirmWork | Missing | student | temp | HURVS | J01 | 1 | ||
| M32 | GQL M | connectDiscordUser | Missing | student | temp | HURVS | — | 2 | ||
| M33 | GQL M | createLeave | Logic | student | none | HURVS | J15 | 3 | ||
| M34 | GQL M | createStudentActivity | Missing | student | temp | HURVS | J17 | 2 | ||
| M35 | GQL M | createStudentCertificate | Missing | student | none | HURVS | — | 3 | ||
| M36 | GQL M | createStudentCovid19Vaccine | Missing | student | none | HURVS | — | 3 | ||
| M37 | GQL M | createStudentLeave | Logic | student | temp | HURVS | J15 | 1 | ||
| M38 | GQL M | editStudent | Missing | student | temp | HURVS | — | 1 | ||
| M39 | GQL M | favoriteRestaurant | Missing | student | temp | HURVS | J01 | 2 | ||
| M40 | GQL M | redeemCampaignTicket | Logic | student | temp | HURVS | J18 | 2 | ||
| M41 | GQL M | requestCertificateOfEmployment | Logic | student | temp | HURVS | — | 2 | ||
| M42 | GQL M | requestLeaveJob | Missing | student | temp | HURVS | J15 | 1 | ||
| M43 | GQL M | requestSkill | Missing | student | temp | HURVS | J16 | 2 | ||
| M44 | GQL M | reviewRestaurant | Missing | student | temp | HURVS | J01 | 1 | ||
| M45 | GQL M | studentReferral | Missing | student | temp | HURVS | J18 | 2 | ||
| M46 | GQL M | acceptPdpa | Logic | any | both | HURVS | — | 1 | ||
| M47 | GQL M | cancelJob | Logic | any | both | HURVS | J14 | 1 | ||
| M48 | GQL M | changeUsername | Missing | any | both | HURVS | — | 1 | ||
| M49 | GQL M | createOtpToken | Missing | any | both | HURVS | — | 1 | ||
| M50 | GQL M | createUserDeleteRequest | Missing | any | temp | HURVS | — | 2 | ||
| M51 | GQL M | markNotificationRead | Missing | any | both | HURVS | J20 | 1 | ||
| M52 | GQL M | markNotificationReceived | Missing | any | none | HURVS | — | 3 | ||
| M53 | GQL M | redeemReward | Missing | any | temp | HURVS | J19 | 2 | ||
| M54 | GQL M | registerExpoPushToken | Missing | any | none | HURVS | — | 3 | ||
| M55 | GQL M | registerNotificationPushToken | Missing | any | both | HURVS | J20 | 1 | ||
| M56 | GQL M | submitSurveyAnswers | Missing | any | temp | HURVS | J17 | 2 | ||
| M57 | GQL M | testPushNotification | Missing | any | findtemp | HURVS | — | 3 | ||
| M58 | GQL M | unregisterExpoPushToken | Missing | any | none | HURVS | — | 3 | ||
| M59 | GQL M | unregisterNotificationPushToken | Missing | any | both | HURVS | J20 | 1 | ||
| M60 | GQL M | updateJobHiringOperationTime | Missing | any | both | HURVS | J01 | 1 |
| Done | ID | Surface | Operation | Today | Role | Clients | Cases | Journey | Task | Tier |
|---|---|---|---|---|---|---|---|---|---|---|
| R01 | REST | POST /users/sign_in | Missing | guest | both | HURVS | J01 | 1 | ||
| R02 | REST | DELETE /users/sign_out | Missing | any | both | HURVS | J20 | 1 | ||
| R03 | REST | POST /users/tokens | Missing | any | both | HURVS | — | 1 | ||
| R04 | REST | PATCH /users/passwords | Missing | any | both | HURVS | — | 1 | ||
| R05 | REST | POST /registration | Logic | guest | both | HURVS | — | 1 | ||
| R06 | REST | GET /registration/can_skip | Missing | guest | temp | HURVS | — | 2 | ||
| R07 | REST | POST /reset_password | Missing | guest | both | HURVS | — | 1 | ||
| R08 | REST | PATCH /reset_password | Missing | guest | both | HURVS | — | 1 | ||
| R09 | REST | GET /enums/:key | Missing | any | both | HURVS | — | 1 | ||
| R10 | REST | GET /health_check | Missing | guest | none | HURVS | — | 1 | ||
| R11 | REST | POST /image_service | Missing | any | both | HURVS | — | 1 | ||
| R12 | REST | GET /sample_jobs | Missing | guest | temp | HURVS | — | 2 | ||
| R13 | REST | GET /sample_jobs/:id | Missing | guest | temp | HURVS | — | 2 | ||
| R14 | REST | GET /training_questions | Missing | guest | temp | HURVS | J17 | 2 | ||
| R15 | REST | GET /training_attempts/:phone | Missing | guest | temp | HURVS | J17 | 2 | ||
| R16 | REST | POST /training_attempts/:phone | Missing | guest | temp | HURVS | J17 | 2 | ||
| R17 | REST | GET /training/video | Missing | guest | temp | HURVS | J17 | 3 | ||
| R18 | REST | GET /verify | Missing | guest | none | HURVS | — | 2 | ||
| R19 | REST | GET /google_api/geocode | Missing | any | temp | HURVS | — | 2 | ||
| R20 | REST | GET /google_api/place_autocomplete | Missing | any | temp | HURVS | — | 2 | ||
| R21 | REST | GET /google_api/place_details | Missing | any | temp | HURVS | — | 2 | ||
| R22 | REST | GET /google_api_v2/geocode | Missing | any | findtemp | HURVS | — | 2 | ||
| R23 | REST | POST /google_api_v2/place_autocomplete | Missing | any | findtemp | HURVS | — | 2 | ||
| R24 | REST | GET /google_api_v2/place_details/:id | Missing | any | findtemp | HURVS | — | 2 | ||
| R25 | REST | POST /create_guest_job | Logic | guest | findtemp | HURVS | J11 | 1 | ||
| R26 | REST | GET /discounts/:code | Logic | guest | findtemp | HURVS | J11 | 1 | ||
| R27 | REST | POST /charge_credit_card_699 | Missing | guest | findtemp | HURVS | J11 | 1 | ||
| R28 | REST | GET /charge_credit_card_699/:ref | Missing | guest | findtemp | HURVS | J11 | 1 | ||
| R29 | REST | GET /students_pdf/:id | Missing | any | none | HURVS | — | 3 |
| Done | ID | Surface | Operation | Today | Role | Clients | Cases | Journey | Task | Tier |
|---|---|---|---|---|---|---|---|---|---|---|
| S01 | Sched | POST /scheduler/admin_notify_job_hiring_not_start_operate | Missing | scheduler | sched | HURVS | — | 2 | ||
| S02 | Sched | POST /scheduler/admin_notify_job_replacing_not_match | Missing | scheduler | sched | HURVS | — | 2 | ||
| S03 | Sched | POST /scheduler/admin_notify_not_full_hiring_job | Missing | scheduler | sched | HURVS | — | 2 | ||
| S04 | Sched | POST /scheduler/admin_notify_not_full_period_job | Controller | scheduler | sched | HURVS | J09 | 2 | ||
| S05 | Sched | POST /scheduler/admin_notify_not_full_urgent_job | Missing | scheduler | sched | HURVS | — | 2 | ||
| S06 | Sched | POST /scheduler/bot_auto_approve_reject_attendances | Controller | scheduler | sched | HURVS | J01 | 1 | ||
| S07 | Sched | POST /scheduler/bot_auto_hiring_period_jobs | Controller | scheduler | sched | HURVS | J08 | 1 | ||
| S08 | Sched | POST /scheduler/bot_auto_hiring_perfect_period_jobs | Controller | scheduler | sched | HURVS | J08 | 1 | ||
| S09 | Sched | POST /scheduler/bot_cancel_unconfirmed_first_jobber_hirings | Controller | scheduler | sched | HURVS | J01 | 1 | ||
| S10 | Sched | POST /scheduler/bot_random_job_hiring_and_student_leave_status | Missing | scheduler | sched | HURVS | — | 3 | ||
| S11 | Sched | POST /scheduler/bot_set_student_district | Missing | scheduler | sched | HURVS | — | 3 | ||
| S12 | Sched | POST /scheduler/bot_student_random_apply_not_full_job | Missing | scheduler | sched | HURVS | — | 3 | ||
| S13 | Sched | POST /scheduler/backfill_user_notifications | Controller | scheduler | sched | HURVS | — | 3 | ||
| S14 | Sched | POST /scheduler/claw_pending_topup_attempt | Missing | scheduler | sched | HURVS | J12 | 1 | ||
| S15 | Sched | POST /scheduler/credit_report | Missing | scheduler | sched | HURVS | — | 2 | ||
| S16 | Sched | POST /scheduler/crm_churned_chains_report | Missing | scheduler | sched | HURVS | — | 3 | ||
| S17 | Sched | POST /scheduler/crm_zoned_restaurants_report | Missing | scheduler | sched | HURVS | — | 3 | ||
| S18 | Sched | POST /scheduler/destroy_expired_external_data | Missing | scheduler | sched | HURVS | — | 2 | ||
| S19 | Sched | POST /scheduler/destroy_expired_token | Missing | scheduler | sched | HURVS | — | 2 | ||
| S20 | Sched | POST /scheduler/push_notification | Controller | scheduler | sched | HURVS | J20 | 1 | ||
| S21 | Sched | POST /scheduler/bot_startwork_getoffwork | Missing | scheduler | sched | HURVS | J01 | 2 | ||
| S22 | Sched | POST /scheduler/fast_track_discord_notify_pending_jobs | Missing | scheduler | sched | HURVS | J11 | 2 | ||
| S23 | Sched | POST /scheduler/fast_track_send_invoice_email | Missing | scheduler | sched | HURVS | J11 | 2 | ||
| S24 | Sched | POST /scheduler/fast_track_send_summary_email | Missing | scheduler | sched | HURVS | J11 | 2 | ||
| S25 | Sched | POST /scheduler/job_hiring_attendances_report | Controller | scheduler | sched | HURVS | — | 2 | ||
| S26 | Sched | POST /scheduler/restaurant_notify_expiring_job | Missing | scheduler | sched | HURVS | — | 2 | ||
| S27 | Sched | POST /scheduler/restaurant_notify_pending_accept_job | Missing | scheduler | sched | HURVS | J01 | 1 | ||
| S28 | Sched | POST /scheduler/restaurant_notify_not_done_job_hirings | Missing | scheduler | sched | HURVS | — | 2 | ||
| S29 | Sched | POST /scheduler/upload_makro_shift_planning | Missing | scheduler | sched | HURVS | — | 3 | ||
| S30 | Sched | POST /scheduler/upload_makro_time_attendance | Missing | scheduler | sched | HURVS | — | 3 | ||
| S31 | Sched | POST /scheduler/broadcast_not_full_job | Missing | scheduler | sched | HURVS | — | 2 | ||
| S32 | Sched | POST /scheduler/claw_student_confirm_response | Controller | scheduler | sched | HURVS | J01 | 1 | ||
| S33 | Sched | POST /scheduler/get_off_work_started_job | Missing | scheduler | sched | HURVS | J01 | 2 | ||
| S34 | Sched | POST /scheduler/send_student_certificate_of_employment | Missing | scheduler | sched | HURVS | — | 2 | ||
| S35 | Sched | POST /scheduler/student_confirm_notify | Controller | scheduler | sched | HURVS | J01 | 1 | ||
| S36 | Sched | POST /scheduler/student_confirm_notify_noti | Missing | scheduler | sched | HURVS | J01 | 1 | ||
| S37 | Sched | POST /scheduler/student_debit | Controller | scheduler | sched | HURVS | J01 | 3 | ||
| S38 | Sched | POST /scheduler/student_debit_v2 | Missing | scheduler | sched | HURVS | J01 | 3 | ||
| S39 | Sched | POST /scheduler/student_debit_v3 | Missing | scheduler | sched | HURVS | J01 | 2 | ||
| S40 | Sched | POST /scheduler/student_debit_v4 | Missing | scheduler | sched | HURVS | J01 | 1 | ||
| S41 | Sched | POST /scheduler/student_job_hiring_leave_missing | Missing | scheduler | sched | HURVS | J15 | 2 | ||
| S42 | Sched | POST /scheduler/student_notify_open_applicants | Controller | scheduler | sched | HURVS | — | 2 |
| Done | ID | Surface | Operation | Today | Role | Clients | Cases | Journey | Task | Tier |
|---|---|---|---|---|---|---|---|---|---|---|
| C01 | Callback | POST /callback/gb_prime_pay_charge | Missing | guest | none | HURVS | J12 | 1 | ||
| C02 | Callback | POST /callback/gb_prime_pay_guest_charge | Missing | guest | none | HURVS | J11 | 1 | ||
| C03 | Callback | POST /callback/gb_prime_pay_checkout_confirmation | Missing | guest | none | HURVS | J12 | 1 | ||
| C04 | Callback | POST /callback/gb_prime_pay_success | Missing | guest | none | HURVS | J12 | 1 | ||
| C05 | Callback | GET /callback/gb_prime_pay_success | Missing | guest | none | HURVS | J12 | 2 | ||
| C06 | Callback | POST /callback/aws_connect_confirm_job_hiring_response | Controller | guest | none | HURVS | J01 | 2 | ||
| C07 | Callback | POST /callback/discord_verify_interaction | Missing | guest | none | HURVS | — | 2 |
Multi-actor flows. Same inventory checkboxes (surface = journey).
| Done | ID | Surface | Journey | Today | Actors | Step sequence | Side effects | Task | Tier |
|---|---|---|---|---|---|---|---|---|---|
| J01 | Journey | Single job happy path | Logic | restaurant,student,sched | createJob → applyJob → acceptAppliedStudent → student_confirm_notify → confirmWork → checkIn → checkOut → approveAttendances → settleJob → student_debit_v4 | wallet,outbox,mail | 1 | ||
| J02 | Journey | Student applied but employer dislikes | Missing | restaurant,student | createJob → applyJob → dislikeAppliedStudent | outbox | 1 | ||
| J03 | Journey | Employer settles early (job full) | Logic | restaurant,student,sched | createJob ×N → apply → accept → settleJob → debit | wallet | 1 | ||
| J04 | Journey | Student cancels after match | Logic | restaurant,student | match → cancelJob (student) → fee / slot release | wallet,outbox | 1 | ||
| J05 | Journey | Restaurant cancels with fee | Logic | restaurant,student | match → cancelJob (restaurant) → cancel fee charged | wallet,outbox | 1 | ||
| J06 | Journey | Attendance auto-approve via cron | Controller | student,sched | checkIn → checkOut → bot_auto_approve_reject_attendances | wallet,outbox | 1 | ||
| J07 | Journey | Attendance reject then resubmit | Logic | restaurant,student | checkIn/Out → rejectAttendances → re-check → approve | outbox | 2 | ||
| J08 | Journey | Period job bulk create + bot auto-hire | Controller | restaurant,student,sched | createJobs → applyPeriodJobs → bot_auto_hiring_period_jobs | outbox | 1 | ||
| J09 | Journey | Period job cancel mid-flight | Logic | restaurant,sched | createJobs → cancelPeriodJob → admin_notify_not_full_period_job | wallet,outbox | 1 | ||
| J10 | Journey | Perfect-match auto-hire path | Controller | restaurant,student,sched | createJobs → apply → bot_auto_hiring_perfect_period_jobs | outbox | 2 | ||
| J11 | Journey | Guest Fast Track job + card charge | Logic | guest,sched | create_guest_job → discounts → charge_credit_card_699 → guest callback → invoice email | mail,discord | 1 | ||
| J12 | Journey | Employer QR top-up | Missing | restaurant,sched | getGbPrimePayQrCode → callback charge → claw_pending → topupStatus complete | wallet,mail | 1 | ||
| J13 | Journey | Employer credit-card top-up | Missing | restaurant | chargeGbPrimePay → checkout confirmation → topupStatus | wallet | 1 | ||
| J14 | Journey | Close job after applicants | Logic | restaurant,student | createJob → apply → closeJob → applicants cancel_full + find-new-job noti | outbox | 2 | ||
| J15 | Journey | Absent / leave / ban edges | Logic | restaurant,student,sched | match → reportAbsent OR createStudentLeave OR banStudent → cron leave-missing | wallet,outbox | 1 | ||
| J16 | Journey | Skill request lifecycle | Logic | student | skills → requestSkill → skillRequests list | outbox | 2 | ||
| J17 | Journey | Training + tutorial + survey | Logic | student,guest | training REST → answerTraining → tutorial → survey submit | outbox | 2 | ||
| J18 | Journey | Campaign ticket redeem | Logic | student | studentsCampaigns → campaignTickets → redeemCampaignTicket | wallet | 2 | ||
| J19 | Journey | Challenge score + reward redeem | Logic | student | challenges → score txns → rewards → redeemReward | wallet | 2 | ||
| J20 | Journey | Push token register / notify / unregister | Controller | any,sched | registerNotificationPushToken → push_notification cron → markRead → unregister | outbox | 1 | ||
| J21 | Journey | Token refresh mid-session | Missing | any | sign_in → expire access → /users/tokens → gql still works | — | 1 | ||
| J22 | Journey | Wrong-role GraphQL rejection | Missing | student,restaurant | student token on createJob; restaurant token on applyJob → extension errors | — | 1 | ||
| J23 | Journey | Unconfirmed first-jobber cancelled | Controller | student,sched | first-jobber hire → bot_cancel_unconfirmed_first_jobber_hirings | outbox | 2 | ||
| J24 | Journey | IVR confirm response | Controller | student,sched | student_confirm_notify → aws_connect callback → claw_student_confirm_response | outbox | 2 | ||
| J25 | Journey | Bid price adjustment after post | Missing | restaurant | createJob → updateJobRestaurantBidPrice → jobPricing reflects | — | 2 | ||
| J26 | Journey | Restaurant onboarding | Missing | restaurant | register → acceptPdpa → upsertContact → createRestaurant | — | 1 | ||
| J27 | Journey | Student onboarding + PDPA | Logic | student | register → training → acceptPdpa → editStudent | sms | 1 | ||
| J28 | Journey | OTP phone change | Missing | any | createOtpToken → changeUsername | sms | 2 | ||
| J29 | Journey | Export hirings Excel | Logic | restaurant | settle → exportJobHirings → xlsx attachment | — | 3 | ||
| J30 | Journey | Idempotent createJob | Missing | restaurant | createJob twice with same x-idempotency-key → one job | — | 1 |
| Risk | Mitigation |
|---|---|
| PostGIS template clone flaky on CI | Retry once; document E2E_REUSE_DB for local; pin image digest |
| Singleton clients leak across examples | Reset/fake in before(:suite); never connect Bunny in test |
| Contract template drift from real clients | Vendor documents + HimeSchema.validate gate |
| Coverage % gamed by shallow specs | Journeys required for Tier-1 domains; side-effect cases on money/lifecycle |
| parallel_tests / testcontainers on Ruby 2.7 | Pin parallel_tests 5.3.0; testcontainers ≥2.6 OK |
| Holiday/pricing clock surprises | E2E baseline on known non-holiday weekday; freeze per example |