|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +codebar planner is a Rails 7.2 application for managing [codebar.io](https://codebar.io) members and events. It handles workshop/event scheduling, member registration, invitations, RSVPs, and feedback collection for coding workshops organized by codebar chapters. |
| 8 | + |
| 9 | +## Development Setup |
| 10 | + |
| 11 | +### Docker (Recommended) |
| 12 | + |
| 13 | +- **Initial setup**: `bin/dup` - builds container, sets up database with seed data |
| 14 | +- **Start container**: `bin/dstart` - starts existing container |
| 15 | +- **Start Rails server**: `bin/dserver` - runs server on http://localhost:3000 |
| 16 | +- **Run tests**: `bin/drspec [path]` - runs RSpec tests, optionally for specific file/line |
| 17 | +- **Rails console**: `bin/drails console` |
| 18 | +- **Run rake tasks**: `bin/drake [task]` |
| 19 | +- **Bash shell in container**: `bin/dexec` |
| 20 | +- **Grant admin access**: `bin/dadmin <email>` - gives admin role to user |
| 21 | +- **Stop container**: `bin/dstop` |
| 22 | +- **Destroy container**: `bin/ddown` |
| 23 | + |
| 24 | +### Native Installation |
| 25 | + |
| 26 | +If not using Docker: |
| 27 | +- Setup: `bundle && rake db:create db:migrate db:seed` |
| 28 | +- Server: `rails server` |
| 29 | +- Tests: `rake` or `rspec` |
| 30 | +- Linting: `rubocop` |
| 31 | + |
| 32 | +### Environment Variables |
| 33 | + |
| 34 | +Required in `.env` file: |
| 35 | +``` |
| 36 | +GITHUB_KEY=<your_github_oauth_client_id> |
| 37 | +GITHUB_SECRET=<your_github_oauth_client_secret> |
| 38 | +``` |
| 39 | + |
| 40 | +Create GitHub OAuth app at https://github.com/settings/applications/new with callback URL `http://localhost:3000/auth/github`. |
| 41 | + |
| 42 | +## Development Workflow |
| 43 | + |
| 44 | +**IMPORTANT**: All changes to this project must be made via pull requests. Never commit directly to the `master` branch. |
| 45 | + |
| 46 | +1. Create a feature branch from `master` |
| 47 | +2. Make your changes and commit them to the feature branch |
| 48 | +3. Push the branch and create a pull request |
| 49 | +4. Wait for review and approval before merging |
| 50 | + |
| 51 | +## Architecture & Domain Model |
| 52 | + |
| 53 | +### Core Domain Concepts |
| 54 | + |
| 55 | +**Members**: Users of the system. Can be students, coaches, both, or neither. Authenticated via GitHub OAuth (stored in `auth_services` table). Members have roles managed by Rolify (`admin`, `organiser` for chapters/workshops). |
| 56 | + |
| 57 | +**Chapters**: Local codebar organizations (e.g., "London", "Berlin"). Chapters have organisers and host workshops/events. |
| 58 | + |
| 59 | +**Workshops**: Regular coding workshops. Belong to one chapter. Send invitations to chapter subscribers. Attendance is first-come-first-served up to venue capacity, with automatic waiting list management. |
| 60 | + |
| 61 | +**Events**: Multi-chapter events. Attendance requires admin verification/approval after RSVP. |
| 62 | + |
| 63 | +**Sponsors**: Organizations providing venue space. Have addresses and member contacts. One sponsor acts as "host" (venue) for each workshop. |
| 64 | + |
| 65 | +**Invitations**: Track member attendance status for workshops/events. Different classes: |
| 66 | +- `WorkshopInvitation` - for workshops (auto-accepted up to capacity) |
| 67 | +- `Invitation` - for events (require admin verification) |
| 68 | + |
| 69 | +**Waiting Lists**: When workshops are full, members can join waiting list (`WaitingList` model with `auto_rsvp` flag). Automatically promoted when spaces become available. |
| 70 | + |
| 71 | +### Key Model Relationships |
| 72 | + |
| 73 | +``` |
| 74 | +Chapter |
| 75 | + has_many :workshops |
| 76 | + has_many :groups (for subscriptions) |
| 77 | + has_many :organisers (via permissions) |
| 78 | +
|
| 79 | +Workshop |
| 80 | + belongs_to :chapter |
| 81 | + has_many :workshop_sponsors |
| 82 | + has_many :invitations (WorkshopInvitation) |
| 83 | + has_one :host (sponsor where workshop_sponsors.host = true) |
| 84 | +
|
| 85 | +Member |
| 86 | + has_many :workshop_invitations |
| 87 | + has_many :invitations (for events) |
| 88 | + has_many :subscriptions |
| 89 | + has_many :groups, through: :subscriptions |
| 90 | + has_many :chapters, through: :groups |
| 91 | + has_many :auth_services |
| 92 | +
|
| 93 | +Sponsor |
| 94 | + has_one :address |
| 95 | + has_many :workshop_sponsors |
| 96 | + has_many member_contacts |
| 97 | +``` |
| 98 | + |
| 99 | +See `app/models/README.md` for detailed data model documentation. |
| 100 | + |
| 101 | +## Authorization & Authentication |
| 102 | + |
| 103 | +- **Authentication**: GitHub OAuth via OmniAuth. Session stores `member_id`. |
| 104 | +- **Authorization**: Pundit policies in `app/policies/`. Key roles: |
| 105 | + - `admin` - global admin access |
| 106 | + - `organiser` - per-chapter or per-workshop organiser role |
| 107 | +- Access checks: `current_user.is_admin?`, `current_user.manager?` (admin or organiser) |
| 108 | +- Policies must be called in controllers. `ApplicationController` rescues `Pundit::NotAuthorizedError`. |
| 109 | + |
| 110 | +## Frontend Stack |
| 111 | + |
| 112 | +- **CSS Framework**: Bootstrap 5 |
| 113 | +- **JavaScript**: Stimulus controllers, Turbo for page transitions |
| 114 | +- **View Engine**: HAML (not ERB) |
| 115 | +- **Asset Pipeline**: Sprockets with importmap-rails |
| 116 | +- **Icons**: Font Awesome 5 |
| 117 | + |
| 118 | +## Background Jobs |
| 119 | + |
| 120 | +- **Queue**: Delayed Job (database-backed) |
| 121 | +- Jobs defined in `app/jobs/` (inheriting from `ApplicationJob`) |
| 122 | +- Worker process: `bin/delayed_job start` (native) or managed by Docker |
| 123 | + |
| 124 | +## Testing |
| 125 | + |
| 126 | +- **Framework**: RSpec with Capybara for feature tests |
| 127 | +- **JavaScript Driver**: Playwright (Chromium by default) |
| 128 | +- **Factories**: Fabrication (not FactoryBot) |
| 129 | +- **Test data**: Faker for generated data |
| 130 | +- **Coverage**: SimpleCov |
| 131 | +- **JavaScript tests**: Capybara with Playwright driver |
| 132 | + - Use `PLAYWRIGHT_HEADLESS=false` to debug with visible browser |
| 133 | + - Use `PWDEBUG=1` for Playwright Inspector (step-through debugging) |
| 134 | + - Use `PLAYWRIGHT_BROWSER=firefox` or `webkit` for cross-browser testing |
| 135 | +- **Matchers**: Shoulda Matchers, RSpec Collection Matchers |
| 136 | + |
| 137 | +Run single test: `bin/drspec spec/path/to/file_spec.rb:42` |
| 138 | + |
| 139 | +## Code Style |
| 140 | + |
| 141 | +- **Linter**: RuboCop with custom config (`.rubocop.yml`) |
| 142 | +- **Max line length**: 120 characters |
| 143 | +- **Max method length**: 10 lines (excludes tests) |
| 144 | +- **Hash syntax**: Modern style `{ key: value }` not `{ :key => value }` |
| 145 | +- **HAML linting**: `haml_lint` (config in `.haml-lint.yml`) |
| 146 | +- Run linter: `rubocop` or `bin/drubocop` (Docker) |
| 147 | + |
| 148 | +Key RuboCop exclusions: |
| 149 | +- `db/`, `spec/`, `config/`, `bin/` excluded from most cops |
| 150 | +- Documentation not required (`Style/Documentation: false`) |
| 151 | + |
| 152 | +## Important Patterns |
| 153 | + |
| 154 | +### Controllers |
| 155 | + |
| 156 | +- Use Pundit `authorize` to check permissions |
| 157 | +- Admin controllers in `app/controllers/admin/` namespace |
| 158 | +- Super admin controllers in `app/controllers/super_admin/` |
| 159 | +- Use `authenticate_admin!` or `authenticate_admin_or_organiser!` before_action for protected routes |
| 160 | + |
| 161 | +### Models |
| 162 | + |
| 163 | +- Concerns in `app/models/concerns/` (e.g., `Invitable`, `Listable`, `DateTimeConcerns`) |
| 164 | +- Permissions via Rolify: `member.add_role(:organiser, workshop)` |
| 165 | +- Scopes commonly used for filtering (e.g., `Member.not_banned`, `Workshop.students`) |
| 166 | + |
| 167 | +### Views |
| 168 | + |
| 169 | +- Use Presenters (`app/presenters/`) for complex view logic |
| 170 | +- Form objects in `app/form_models/` for complex forms |
| 171 | +- Helpers in `app/helpers/` |
| 172 | + |
| 173 | +### Services |
| 174 | + |
| 175 | +- Service objects in `app/services/` for complex business logic |
| 176 | +- Example: invitation management, email sending logic |
| 177 | + |
| 178 | +## Routes |
| 179 | + |
| 180 | +- Root: `dashboard#show` |
| 181 | +- Admin namespace: `/admin/*` - requires admin/organiser access |
| 182 | +- Auth: `/auth/github` (login), `/logout` (logout) |
| 183 | +- Key resources: `/workshops/:id`, `/events/:id`, `/meetings/:id` |
| 184 | +- Chapter pages: `/:id` (catch-all at end of routes) |
| 185 | + |
| 186 | +## Database |
| 187 | + |
| 188 | +- **RDBMS**: PostgreSQL |
| 189 | +- **Migrations**: Standard Rails migrations in `db/migrate/` |
| 190 | +- **Seeds**: `db/seeds.rb` creates sample data for development |
| 191 | + |
| 192 | +## Deployment |
| 193 | + |
| 194 | +This app uses Heroku. See `Makefile` for deployment commands (requires appropriate Heroku access): |
| 195 | +- `make deploy_production` |
| 196 | +- `make deploy_staging` |
| 197 | + |
| 198 | +## Additional Tools |
| 199 | + |
| 200 | +- **Email preview**: Letter Opener (development) - emails open in browser |
| 201 | +- **Error tracking**: Rollbar (production) |
| 202 | +- **Performance monitoring**: Scout APM |
| 203 | +- **Activity tracking**: PublicActivity gem for user action history |
| 204 | +- **Pagination**: Pagy |
| 205 | +- **File uploads**: CarrierWave (AWS S3 in production) |
| 206 | +- **Friendly URLs**: FriendlyId for slug generation |
0 commit comments