Skip to content

Commit 27a8d2d

Browse files
authored
Merge pull request #4718 from crazyserver/MOBILE-5004
Mobile 5004
2 parents 2dd6b16 + 9542f0d commit 27a8d2d

File tree

4 files changed

+410
-0
lines changed

4 files changed

+410
-0
lines changed

.github/copilot-instructions.md

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# Moodle Mobile App - AI Agent Guidelines
2+
3+
## Project Overview
4+
This is the official Moodle Mobile App - an Ionic/Angular hybrid application that runs on Android and iOS via Cordova. The app provides offline-first access to Moodle LMS functionality.
5+
6+
## Architecture Patterns
7+
8+
### Singleton Services via `makeSingleton`
9+
Services are NOT Angular-managed singletons. Use the `makeSingleton` pattern:
10+
```typescript
11+
@Injectable({ providedIn: 'root' })
12+
export class MyService { }
13+
export const My = makeSingleton(MyService);
14+
```
15+
Import from `@singletons` for platform APIs, only import directly from `@angular/core` or Ionic when necessary.
16+
17+
### Delegate Pattern for Extensibility
18+
The codebase uses delegates extensively to allow addons to register handlers:
19+
- **CoreDelegate** base class in `src/core/classes/delegate.ts`
20+
- Handlers register in module providers using `provideAppInitializer`:
21+
```typescript
22+
@NgModule({
23+
providers: [
24+
provideAppInitializer(() => {
25+
CoreCourseModuleDelegate.registerHandler(AddonModPageModuleHandler.instance);
26+
}),
27+
],
28+
})
29+
```
30+
- Delegate examples: `CoreCourseModuleDelegate`, `CoreContentLinksDelegate`, `CoreCourseModulePrefetchDelegate`, `CoreMainMenuDelegate`
31+
32+
### Path Aliases (TypeScript)
33+
Use barrel exports for cleaner imports:
34+
- `@/` - Project root
35+
- `@singletons` / `@singletons/*` - Core singletons
36+
- `@services/*` - Core services
37+
- `@features/*` - Core features
38+
- `@components/*`, `@directives/*`, `@pipes/*` - UI elements
39+
- `@addons/*` - Addon modules
40+
- `@classes/*` - Shared classes
41+
42+
### Lazy Loading with Dynamic Routes
43+
Routes use Angular's `ROUTES` injection token with factory functions:
44+
```typescript
45+
@NgModule({
46+
providers: [
47+
{ provide: ROUTES, multi: true, useFactory: buildRoutes, deps: [Injector] },
48+
],
49+
})
50+
export default class MyLazyModule {}
51+
```
52+
Main routing modules:
53+
- `CoreMainMenuRoutingModule` - Top-level tabs (calendar, messages, etc.)
54+
- `CoreMainMenuTabRoutingModule` - Child routes within tabs
55+
- `CoreCourseContentsRoutingModule` - Module used to register routes in the course contents page. These are routes that will only be used on single activity courses where the activity uses split-view navigation in tablets, such as forum or glossary.
56+
- `CoreCourseIndexRoutingModule` - Course tab pages
57+
- `CoreMainMenuHomeRoutingModule` - Home page tabs
58+
- `CoreSitePreferencesRoutingModule` - Site preferences pages
59+
- Use `buildTabMainRoutes()` helper for consistent tab navigation
60+
61+
### Cache Data Layer
62+
**SQLite Database**: Site-specific tables via `CORE_SITE_SCHEMAS` token:
63+
```typescript
64+
providers: [
65+
{ provide: CORE_SITE_SCHEMAS, useValue: [MY_SCHEMA], multi: true }
66+
]
67+
```
68+
69+
**File Management**:
70+
- `CoreFilepool` - Downloads/caches files with queue management
71+
- `CoreCourseModulePrefetchDelegate` - Handles module prefetching for offline
72+
- `CoreCourseHelper` - Manages course and section downloads for offline access
73+
- `CoreFileProvider` - Manages file operations (read, write, delete) across device storage
74+
- Files stored in filepool with metadata tracking (stale detection, external file flags)
75+
76+
**Sync Pattern**:
77+
- Offline actions stored in local DB tables
78+
- Sync services (extend `CoreSyncBaseProvider`) process on connection
79+
- Use `CoreSyncCronHandler` for background sync
80+
81+
## Development Workflows
82+
83+
### Build & Serve
84+
```bash
85+
npm start # Dev server with SSL at localhost:8100
86+
npm run build # Development build
87+
npm run build:prod # Production build
88+
npm run build:test # Testing build with NODE_ENV=testing
89+
```
90+
Before serving, Gulp tasks auto-run: `lang`, `env`, `icons`, optionally `behat`
91+
92+
### Testing
93+
**Unit Tests (Jest)**:
94+
```bash
95+
npm test # Run all tests
96+
npm run test:watch # Watch mode
97+
npm run test:coverage # With coverage
98+
```
99+
Test files: `**/*.test.ts` with setup in `src/testing/setup.ts`
100+
101+
**E2E Tests (Behat)**:
102+
- Feature files in `src/**/tests/behat/*.feature`
103+
- PHP-based Behat communicates with app via `window.behat` API
104+
- Build plugin: `gulp behat` (requires `MOODLE_APP_BEHAT_PLUGIN_PATH` or `MOODLE_DOCKER_WWWROOT`)
105+
- Behat runtime in `src/testing/services/behat-runtime.ts`
106+
107+
### Mobile Development
108+
```bash
109+
npm run dev:android # Run on Android with livereload
110+
npm run dev:ios # Run on iOS
111+
npm run prod:android # Production Android build
112+
npm run prod:ios # Production iOS build
113+
```
114+
Custom Cordova plugin in `cordova-plugin-moodleapp/` with TypeScript source compiled to `www/index.js`
115+
116+
### Language Files
117+
Distributed lang files compiled into `src/assets/lang/{lang}.json`:
118+
```bash
119+
npm run lang:update-langpacks # Pull from Moodle language packs
120+
npm run lang:create-langindex # Generate language index
121+
```
122+
Watch for changes: `gulp watch`
123+
124+
## Project-Specific Conventions
125+
126+
### Module Structure
127+
- Core modules: `src/core/features/{feature}/`
128+
- Addon modules: `src/addons/{type}/{name}/`
129+
- Each feature has `{name}.module.ts` (eager) and `{name}-lazy.module.ts` (lazy-loaded routes) when needed
130+
- Avoid creating separate `-lazy.module.ts` files; instead use `loadComponent` with dynamic imports for lazy loading
131+
- Services in `services/`, components in `components/`, pages in `pages/`
132+
133+
### Handler Pattern
134+
Handlers are singletons with `.instance` property added by `makeSingleton`:
135+
```typescript
136+
@Injectable({ providedIn: 'root' })
137+
export class MyHandler extends CoreContentLinksHandler {
138+
name = 'AddonMyHandler';
139+
// ...implementation
140+
}
141+
export const MyHandler = makeSingleton(MyHandler);
142+
```
143+
144+
### Shared Module Usage
145+
Components import `CoreSharedModule` which re-exports:
146+
- `CoreBaseModule` (CommonModule, FormsModule, IonicModule, TranslateModule)
147+
- `CoreComponentsModule`, `CoreDirectivesModule`, `CorePipesModule`
148+
149+
### Database Schema Versioning
150+
Define tables with columns, indexes in site schemas. Version increments trigger migrations.
151+
152+
### Environment Configuration
153+
`moodle.config.json` (gitignored) extends `moodle.config.example.json`. Access via `CoreConstants.CONFIG` service. Test config overrides via `TestingBehatRuntime.init()`.
154+
155+
## Common Pitfalls
156+
157+
1. Always use singletons via `@singletons` instead of injecting Angular services directly
158+
2. Use standalone components for new modules instead of `@NgModule({ declarations: [] })`
159+
3. Always register handlers in `provideAppInitializer`
160+
4. Import only from barrel files that are configured in `tsconfig.json` paths
161+
5. **Do** run `gulp` before testing to ensure lang files are built
162+
6. **Do** use `CoreSitesReadingStrategy` when fetching data to control cache vs network behavior
163+
164+
165+
## Code reviews
166+
- When performing a code review, check that the language is in British English.
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
---
2+
description: 'Angular and Ionic 8 coding standards for Moodle Mobile App'
3+
applyTo: '**/*.{ts,html,scss} && !**/*.test.ts'
4+
---
5+
6+
# Angular & Ionic 8 Development Instructions
7+
8+
Instructions for generating high-quality Angular applications with TypeScript, using Angular Signals for state management, adhering to Angular best practices as outlined at https://angular.dev.
9+
10+
## Project Context
11+
- Angular version (version defined in package.json)
12+
- TypeScript for type safety
13+
- Angular CLI for project setup and scaffolding
14+
- Follow Angular Style Guide (https://angular.dev/style-guide)
15+
- Use Ionic framework for mobile-optimised UI components (version defined in package.json)
16+
- Use Cordova for native device features
17+
- Check .browserslistrc for supported browsers and platforms
18+
19+
## Development Standards
20+
21+
### Architecture
22+
- Use standalone components unless modules are explicitly required
23+
- Organise code by standalone feature modules or domains for scalability
24+
- Implement lazy loading for feature modules to optimise performance
25+
- Use Angular's built-in dependency injection system effectively
26+
- Structure components with a clear separation of concerns (smart vs. presentational components)
27+
28+
### TypeScript
29+
- Using recommended rules in `eslint.config.mjs` for type safety
30+
- Define clear interfaces and types for components, services, and models
31+
- Use type guards and union types for robust type checking
32+
- Use typed forms (e.g., `FormGroup`, `FormControl`) for reactive forms
33+
34+
### Component Design
35+
- Follow Angular's component lifecycle hooks best practices
36+
- Use `input()` `output()`, `viewChild()`, `viewChildren()`, `contentChild()` and `contentChildren()` functions instead of decorators
37+
- Leverage Angular's change detection strategy (default or `OnPush` for performance)
38+
- Keep templates clean and logic in component classes or services
39+
- Use Angular directives and pipes for reusable functionality
40+
- Use new control flow directives like `@if`, `@for`, `@switch` for cleaner templates
41+
42+
### Styling
43+
- Use Angular's component-level CSS encapsulation (default: ViewEncapsulation.Emulated)
44+
- Prefer SCSS for styling with consistent theming
45+
- Implement responsive design using CSS Grid, Flexbox, or Ionic Layout utilities
46+
- Maintain accessibility (a11y) with ARIA attributes and semantic HTML
47+
48+
### State Management
49+
- Use Angular Signals for reactive state management in components and services
50+
- Leverage `signal()`, `computed()`, and `effect()` for reactive state updates
51+
- Use only stable features of Angular Signals and exclude experimental features such as `resource()`
52+
- Use writable signals for mutable state and computed signals for derived state
53+
- Handle loading and error states with signals and proper UI feedback
54+
- Use Angular's `AsyncPipe` to handle observables in templates when combining signals with RxJS
55+
- Use Signals for local state rather than RxJS Subjects where possible.
56+
57+
### Data Fetching
58+
- Use the `CoreWS` service for API calls (which handles both web and Cordova environments)
59+
- Implement RxJS operators for data transformation and error handling
60+
- Use Angular's `inject()` function for dependency injection in standalone components and feature modules only; for services, use the `makeSingleton` pattern via `@singletons` (see Moodle Mobile App - AI Agent Guidelines)
61+
- Implement caching strategies
62+
63+
### Security
64+
- Sanitise user inputs using Angular's built-in sanitisation
65+
- Implement route guards for authentication and authorisation
66+
- Validate form inputs with Angular's reactive forms and custom validators
67+
- Follow Angular's security best practices by using Angular APIs instead of direct DOM manipulation
68+
69+
### Performance
70+
- Enable production builds with `npm run build:prod` for optimisation
71+
- Use lazy loading for routes to reduce initial bundle size
72+
- Use trackBy in `@for` loops to improve rendering performance
73+
74+
### Testing
75+
- Write unit tests for components, services, and pipes using Jest as the test runner
76+
- Use Angular's `TestBed` for component testing with mocked dependencies
77+
- Test signal-based state updates using Angular's testing utilities
78+
- Ensure high test coverage for critical functionality
79+
80+
## Implementation Process
81+
1. Plan project structure and feature modules
82+
2. Define TypeScript interfaces and models
83+
3. Scaffold components, services, and pipes using Angular CLI
84+
4. Implement data services and API integrations with signal-based state
85+
5. Build reusable components with clear inputs and outputs
86+
6. Add reactive forms and validation
87+
7. Apply styling with SCSS and responsive design
88+
8. Implement lazy-loaded routes and guards
89+
9. Add error handling and loading states using signals
90+
10. Write unit and end-to-end tests
91+
11. Optimise performance and bundle size
92+
93+
## Additional Guidelines
94+
- Follow the Moodle App Style Guide for file naming conventions (see https://moodledev.io/general/development/policies/codingstyle-moodleapp). Also check eslint.config.mjs.
95+
- Use Angular CLI commands for generating boilerplate code
96+
- Document components and services with clear JSDoc comments
97+
- Ensure accessibility compliance (WCAG 2.1) where applicable
98+
- Use ngx-translate for internationalisation
99+
- Keep code DRY by creating reusable utilities and shared modules
100+
- Use signals consistently for state management to ensure reactive updates
101+
102+
## Documentation
103+
- When changing the API or adding new features, update the UPGRADE.md file where necessary
104+
- Document any new components, services, or significant changes in the codebase with clear comments and documentation
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
description: "Guidelines for writing Node.js and TypeScript code with Jest testing"
3+
applyTo: '**/*.test.ts'
4+
---
5+
6+
# Code Generation Guidelines
7+
8+
## Coding standards
9+
- Use TypeScript with ES2022 features and Node.js (version defined in .nvmrc) ESM modules
10+
- Use Node.js built-in modules and minimise external dependencies where possible
11+
- Ask the user before adding any additional dependencies
12+
- Always use async/await for asynchronous code, and use 'node:util' promisify function to avoid callbacks
13+
- Keep the code simple and maintainable
14+
- Use descriptive variable and function names
15+
- Write code that is self-explanatory, so comments are only needed when absolutely necessary
16+
- Use `undefined` for optional values instead of `null`
17+
- Prefer functions over classes
18+
19+
## Testing
20+
- Use Jest for testing
21+
- It's recommended to write tests for all new features and bug fixes
22+
- Ensure tests cover edge cases and error handling
23+
- Always write tests that cover the original code as it is, without changing the original code for testability
24+
25+
## User interactions
26+
- Ask questions if you are unsure about the implementation details, design choices, or need clarification on the requirements
27+
- Always answer in the same language as the question, but use English for the generated content like code, comments or docs

0 commit comments

Comments
 (0)