Skip to content
Draft
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
14 changes: 8 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@
- **REST** under `app/controllers/api/**` with Jbuilder views in `app/views/api/**`; **GraphQL** at `/graphql` (schema in `app/graphql/**`).
- **Auth**: Browser/session via OmniAuth (OIDC to Hydra); API token via `Authorization: Bearer` with `Identifiable#identify_user` → `User.from_token` → `HydraPublicApiClient`.
- **Authorization**: cancancan in `app/models/ability.rb`. Use `load_and_authorize_resource` in controllers; GraphQL uses `Types::ProjectType.authorized?` and `current_ability` in context.
- **Domain**: `Project` (+ `Component`) with Active Storage attachments. Domain operations in `lib/concepts/**` (e.g. `Project::Create`, `Project::CreateRemix`). Prefer calling these from controllers/mutations.
- **Domain**: `Project` (+ `Component`) with Active Storage attachments. Controllers and mutations must use an existing domain operation from `lib/concepts/**` (e.g. `Project::Create`, `Project::CreateRemix`). Add a new operation when no suitable one exists; keep logic in the transport layer only when it is transport-specific.
- **Jobs**: GoodJob (`bundle exec good_job start --max-threads=8`). Admin UI at `/admin/good_job`.
- **Integrations**: Profile API (`lib/profile_api_client.rb`), UserInfo API, GitHub GraphQL (`lib/github_api.rb`), GitHub webhooks via `GithubWebhooksController`.
- **Storage/CORS**: Active Storage uses S3 in non-dev. CORS via `config/initializers/cors.rb` and `lib/origin_parser.rb`. `CorpMiddleware` sets CORP for Active Storage routes.

## Sources of Truth
- `.rubocop.yml` is authoritative for machine-checkable Ruby style; do not restate individual cop rules here.

## Key Conventions
- GraphQL context: `current_user`, `current_ability`, `remix_origin`. Object IDs use GlobalID. Locale fallback via `ProjectLoader`: `[requested, 'en', nil]`.
- REST pagination returns HTTP `Link` header (see `Api::ProjectsController#pagination_link_header`).
- Project rules: identifiers unique per locale; default component name/extension immutable on update; students cannot update `instructions` on school projects; creating a project in a school auto-builds `SchoolProject`.
- Remix: `Project::CreateRemix` clones media/components, sets `remix_origin`, clears `lesson_id`.
- Errors: domain ops return `OperationResponse` with `:error`; controllers return 4xx heads; GraphQL raises `GraphQL::ExecutionError`. Exceptions reported to Sentry.
- snake_case for variable numbers (exceptions: `sha256`, `X-Hub-Signature-256`).

## Quickstart
```bash
Expand All @@ -31,10 +33,10 @@ docker compose up
- Use `docker compose` for all commands; project mounts into `editor-api:builder` with tmpfs for `tmp/`.

## Testing
- Full suite: `docker compose run --rm api rspec`
- Single spec: `docker compose run --rm api rspec spec/path/to/spec.rb`
- Lint: `docker compose run --rm api bundle exec rubocop`
- CI: GitHub Actions with Ruby 4, Postgres 12, Redis.
- After changing behavior, run the closest relevant spec: `docker compose run --rm api rspec spec/path/to/spec.rb`
- After changing Ruby, run RuboCop: `docker compose run --rm api bundle exec rubocop`
- After changing shared infrastructure, the database or schema, authorization, or other cross-cutting behavior, run the full suite: `docker compose run --rm api rspec`
- CI runs in GitHub Actions; treat `.github/workflows/ci.yml` and `.tool-versions` as authoritative for jobs and runtime versions.
- Salesforce sync specs need `SALESFORCE_CONNECT_DB` set and matching Heroku Connect tables (schema comes from the published `heroku-connect` image after Salesforce mapping is exported).

## Salesforce / Heroku Connect
Expand Down
Loading