Skip to content

Develop backend#82

Merged
Rashed99Azm merged 138 commits into
mainfrom
develop-backend
Jun 28, 2026
Merged

Develop backend#82
Rashed99Azm merged 138 commits into
mainfrom
develop-backend

Conversation

@Rashed99Azm

Copy link
Copy Markdown
Collaborator

Summary

Backend enhancements

  • Improved architecture / code organization
  • Performance improvements (queries, caching, allocations, etc.)
  • Validation and business rule enhancements
  • Error handling and API response consistency
  • Logging, auditing, or observability improvements
  • Database/index/migration changes
  • Security improvements
  • Other technical debt and refactoring

rashed99mm and others added 30 commits May 14, 2026 16:56
- Fix CA1859/CA2263 analyzer errors in Domain and Application tests
- Suppress CA1873 false positives in Directory.Build.props with justification
- Add JWT Bearer security definition to Swagger (Authorize button)
- Catch RedisException in output-cache middleware to allow startup without Redis
- Apply EF migrations to remote dev SQL Server
- Seed demo data (categories, news, events, posts, roles)
Bumps all project TFMs from net8.0 to net10.0 and updates
package references to compatible versions.
- Directory.Build.props: <TargetFramework>net10.0</TargetFramework>
- Roslyn source generator remains on netstandard2.0
- All test projects updated to net10.0
- Adds ApplicationErrors with typed error codes (Identity.PASSWORD_RESET,
  EMAIL_EXISTS, INVALID_CREDENTIALS, etc.)
- Introduces Result<T> monad for command/query return types
- Adds localization service with YAML-backed stores
- Integrates ValidationBehavior and ResultValidationBehavior
  into MediatR pipeline
- DomainException / ConcurrencyException / DuplicateException
  mapped to problem details via middleware
Replaces coarse-grained domain services (ICommunityWriteService,
ICountryProfileService, etc.) with aggregate-specific repository
interfaces aligned to DDD per-aggregate persistence.
- Introduces I*Repository interfaces per aggregate root
- Updates command/query handlers to depend on repositories
- Infrastructure layer implements repository interfaces with EF Core
- Removes obsolete service abstractions from Application layer
- Added AuditableAggregateRoot for creation and update tracking
- Added SoftDeleteAggregateRoot for logical deletion support

- Improved domain consistency across aggregates
…y, unify repository commit pattern

-
IAuthService (Login, RefreshToken, Logout, Register, ForgotPassword, ResetPassword): all 6 auth handlers reduced to thin wrappers (2 deps each instead of 4–6); duplicated token rotation/issuance logic eliminated; wrong ResetPassword domain keys fixed (INVALID_REFRESH_TOKEN → INVALID_RESET_TOKEN, REGISTRATION_FAILED → RESET_FAILED)
-
Refresh token repos no longer own commits: SaveChangesAsync removed from IRefreshTokenRepository / RefreshTokenRepository — AuthService owns commit via ICceDbContext
-
DDD hierarchy aligned: Entity<TId> constrained to IEquatable<TId>, domain events moved to AggregateRoot<TId> (inherits SoftDeletableEntity), deleted AuditableAggregateRoot/SoftDeletableAggregateRoot, upgraded 3 entities to AggregateRoot, updated 12 entity base classes
-
Generic repository pattern: IRepository<T,TId> + Repository<T,TId> base for aggregate repos
-
Handler commit ownership: IStateRepAssignmentRepository, IExpertRequestSubmissionRepository, IExpertWorkflowRepository, IUserProfileRepository — all SaveChangesAsync calls moved to handl
BREAKING CHANGE: Response.message is now a plain string instead of
{ ar, en } bilingual object, and FieldError.message is also a string.
LocalizationService.GetString() now defaults to
CultureInfo.CurrentUICulture (set by LocalizationMiddleware from
the Accept-Language header) instead of hardcoded "ar".
Changes:
- Response<T>.Message: LocalizedMessage → string
- FieldError.Message: LocalizedMessage → string
- MessageFactory uses _l.GetString() instead of GetLocalizedMessage()
- ExceptionHandlingMiddleware returns single message string
- ResponseValidationBehavior uses GetString() for validation errors
-manage user status
- Optimize ListUsersQuery: single-projection with inline role sub-select, replace join-based role filter with EXISTS subquery
- Optimize GetUserByIdQuery: collapse two DB round-trips into one Select projection, replace ToList+SingleOrDefault with FirstOrDefaultAsync
- Fix auth token handling in user management flow
…ables

