|
| 1 | +# GitHub Copilot Instructions for StatusBoard |
| 2 | + |
| 3 | +## Project Overview |
| 4 | +StatusBoard is a real-time monitoring platform for tracking service health status. It features: |
| 5 | +- HTTP and AWS SDK-based health checks |
| 6 | +- Status change history tracking |
| 7 | +- Email and MS Teams notifications |
| 8 | +- REST API for programmatic access |
| 9 | +- Angular-based UI for visualization |
| 10 | + |
| 11 | +## Technology Stack |
| 12 | + |
| 13 | +### Backend (Scala) |
| 14 | +- **Framework**: ZIO (functional effects library) |
| 15 | +- **Build Tool**: SBT (Scala Build Tool) |
| 16 | +- **API**: Tapir for type-safe HTTP endpoints with Swagger documentation |
| 17 | +- **HTTP Server**: Blaze Server (http4s) |
| 18 | +- **Database**: AWS DynamoDB for persistence |
| 19 | +- **Testing**: ZIO Test framework |
| 20 | +- **Code Coverage**: Jacoco |
| 21 | + |
| 22 | +### Frontend (TypeScript) |
| 23 | +- **Framework**: Angular 19 |
| 24 | +- **UI Library**: PrimeNG, CPS UI Kit |
| 25 | +- **Testing**: Jest (unit tests) with `jest.config.ts`, Cypress (e2e tests) with `cypress.json` |
| 26 | +- **Build Tool**: Angular CLI |
| 27 | +- **Styling**: SCSS |
| 28 | + |
| 29 | +### Infrastructure |
| 30 | +- **Runtime**: JRE 21 (Corretto) |
| 31 | +- **Containerization**: Docker with docker-compose |
| 32 | +- **Cloud**: AWS (DynamoDB, SDK integrations) |
| 33 | + |
| 34 | +## Code Style and Conventions |
| 35 | + |
| 36 | +### Scala Code |
| 37 | +- Follow functional programming principles with ZIO effects |
| 38 | +- Use `scalafmt` for code formatting (`.scalafmt.conf` is configured) |
| 39 | +- Enable compiler flags: `-unchecked`, `-deprecation`, `-feature`, `-Xfatal-warnings`, `-Ymacro-annotations` |
| 40 | +- Organize code into layers: |
| 41 | + - **Controllers**: Business logic and API endpoint handlers |
| 42 | + - **Repository**: Database access layer |
| 43 | + - **Services**: Core business services (monitoring, notifications) |
| 44 | + - **Checkers**: Health check implementations |
| 45 | + - **Models**: Domain models and DTOs |
| 46 | + - **Config**: Configuration management with ZIO Config |
| 47 | + |
| 48 | +### TypeScript/Angular Code |
| 49 | +- Use ESLint (via `eslint.config.js`) and Prettier (via `.prettierrc`) for linting and formatting |
| 50 | +- Follow Angular style guide |
| 51 | +- Component-based architecture with services for business logic |
| 52 | +- Use RxJS for reactive programming |
| 53 | +- Test with Jest and Cypress |
| 54 | + |
| 55 | +### Error Handling |
| 56 | +- Use ZIO's `IO[ErrorResponse, A]` pattern for typed errors |
| 57 | +- Map database errors to API response errors consistently |
| 58 | +- Common error types: `RecordNotFoundErrorResponse`, `DataConflictErrorResponse`, `InternalServerErrorResponse`, `UnauthorizedErrorResponse` |
| 59 | + |
| 60 | +### Authentication |
| 61 | +- API key-based authentication via `Authorization` header |
| 62 | +- Use `AuthController` ([api/controllers/AuthController.scala](../src/main/scala/za/co/absa/statusboard/api/controllers/AuthController.scala)) to protect write endpoints |
| 63 | +- Read endpoints are generally public |
| 64 | + |
| 65 | +## Project Structure |
| 66 | + |
| 67 | +### Backend (`src/main/scala`) |
| 68 | +``` |
| 69 | +za. co.absa.statusboard/ |
| 70 | +├── api/ |
| 71 | +│ ├── controllers/ # API endpoint handlers |
| 72 | +│ │ ├── AuthController |
| 73 | +│ │ ├── ServiceConfigurationController |
| 74 | +│ │ ├── StatusController |
| 75 | +│ │ └── MonitoringController |
| 76 | +│ └── http/ # HTTP layer (routes, endpoints) |
| 77 | +├── checker/ # Health check implementations |
| 78 | +├── config/ # Configuration models |
| 79 | +├── model/ # Domain models |
| 80 | +├── monitoring/ # Monitoring service and workers |
| 81 | +├── notification/ # Email and Teams notifications |
| 82 | +├── providers/ # External service providers |
| 83 | +└── repository/ # Database access layer |
| 84 | +``` |
| 85 | + |
| 86 | +### Frontend (`ui/src/app`) |
| 87 | +``` |
| 88 | +├── components/ # Angular components |
| 89 | +│ ├── status-list/ |
| 90 | +│ ├── status-history/ |
| 91 | +│ ├── card/ |
| 92 | +│ └── dependency-graph/ |
| 93 | +├── services/ # Angular services |
| 94 | +│ ├── backend/ # API client |
| 95 | +│ ├── repository/ # Data management |
| 96 | +│ └── refresh/ # Auto-refresh logic |
| 97 | +└── modules/ # Shared modules |
| 98 | +``` |
| 99 | + |
| 100 | +## Key Patterns |
| 101 | + |
| 102 | +### ZIO Layers |
| 103 | +- Use ZIO layers for dependency injection |
| 104 | +- Define layer in companion object: `object XImpl { val layer: TaskLayer[X] = ... }` |
| 105 | +- Access services via ZIO environment: `ZIO.serviceWithZIO[Service](_. method())` |
| 106 | + |
| 107 | +### API Endpoints (Tapir) |
| 108 | + Define endpoints in `Endpoints. scala` with full type safety |
| 109 | +- Use `@accessible` macro for controller traits |
| 110 | +- Bind public endpoints: `bindEndpoint(endpoint, handler)` |
| 111 | +- Bind authenticated endpoints: `bindEndpoint(authController)(endpoint, handler)` |
| 112 | +- Add `. noCache` to prevent caching on real-time data |
| 113 | +- Read endpoints (GET) are typically public |
| 114 | +- Write endpoints (POST, PUT, DELETE) typically require authentication via API key |
| 115 | + |
| 116 | +### Controllers Pattern |
| 117 | +```scala |
| 118 | +@accessible |
| 119 | +trait XController { |
| 120 | + def method(params): IO[ErrorResponse, Result] |
| 121 | +} |
| 122 | + |
| 123 | +class XControllerImpl(dependencies) extends XController { |
| 124 | + def method(params): IO[ErrorResponse, Result] = |
| 125 | + // implementation with error handling |
| 126 | +} |
| 127 | + |
| 128 | +object XControllerImpl { |
| 129 | + val layer: TaskLayer[XController] = ZLayer { /* ... */ } |
| 130 | +} |
| 131 | +``` |
| 132 | + |
| 133 | +### Checker Architecture |
| 134 | +The checker system uses a polymorphic design: |
| 135 | +- **Base trait**: `Checker` defines the core interface: |
| 136 | + ```scala |
| 137 | + trait Checker { |
| 138 | + def checkRawStatus(action: StatusCheckAction): UIO[RawStatus] |
| 139 | + } |
| 140 | + ``` |
| 141 | +- **Specialized traits**: Each checker type has its own trait (e.g., `HttpGetRequestWithMessageChecker`, `AwsRdsChecker`, `AwsEmrChecker`) |
| 142 | +- **Implementations**: Concrete implementations for each specialized trait (e.g., `HttpGetRequestWithMessageCheckerImpl`) |
| 143 | +- **Polymorphic dispatcher**: `PolymorphicChecker` implements the base `Checker` trait and delegates to specialized checkers based on the `StatusCheckAction` subtype |
| 144 | +- **Supported checkers**: |
| 145 | + - HTTP-based: `HttpGetRequestStatusCodeOnly`, `HttpGetRequestWithMessage`, `HttpGetRequestWithJsonStatus` |
| 146 | + - AWS-based: `AwsRds`, `AwsRdsCluster`, `AwsEmr`, `AwsEc2AmiCompliance` |
| 147 | + - Special: `FixedStatus`, `TemporaryFixedStatus`, `Composition` |
| 148 | + |
| 149 | +### Database Operations |
| 150 | +- Repository layer returns `IO[DatabaseError, Result]` |
| 151 | +- Controllers map `DatabaseError` to `ErrorResponse` |
| 152 | +- Use DynamoDB as primary persistence |
| 153 | + |
| 154 | +## Testing Guidelines |
| 155 | + |
| 156 | +### Scala Tests |
| 157 | +- Unit tests: `sbt test` - should require no external dependencies |
| 158 | +- Integration tests: Custom SBT commands (`testDynamo`, `testSMTP`, `testMSTeams`) |
| 159 | +- Use ZIO Test framework with `suite` and `test` functions |
| 160 | +- Mock external dependencies for unit tests |
| 161 | +- Use `ConfigProviderSpec` for test configurations |
| 162 | +- Test aspects: Use `@@ TestAspect. sequential` for tests that must run sequentially |
| 163 | + |
| 164 | +### TypeScript Tests |
| 165 | +- Unit tests: `npm run test` (Jest via `jest.config.ts`) |
| 166 | +- E2E tests: `npm run e2e` (Cypress via `cypress.json`) |
| 167 | +- Test coverage: `npm run test:coverage` |
| 168 | + |
| 169 | +## Configuration |
| 170 | +- Main config: `config. conf` (HOCON format) |
| 171 | +- Environment-specific configurations for different deployments |
| 172 | +- AWS credentials required (can be mocked for non-AWS environments) |
| 173 | +- DynamoDB endpoint configurable for local development |
| 174 | +- Configuration uses ZIO Config with magnolia derivation: `deriveConfig[T]. nested("path", "to", "config")` |
| 175 | + |
| 176 | +## Build and Assembly |
| 177 | +- Backend: `sbt assembly` creates fat JAR in `target/scala-2.13/` |
| 178 | +- Frontend: `npm run build` in `ui/` directory |
| 179 | +- Version source of truth: `VERSION` file at root |
| 180 | +- Version sync: Frontend runs `npm run sync-version` (via `syncVersion.js`) to sync with VERSION file |
| 181 | + |
| 182 | +## Dependency Management |
| 183 | + |
| 184 | +### Scala Dependencies |
| 185 | +- Define dependencies in `project/Dependencies.scala` |
| 186 | +- Version constants in `Dependencies. Versions` object |
| 187 | +- Common dependencies in `Dependencies.commonDependencies` sequence |
| 188 | +- Referenced in `build.sbt` |
| 189 | + |
| 190 | +### Frontend Dependencies |
| 191 | +- Add npm dependencies in `ui/package.json` |
| 192 | +- Major dependencies: Angular 19, PrimeNG, CPS UI Kit, RxJS |
| 193 | + |
| 194 | +## API Documentation |
| 195 | +- Swagger UI available at `GET /docs` |
| 196 | +- Endpoints follow pattern: `/api/v1/{resource}` |
| 197 | +- Use typed requests/responses with Circe JSON codec |
| 198 | + |
| 199 | +## Notifications |
| 200 | +- Email templates support variable substitution: `{{ SERVICE_NAME }}`, `{{ STATUS }}`, `{{ STATUS_COLOR }}`, etc. |
| 201 | +- MS Teams webhook integration |
| 202 | +- Notification logic in `notification/` package (templates in `src/main/resources/notifications/`) |
| 203 | +- Polymorphic design: `PolymorphicNotificationActioner` delegates to specialized actioners |
| 204 | +- Notification deciders: Duration-based logic to prevent notification spam |
| 205 | + |
| 206 | +## Docker |
| 207 | +- Backend Dockerfile for service |
| 208 | +- UI.Dockerfile for frontend |
| 209 | +- docker-compose.yml for local DynamoDB setup |
| 210 | +- Follow comments in Dockerfiles for build/run instructions |
| 211 | + |
| 212 | +## Release Management |
| 213 | +- Semver versioning in VERSION file (keep the file in sync with Git tags/CI release pipelines to avoid mismatches) |
| 214 | +- Snapshot builds: `X.Y.Z-SNAPSHOT` |
| 215 | +- Release builds: `X.Y.Z` (no suffix) |
| 216 | +- DEV deployment: automatic on merge to master |
| 217 | +- PROD deployment: manual trigger after release |
| 218 | + |
| 219 | +## When Writing Code |
| 220 | + |
| 221 | +### For Backend Changes |
| 222 | +1. Start with the model/domain types |
| 223 | +2. Add repository methods if database access needed |
| 224 | +3. Implement controller logic with proper error handling |
| 225 | +4. Define Tapir endpoints with all error cases |
| 226 | +5. Wire up in `RoutesImpl` |
| 227 | +6. Add tests covering happy path and error cases |
| 228 | +7. Update API documentation if endpoints change |
| 229 | + |
| 230 | +### For Frontend Changes |
| 231 | +1. Create/modify Angular components |
| 232 | +2. Update services for API communication |
| 233 | +3. Use CPS UI Kit and PrimeNG components |
| 234 | +4. Add unit tests (Jest) and/or E2E tests (Cypress) |
| 235 | +5. Ensure responsive design |
| 236 | +6. Follow Angular reactive patterns with RxJS |
| 237 | + |
| 238 | +### For Health Checkers |
| 239 | +1. Define a specialized trait in `checker/` package extending the checker pattern: |
| 240 | + ```scala |
| 241 | + @accessible |
| 242 | + trait XChecker { |
| 243 | + def checkRawStatus(action: StatusCheckAction. X): UIO[RawStatus] |
| 244 | + } |
| 245 | + ``` |
| 246 | +2. Implement the trait in `XCheckerImpl` class |
| 247 | +3. Define a ZIO layer in the companion object |
| 248 | +4. Add the checker to `PolymorphicChecker` to handle the new action type |
| 249 | +5. Support configuration from HOCON if needed |
| 250 | +6. Return typed status results: `RawStatus. Green`, `RawStatus.Amber`, or `RawStatus.Red` |
| 251 | +7. Use `intermittent` flag for transient failures |
| 252 | +8. Add integration tests |
| 253 | +9. Document in wiki under "Supported checkers" |
| 254 | + |
| 255 | +## Common Commands |
| 256 | +```bash |
| 257 | +# Backend |
| 258 | +sbt clean test # Clean + unit tests |
| 259 | +sbt compile # Compile |
| 260 | +sbt assembly # Build fat JAR |
| 261 | +sbt jacoco # Code coverage |
| 262 | + |
| 263 | +# Frontend |
| 264 | +npm run start # Dev server |
| 265 | +npm run build # Production build |
| 266 | +npm run test # Unit tests (Jest) |
| 267 | +npm run e2e # E2E tests (Cypress) |
| 268 | +npm run lint # Lint & format check |
| 269 | +npm run lint:fix # Auto-fix linting issues |
| 270 | +npm run sync-version # Sync VERSION file to package.json |
| 271 | +``` |
| 272 | + |
| 273 | +## AWS Integration |
| 274 | +- AWS SDK used for: DynamoDB, RDS, RDS Clusters, EMR, EC2 |
| 275 | +- ZIO-AWS library provides typed AWS integrations |
| 276 | +- Region configuration per service check |
| 277 | +- Endpoint override available for local testing |
| 278 | + |
| 279 | +## Additional Resources |
| 280 | +- [Wiki - REST API](https://github.com/AbsaOSS/StatusBoard/wiki/REST-API) |
| 281 | +- [Wiki - Architecture](https://github.com/AbsaOSS/StatusBoard/wiki/Architecture) |
| 282 | +- [Wiki - Supported Checkers](https://github.com/AbsaOSS/StatusBoard/wiki/Supported-checkers) |
0 commit comments