|
1 | 1 | # Project Overview |
2 | | -- Rails 7.1 monolith for the Raspberry Pi Code Editor API (REST + GraphQL), served at |
3 | | - `editor-api.raspberrypi.org`. Provides auth, project storage, and education features. |
4 | | -- Primary runtime via Docker; API listens on port 3009 in containers. |
5 | | - |
6 | | -## Repository Structure |
7 | | -- `app/` Rails application code (REST, GraphQL, jobs, views, admin). |
8 | | -- `config/` environment, initializers, Puma, CORS, credentials. |
9 | | -- `db/` migrations, seeds, schema helpers; `bin/db-sync/` for pulling Heroku data locally. |
10 | | -- `spec/` RSpec tests (Rails, GraphQL, feature/system). |
11 | | -- `bin/` developer scripts (`with-builder.sh`, `db-sync/*`, Rails binstubs). |
12 | | -- `lib/` supporting libraries, tasks, assets; `public/` static assets; `docker-compose.yml` |
13 | | - for local stack; `.circleci/` for CI; `.rubocop.yml` for style config. |
14 | | - |
15 | | -## Quickstart Commands |
| 2 | +- Rails 7.1 monolith for the Raspberry Pi Code Editor API (REST + GraphQL), served at `editor-api.raspberrypi.org`. |
| 3 | +- Primary runtime via Docker; API listens on port 3009. |
| 4 | + |
| 5 | +## Architecture |
| 6 | +- **REST** under `app/controllers/api/**` with Jbuilder views in `app/views/api/**`; **GraphQL** at `/graphql` (schema in `app/graphql/**`). |
| 7 | +- **Auth**: Browser/session via OmniAuth (OIDC to Hydra); API token via `Authorization: Bearer` with `Identifiable#identify_user` → `User.from_token` → `HydraPublicApiClient`. |
| 8 | +- **Authorization**: cancancan in `app/models/ability.rb`. Use `load_and_authorize_resource` in controllers; GraphQL uses `Types::ProjectType.authorized?` and `current_ability` in context. |
| 9 | +- **Domain**: `Project` (+ `Component`) with Active Storage attachments. Domain operations in `lib/concepts/**` (e.g. `Project::Create`, `Project::CreateRemix`). Prefer calling these from controllers/mutations. |
| 10 | +- **Jobs**: GoodJob (`bundle exec good_job start --max-threads=8`). Admin UI at `/admin/good_job`. |
| 11 | +- **Integrations**: Profile API (`lib/profile_api_client.rb`), UserInfo API, GitHub GraphQL (`lib/github_api.rb`), GitHub webhooks via `GithubWebhooksController`. |
| 12 | +- **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. |
| 13 | + |
| 14 | +## Key Conventions |
| 15 | +- GraphQL context: `current_user`, `current_ability`, `remix_origin`. Object IDs use GlobalID. Locale fallback via `ProjectLoader`: `[requested, 'en', nil]`. |
| 16 | +- REST pagination returns HTTP `Link` header (see `Api::ProjectsController#pagination_link_header`). |
| 17 | +- 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`. |
| 18 | +- Remix: `Project::CreateRemix` clones media/components, sets `remix_origin`, clears `lesson_id`. |
| 19 | +- Errors: domain ops return `OperationResponse` with `:error`; controllers return 4xx heads; GraphQL raises `GraphQL::ExecutionError`. Exceptions reported to Sentry. |
| 20 | +- snake_case for variable numbers (exceptions: `sha256`, `X-Hub-Signature-256`). |
| 21 | + |
| 22 | +## Quickstart |
16 | 23 | ```bash |
17 | 24 | cp .env.example .env |
18 | | -docker-compose build |
| 25 | +docker compose build |
19 | 26 | docker compose run --rm api rails db:setup |
20 | | -docker-compose up |
21 | | -# API available on http://localhost:3009 |
| 27 | +docker compose up |
22 | 28 | ``` |
23 | 29 |
|
24 | | -## Development Workflow |
25 | | -- Prefer Docker compose; mounts project into `editor-api:builder` image with tmpfs for `tmp/`. |
26 | | -- Use `./bin/with-builder.sh <cmd>` for operations that modify Gemfile.lock (e.g. `bundle update`). |
27 | | -- Seeds (dev): `docker compose run --rm api rails projects:create_all` and |
28 | | - `docker compose run --rm api rails for_education:seed_a_school_with_lessons_and_students` |
29 | | - (others in README). |
30 | | -- DB sync (needs Heroku access): `./bin/db-sync/production-to-local.sh` or `staging-to-local.sh`. |
31 | | -- Background jobs use GoodJob; Procfile defines `worker: bundle exec good_job start --max-threads=8`. |
32 | | - |
33 | | -## Testing & CI |
34 | | -- Full suite: `docker-compose run api rspec` |
35 | | -- Single spec: `docker-compose run api rspec spec/path/to/spec.rb` |
36 | | -- CI (CircleCI): Ruby 3.2 images with Postgres 12 + Redis; steps include `bin/rails db:setup --trace`, |
37 | | - `ruby/rspec-test`, RuboCop via `ruby/rubocop-check`, coverage artifacts uploaded and posted via |
38 | | - `.circleci/record_coverage`. |
39 | | - |
40 | | -## Code Style & Conventions |
41 | | -- Ruby 3.2.3 (specified as `~> 3.2.0` in Gemfile). |
42 | | -- RuboCop uses Raspberry Pi Foundation shared configs plus Rails/RSpec/GraphQL cops; many metrics and |
43 | | - line-length checks are relaxed. |
44 | | -- Variable numbers must be snake_case (allowed: `sha256`, `X-Hub-Signature-256`). |
45 | | -- Tests in RSpec (`spec/`), Jbuilder for JSON views, GraphQL types under `app/graphql/`. |
46 | | -- GoodJob for background processing; Puma configured via `config/puma.rb`; release hook runs migrations |
47 | | - then `rake projects:create_experience_cs_examples` (see Procfile). |
| 30 | +## Development |
| 31 | +- Use `docker compose` for all commands; project mounts into `editor-api:builder` with tmpfs for `tmp/`. |
| 32 | +- Seeds: `docker compose run --rm api rails projects:create_all` (see README for others). |
| 33 | +- DB sync (needs Heroku CLI): `./bin/db-sync/production-to-local.sh` or `staging-to-local.sh`. |
48 | 34 |
|
49 | | -## Security & Safety Guardrails |
50 | | -- Never commit secrets: `.env`, `config/master.key`, AWS/Postmark tokens, Hydra/Profile secrets, |
51 | | - webhook secrets. Keep `.env.example` values as references only. |
52 | | -- DB sync scripts fetch production/staging data; run only if authorized and handle dumps securely. |
53 | | -- Generated/ignored paths: `log/`, `tmp/`, `storage/`, `coverage/`, `public/assets/`, `.bundle/`, |
54 | | - `docker-compose.override.yml` (gitignored); do not add noise from these. |
55 | | -- Webhooks and smee tunnel secrets live in env vars; avoid logging or sharing real values. |
| 35 | +## Testing |
| 36 | +- Full suite: `docker compose run --rm api rspec` |
| 37 | +- Single spec: `docker compose run --rm api rspec spec/path/to/spec.rb` |
| 38 | +- Lint: `docker compose run --rm api bundle exec rubocop` |
| 39 | +- CI: CircleCI with Ruby 3.2, Postgres 12, Redis. |
56 | 40 |
|
57 | | -## Common Tasks (add feature, add test, refactor, release/deploy if applicable) |
58 | | -- Run app locally: ensure `.env`, then `docker-compose up` (build + `rails db:setup` first). |
59 | | -- Lint: `docker-compose run --rm api bundle exec rubocop` (mirrors CI RuboCop check). |
60 | | -- Migrate: `docker compose run --rm api rails db:migrate` (release hook also migrates). |
61 | | -- Update gems: `./bin/with-builder.sh bundle update` (keeps builder image and lockfiles in sync). |
62 | | -- Seed dev data: commands in README (e.g. `rails projects:create_all`, |
63 | | - `rails for_education:seed_a_school_with_lessons_and_students`). |
64 | | -- Sync DB from Heroku: `./bin/db-sync/production-to-local.sh` or `staging-to-local.sh` (requires Heroku |
65 | | - CLI + app access). |
66 | | -- Release/deploy: Procfile release runs migrations then `rake projects:create_experience_cs_examples`; |
67 | | - confirm platform/trigger before running manually. > TODO: document official deploy pipeline and branch |
68 | | - triggers. |
| 41 | +## Where to Look First |
| 42 | +- Routes: `config/routes.rb`. Auth: `config/initializers/omniauth.rb`, `app/helpers/authentication_helper.rb`, `app/controllers/concerns/identifiable.rb`. |
| 43 | +- Permissions: `app/models/ability.rb`. Domain ops: `lib/concepts/**`. Models: `app/models/**`. GraphQL: `app/graphql/**`. |
69 | 44 |
|
70 | | -## Further Reading (relative links) |
71 | | -- `README.md` |
72 | | -- `.circleci/config.yml` |
73 | | -- `.rubocop.yml` |
74 | | -- `.env.example` |
75 | | -- `Procfile` |
76 | | -- `bin/db-sync/load-local-db.sh` |
| 45 | +## Security |
| 46 | +- Never commit secrets (`.env`, `config/master.key`, API tokens, webhook secrets). |
| 47 | +- `.env.example` contains placeholder values only. |
0 commit comments