- Replace bilingual video_url with single field on HomepageSettings
- Extract KnowledgePartner as separate aggregate from AboutSettings
- Extract PolicySection with PolicySectionType enum from PoliciesSettings
- Promote GlossaryEntry, HomepageCountry to AggregateRoot<Guid>
- Add order_index to HomepageCountry and all collection tables
- Switch all handlers to Response<T> + MessageFactory pattern
- Add ICceDbContext.Add/Delete/DeleteRange generic write methods
- Add 12 new admin + public endpoints for CRUD (glossary, partners, sections)
- Register new repos, EF configs, DI, SystemCode mappings, Resources.yaml keys
- Regenerate AddPlatformSettings migration with updated schema (7 tables)
- Add MediaFile entity, EF config, repository, upload options
- Add UploadMedia, UpdateMediaMetadata, DeleteMedia, GetMediaById commands/queries
- Add MediaFileBriefDto for consistent POST/PUT/DELETE response shape
- Add Internal (port 5002) and External (port 5001) REST endpoints
- Add MEDIA_UPLOADED/UPDATED/DELETED localized success messages (AR/EN)
- Add ERR110-ERR113 error codes for file validation
- Create and apply EF migration AddMediaService
- Build 0 errors, 773 tests pass (4 pre-existing failures)
- Add Serilog.Sinks.Seq to ship structured logs to Seq
- Add OpenTelemetry with ASP.NET Core + HttpClient instrumentation
- Export traces to Seq via OTLP (http://localhost:5341/ingest/otlp)
- Enrich Serilog logs with TraceId/SpanId from Activity.Current
- Register AddCceOpenTelemetry in both External and Internal APIs
- Add Seq configuration section to appsettings.json (empty in prod, localhost in dev)
- Keep existing Prometheus metrics untouched
- Add `BypassSettings` flag to `NotificationDispatchRequest` so security
  notifications (password reset) always send regardless of user opt-out
- Replace `IPasswordResetEmailSender` with `INotificationGateway` in
  `AuthService.ForgotPasswordAsync` — sends through the notification system
- Add `NotificationChannel.Sms` to password reset dispatch alongside Email
- Add `PASSWORD_RESET` SMS template to `ReferenceDataSeeder` (short Arabic
  and English bodies suitable for SMS character limits)
- Fix seeder idempotency check in `SeedNotificationTemplatesAsync` to query
  by `(code, channel)` instead of deterministic ID, preventing duplicate-key
  errors on re-seed
- Delete unused `IPasswordResetEmailSender` interface and
  `PasswordResetEmailSender` implementation
…ices

Feat/add system notificaton services
- Domain: add OtpVerification aggregate, UserVerification entity, OtpVerificationType enum
- Application: add RequestVerification and VerifyOtp commands, handlers, validators, DTOs
- Application: add IOtpVerificationRepository, IUserVerificationRepository, IUserRepository, IOtpCodeGenerator
- Application: add OTP system codes (ERR120–ERR125, CON060–CON061) and message factory shortcuts
- Infrastructure: add EF configurations, repository implementations, HMAC-based OtpCodeGenerator
- Infrastructure: register verification services and UserRepository in DI
- API: add POST /verification/request and POST /verification/verify endpoints (anonymous)
- Seeder: add OTP_VERIFICATION notification template for Email and SMS channels
…rmation

- Domain: add OtpVerification aggregate, UserVerification entity, OtpVerificationType enum
- Application: add RequestVerification and VerifyOtp commands/handlers/validators/DTOs
- Application: add IUserRepository, IOtpVerificationRepository, IUserVerificationRepository, IOtpCodeGenerator
- Application: add OTP system codes (ERR120–ERR125, CON060–CON061) and message factory shortcuts
- Application: refactor VerifyOtpCommandHandler to use repositories instead of direct ICceDbContext queries
- Infrastructure: add EF configurations, repository implementations, HMAC-based OtpCodeGenerator
- Infrastructure: add UserRepository with FindUserIdByContactAsync and StampConfirmedAsync
- Infrastructure: fix ConcurrencyStamp null stub causing DbUpdateConcurrencyException on user confirm
- Infrastructure: restore pre-existing missing sub-namespace usings in DependencyInjection.cs
- Infrastructure: fix missing using in MessagingOptions.xml doc cref
- API: add POST /verification/request and POST /verification/verify endpoints (anonymous)
- API: add Otp:HmacSecret to appsettings (dev + base configs)
- Seeder: add OTP_VERIFICATION notification template
- Migration: AddOtpVerification
rashed99mm and others added 27 commits June 22, 2026 12:16
add-roles claims
add-users-claims
- Make POST /api/community/polls/{id}/vote idempotent (upsert):
  delete existing votes for the user before inserting new ones,
  allowing vote changes without conflict
- Add PollOption.DecrementVotes() for consistent counter rollback
- Add IPollRepository.RemoveVotesAsync(); remove HasVotedAsync
- Add PollSummaryDto / FeedPollOptionDto — vote counts, percentages,
  userVoted, resultsVisible computed per request
- Extend FeedHydratorService with poll batch fetch + user voted IDs
- Extend GetPublicPostByIdQueryHandler and
  ListPublicPostsInTopicQueryHandler to load poll data
- Add PollSummaryDto? Poll to CommunityFeedItemDto, PublicPostDto,
  PostDetailDto
- Add audit fields (CreatedOn, CreatedById, LastModifiedOn,
  LastModifiedById) to User entity + migration AddUserAuditFields
- Update all User factory methods to accept ISystemClock
- Extend CommunityUserProfileDto with ExpertBioAr, ExpertBioEn,
  CountryNameAr, CountryNameEn, JoinedDate
- Change profile endpoint to AllowAnonymous
Feat add claims based matrix db + community audits
…ardening

Phase 1 — Envelope correctness (no contract change)
- ExceptionHandlingMiddleware: locale resolved from Accept-Language header
- UnauthorizedAccessException maps to 401; correlationId added to envelope body
- BAD_REQUEST message made distinct from VALIDATION_ERROR
- General.NOT_FOUND renamed to RESOURCE_NOT_FOUND_GENERIC
- GetShareLinkQueryHandler consumer fixed
- 6/6 middleware tests pass

Phase 2 — Contract changes + handler migration
- DomainException → 422 BUSINESS_RULE_VIOLATION (ERR910)
- Rate-limit 429 envelope via EnvelopeWriter (replaced External plain-text,
  added Internal OnRejected)
- JWT 401/403 envelope via OnChallenge/OnForbidden
- EnvelopeWriter, EnvelopeResult, EnvelopeResults created as single
  serialization/status-mapping source of truth
- ~40 handlers migrated to Response<T>; all endpoint files processed

Phase 3 — Dead Result<T> deletion
- Deleted: Result.cs, Error.cs, OkApiResult.cs, CreatedApiResult.cs,
  NoContentApiResult.cs, ResultExtensions.cs, ResultValidationBehavior.cs,
  ValidationBehavior.cs
- All source projects build

Phase 4 — Cleanup and hardening
- ApplicationErrors → DomainKeys; moved Errors/ → Messages/; namespace
  CCE.Application.Errors → CCE.Application.Messages
- Bulk-replaced 193 ApplicationErrors. references and 51 using directives
- Hellang ProblemDetails dependency removed
- LoggingBehavior + ValidationBehavior registrations removed
- CSP hardened: X-Frame-Options, base-uri, form-action, object-src added
- Fixed middleware order comment in External/Program.cs

Phase 5 — Build integrity + DomainKeys completeness
- Added DomainKeysIntegrityTests (3 tests) in CCE.ArchitectureTests:
  bidirectional consistency between DomainKeys and SystemCodeMap — all pass
- Fixed missing using Microsoft.Extensions.Configuration in EnvelopeWriter.cs
- Filled 33 orphaned SystemCodeMap entries as new DomainKeys constants
  (General, Identity, Content, Verification, Validation, new InterestTopic class)
- Added 5 missing SystemCodeMap entries + SystemCode constants
  (ERR032, CON073–CON076)

Phase 6 — Validator hardening + SystemCodeMap completion (code review fixes)
- Add .WithErrorCode(MessageKeys.Validation.*) to Login, ForgotPassword,
  RefreshToken, Logout, UpdateMyProfile, CreateUser, SubmitExpertRequest
  validators — all were emitting ERR900 on validation failure
- Replace all remaining .WithMessage() with .WithErrorCode()
- RegisterUserCommandValidator: add RuleLevelCascadeMode = CascadeMode.Stop
  to prevent double REQUIRED_FIELD + INVALID_FORMAT on empty fields; add
  .NotEmpty() guards before Password Must() and ConfirmPassword Equal()
- Rename MatchStoryPasswordPolicy → MatchStrongPasswordPolicy (typo)
- ResetPasswordCommandValidator: add .NotEmpty() guards on NewPassword
  and ConfirmPassword; update method reference to renamed policy check
- Add ERR410 ROLE_NOT_FOUND, ERR411 INVALID_RESET_TOKEN,
  ERR412 EMAIL_CHANGE_FAILED, ERR127 OTP_UNAUTHORIZED to SystemCode +
  SystemCodeMap + Resources.yaml
- Add CON077–CON082 claims/permissions grant/revoke/update; CON083
  AD_LOGIN_SUCCESS; CON084 NEWSLETTER_SUBSCRIBED; CON085 TOPICS_LISTED;
  CON086 SECTION_REORDERED — all branch feature keys that were falling
  back to ERR900
- ExceptionHandlingMiddleware: remove ex.Message fallback from
  UnauthorizedAccessException to prevent internal message leakage
- ListRedisKeysQuery: replace raw "ITEMS_LISTED" with
  MessageKeys.General.ITEMS_LISTED

All source projects build with 0 errors, 0 warnings.
…ll pattern

Deleted all 52 convenience shortcut methods from MessageFactory, leaving
exactly 9 core methods (Ok, NotFound, Conflict, Unauthorized, Forbidden,
BusinessRule, ValidationError, Field). Updated ~130 handlers across
CCE.Application to call the generic API directly with explicit MessageKeys
constants.

Previously 83% of handlers used generic calls while 17% used shortcuts,
forcing every reader to check whether a shortcut exists before writing a
handler. Three handlers already mixed both styles. The factory now has one
pattern with no exceptions.

Rule going forward: new outcomes add a MessageKeys constant, a SystemCodeMap
entry, and a Resources.yaml string — nothing else touches MessageFactory.
…fied--Response--migration,-and-validation-hardening

Feat/unified error envelope, unified  response  migration, and validation hardening
Adds push as a first-class notification channel alongside email and in-app,
following the existing INotificationChannelHandler plug-in model.

- UserDeviceToken entity: one row per (UserId, DeviceId); token rotates,
  deviceId is stable. EF migration: AddUserDeviceToken
- POST /api/me/device-tokens — register/refresh FCM token (upsert by deviceId)
- DELETE /api/me/device-tokens/{deviceId} — unregister
- PushNotificationChannelSender: fetches active tokens, sends FCM multicast,
  deactivates stale tokens on UNREGISTERED/INVALID_ARGUMENT errors
- FirebaseMessagingService wraps FirebaseAdmin SDK with singleton guard
  (DefaultInstance ?? Create) and forwards CancellationToken
- Firebase section in appsettings; channel skipped cleanly when unconfigured
- MetaData added to RenderedNotification so handlers can pass deep-link
  context (postId, communityId, etc.) into FCM data payload
- NotificationChannel.Push added to all existing notification handlers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat: Firebase FCM push notification channel
…y/feed

Adds optional ?searchTerm= parameter to the community feed endpoint that
routes through Meilisearch instead of the SQL feed path when non-empty.
Results share the same CommunityFeedItemDto shape, extended with four
nullable highlight fields (TitleHighlight, BodyHighlight, MatchedInReply,
ReplyExcerpt). When searchTerm is absent the endpoint is unchanged.

Key changes:
- New SearchCommunityPostsQuery / validator / handler; relevance path
  reorders by Meilisearch rank in memory, sort path delegates to SQL
  ORDER BY over the candidate ID set; both delegate hydration to the
  existing FeedHydratorService
- Two new Meilisearch indexes: community_posts and community_replies;
  backfilled on Internal API startup and kept live via PostCreated /
  ReplyCreated domain-event handlers
- StripUnknownSearchFieldsHandler DelegatingHandler strips
  rankingScoreThreshold (SDK v0.15.5 default 0.0) that Meilisearch
  ≤v1.7 rejects; harmless on newer versions
- Global /api/search catch widened from MeilisearchApiError to
  System.Exception to match the SDK's actual throw types against cloud
- Prometheus metrics: community_search_hits, community_search_duration_ms,
  community_search_meili_failures
- Meilisearch config wired to hosted cloud instance in both API appsettings
- Search folder reorganised: Application/Search/Dtos/ and
  Infrastructure/Search/Documents/ subfolders; inline classes extracted
  from MeilisearchClient into their own files

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semgrep OSS found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

const line = document.createElement('div');
line.className = 'log-entry';
const typeClass = type === 'error' ? 'log-error' : type === 'info' ? 'log-info' : type === 'event' ? 'log-event' : 'log-payload';
line.innerHTML = '<span class="log-time">[' + time + ']</span> <span class="' + typeClass + '">' + eventName + '</span>' + (payload ? ' ' + syntaxHighlight(payload) : '');
const line = document.createElement('div');
line.className = 'log-entry';
const typeClass = type === 'error' ? 'log-error' : type === 'info' ? 'log-info' : type === 'event' ? 'log-event' : 'log-payload';
line.innerHTML = '<span class="log-time">[' + time + ']</span> <span class="' + typeClass + '">' + eventName + '</span>' + (payload ? ' ' + syntaxHighlight(payload) : '');
@Rashed99Azm Rashed99Azm merged commit 51f886c into main Jun 28, 2026
4 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants