docs: enrich backend code documentation

This commit is contained in:
vsxd 2026-03-19 12:57:45 +08:00 • committed by Xudong Sun
parent 6a62fec9e8
commit 8ef53d0fdd
257 changed files with 1476 additions and 4 deletions

View file

@ -0,0 +1,249 @@
# Backend Structure Findings During Annotation Pass
This document records architecture and structure issues that became consistently visible while enriching backend comments. The goal is to preserve concrete observations discovered during code reading, not to propose a full redesign.
## 1. Admin user management is split across overlapping application services
Observed files:
- `server/skillhub-app/src/main/java/com/iflytek/skillhub/service/AdminUserAppService.java`
- `server/skillhub-app/src/main/java/com/iflytek/skillhub/service/AdminUserManagementService.java`
Why this stands out:
- Both services sit in the application layer and are named as if they own the same capability.
- The naming does not make the responsibility boundary obvious to a reader.
- This increases the chance that new admin-user use cases get placed inconsistently.
Suggested direction:
- Either consolidate them into one application service, or split them with an explicit boundary such as query vs. command, or account governance vs. account operations.
## 2. Several controllers still perform orchestration that belongs in application services
Observed files:
- `server/skillhub-app/src/main/java/com/iflytek/skillhub/controller/portal/NamespaceController.java`
- `server/skillhub-app/src/main/java/com/iflytek/skillhub/controller/portal/ReviewController.java`
- `server/skillhub-app/src/main/java/com/iflytek/skillhub/controller/portal/PromotionController.java`
- `server/skillhub-app/src/main/java/com/iflytek/skillhub/controller/portal/SkillLifecycleController.java`
- `server/skillhub-app/src/main/java/com/iflytek/skillhub/compat/ClawHubCompatController.java`
Why this stands out:
- Some controllers coordinate multiple repositories, domain services, request-derived identities, and response assembly in one place.
- The controller layer is therefore carrying request translation and business workflow orchestration at the same time.
- This makes endpoint behavior harder to reuse, test, and document consistently.
Suggested direction:
- Move multi-step orchestration into dedicated application services and keep controllers focused on transport concerns.
## 3. Compatibility endpoints are tightly coupled to canonical domain and repository internals
Observed files:
- `server/skillhub-app/src/main/java/com/iflytek/skillhub/compat/ClawHubCompatController.java`
- `server/skillhub-app/src/main/java/com/iflytek/skillhub/compat/ClawHubRegistryFacade.java`
Why this stands out:
- The compatibility layer pulls from repositories, domain services, and DTO-mapping concerns at the same time.
- The layer is useful, but it is not isolated enough to act as a clean anti-corruption boundary.
- Changes in canonical read models or publish flows are more likely to leak into compatibility code.
Suggested direction:
- Treat compatibility support as a dedicated adapter layer with narrower upstream contracts and fewer direct repository dependencies.
## 4. Security route policy is spread across configuration and implementation classes
Observed files:
- `server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/config/SecurityConfig.java`
- `server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/token/ApiTokenScopeService.java`
- `server/skillhub-app/src/main/java/com/iflytek/skillhub/filter/AuthContextFilter.java`
Why this stands out:
- Route access rules, token-scope rules, and request-context projection are all related to request authorization, but they are not expressed from one central policy model.
- A reader has to jump across modules to reconstruct how one API route is actually protected.
Suggested direction:
- Centralize route policy metadata or at least define one authoritative mapping between path patterns, authentication modes, and scope requirements.
## 5. Governance behavior is distributed across multiple services without one clear workflow owner
Observed files:
- `server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/namespace/NamespaceGovernanceService.java`
- `server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/skill/service/SkillGovernanceService.java`
- `server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/review/ReviewService.java`
- `server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/review/PromotionService.java`
Why this stands out:
- Governance rules are present in the right domain areas, but the end-to-end moderation and publishing workflow is distributed.
- Readers need to reconstruct lifecycle rules by navigating several services and controllers.
Suggested direction:
- Keep the domain split, but introduce a clearer workflow owner or workflow-facing facade for governance use cases.
## 6. Search-related read paths are split in a way that is hard to follow at first glance
Observed files:
- `server/skillhub-search/src/main/java/com/iflytek/skillhub/search/postgres/PostgresFullTextQueryService.java`
- `server/skillhub-app/src/main/java/com/iflytek/skillhub/service/SkillSearchAppService.java`
- `server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/skill/service/SkillQueryService.java`
Why this stands out:
- The codebase has a sensible separation between search, application assembly, and canonical detail reads, but the naming alone does not make their responsibilities obvious.
- New contributors may need several passes to understand which service is the authoritative entry point for each read scenario.
Suggested direction:
- Clarify the boundary in naming or package-level docs, especially around "search result assembly" vs. "authoritative skill detail query."
## 7. Event-driven counter maintenance is useful but not yet modeled as a distinct projection concern
Observed files:
- `server/skillhub-app/src/main/java/com/iflytek/skillhub/listener/SkillStarEventListener.java`
- `server/skillhub-app/src/main/java/com/iflytek/skillhub/listener/SkillRatingEventListener.java`
Why this stands out:
- Listeners are maintaining derived counters, which is a legitimate pattern.
- The projection/update responsibility is implicit rather than explicitly named as a read-model maintenance concern.
Suggested direction:
- Consider naming this area more explicitly as projection maintenance or read-model synchronization if the pattern continues to grow.
## 8. Exception modeling is duplicated across application, domain, and auth layers
Observed files:
- `server/skillhub-app/src/main/java/com/iflytek/skillhub/exception/LocalizedException.java`
- `server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/shared/exception/LocalizedDomainException.java`
- `server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/exception/AuthFlowException.java`
- `server/skillhub-app/src/main/java/com/iflytek/skillhub/exception/GlobalExceptionHandler.java`
Why this stands out:
- The codebase uses localized error codes consistently, which is good, but several layers define parallel exception abstractions with overlapping semantics.
- The global exception handler then has to understand each branch separately.
- This makes it harder to tell whether a new business error belongs to the app layer, the auth layer, or the shared domain exception model.
Suggested direction:
- Keep layer-specific exception types only where they represent a real boundary, and consider converging on a smaller shared contract for localized API-facing errors.
## 9. Repository and read-model access patterns are mixed across layers
Observed files:
- `server/skillhub-app/src/main/java/com/iflytek/skillhub/repository/AdminUserSearchRepository.java`
- `server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/*/*Repository.java`
- `server/skillhub-infra/src/main/java/com/iflytek/skillhub/infra/jpa/*`
- `server/skillhub-app/src/main/java/com/iflytek/skillhub/compat/ClawHubCompatController.java`
Why this stands out:
- Some flows use domain repository ports, some use infra JPA repositories, and some app-layer read logic uses `EntityManager` directly.
- This is not wrong in itself, but the conventions are not explicit, so contributors have to infer when bypassing the domain port layer is acceptable.
- The mixed style increases the chance that query behavior and write behavior evolve under different architectural rules.
Suggested direction:
- Define explicit rules for when a use case should depend on domain repository ports, dedicated query repositories, or direct persistence adapters.
## 10. OAuth login behavior is decomposed into many small classes without one visible flow owner
Observed files:
- `server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/oauth/SkillHubOAuth2AuthorizationRequestResolver.java`
- `server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/oauth/CustomOAuth2UserService.java`
- `server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/oauth/GitHubClaimsExtractor.java`
- `server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/oauth/OAuth2LoginSuccessHandler.java`
- `server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/oauth/OAuth2LoginFailureHandler.java`
- `server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/policy/AccessPolicyFactory.java`
Why this stands out:
- The current decomposition is modular, but understanding one OAuth login request still requires following state across request resolution, provider-specific claim extraction, access-policy evaluation, account provisioning, and redirect handling.
- The extension points are good, yet the absence of one flow-oriented facade or documented orchestration path increases onboarding cost.
Suggested direction:
- Keep the provider-specific strategy types, but consider a clearer flow owner or a compact architecture note that names the stages of the OAuth pipeline.
## 11. Some domain repository ports leak Spring Data pagination types
Observed files:
- `server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/skill/SkillRepository.java`
- `server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/review/ReviewTaskRepository.java`
- `server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/audit/AuditLogQueryService.java`
Why this stands out:
- Several domain-facing repository contracts use `Page` and `Pageable` directly.
- This makes the domain boundary more dependent on Spring Data semantics than on a framework-neutral query model.
- It is workable, but it weakens the separation between domain contracts and persistence tooling.
Suggested direction:
- Either accept Spring Data as an intentional part of the domain boundary and document that choice, or introduce domain-oriented page/query abstractions where long-term isolation matters.
## 12. The auth module follows a more direct JPA style than the business-domain modules
Observed files:
- `server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/repository/ApiTokenRepository.java`
- `server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/repository/IdentityBindingRepository.java`
- `server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/repository/RoleRepository.java`
- `server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/skill/SkillRepository.java`
- `server/skillhub-infra/src/main/java/com/iflytek/skillhub/infra/jpa/JpaSkillRepositoryAdapter.java`
Why this stands out:
- The auth area usually talks directly to Spring Data JPA repositories over auth entities.
- The business-domain area more often exposes domain repository ports and implements them through infra adapters.
- Both styles are valid, but using them side by side without an explicit rationale makes the overall architecture feel uneven.
Suggested direction:
- Decide whether auth is intentionally allowed to stay as a more direct persistence-oriented module, and document that distinction so contributors know which style to apply in new code.
## 13. Many domain objects double as persistence entities instead of being isolated from JPA concerns
Observed files:
- `server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/skill/Skill.java`
- `server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/namespace/Namespace.java`
- `server/skillhub-domain/src/main/java/com/iflytek/skillhub/domain/review/ReviewTask.java`
- `server/skillhub-infra/src/main/java/com/iflytek/skillhub/infra/jpa/SkillJpaRepository.java`
- `server/skillhub-infra/src/main/java/com/iflytek/skillhub/infra/jpa/NamespaceMemberJpaRepository.java`
Why this stands out:
- The codebase often uses the same classes as both domain models and JPA persistence entities.
- This keeps implementation compact, but it also means persistence annotations, lazy-loading behavior, and storage-driven shape decisions can leak into domain modeling concerns.
- Combined with the repository-style differences already noted above, the codebase can feel partly domain-driven and partly persistence-driven depending on the module.
Suggested direction:
- If this is an intentional tradeoff, document it clearly as the project's default. Otherwise, consider introducing stronger separation only in areas where persistence concerns are starting to distort domain logic.
## Priority Recommendation
If only a small amount of structural cleanup is feasible, the highest-value items are:
1. Reduce controller orchestration by introducing a few focused application services.
2. Clarify the admin-user service boundary.
3. Centralize security route policy so access behavior is easier to reason about.

View file

@ -5,6 +5,9 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
/**
* Main Spring Boot entry point for the SkillHub backend application.
*/
@SpringBootApplication
@EnableConfigurationProperties(ProfileModerationProperties.class)
public class SkillhubApplication {

View file

@ -3,6 +3,9 @@ package com.iflytek.skillhub.bootstrap;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* Configuration properties for bootstrapping a default admin account in controlled environments.
*/
@Component
@ConfigurationProperties(prefix = "skillhub.bootstrap.admin")
public class BootstrapAdminProperties {

View file

@ -20,6 +20,9 @@ import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
/**
* Seeds predictable users, memberships, and admin roles for the local development profile.
*/
@Component
@Profile("local")
public class LocalDevDataInitializer implements ApplicationRunner {

View file

@ -0,0 +1,5 @@
/**
* Startup initializers that prepare local development data and required system
* accounts before the application begins serving traffic.
*/
package com.iflytek.skillhub.bootstrap;

View file

@ -43,6 +43,10 @@ import java.time.ZoneOffset;
import java.util.List;
import java.util.Map;
/**
* Compatibility controller that exposes SkillHub content using ClawHub-style routes and payload
* shapes expected by legacy clients.
*/
@RestController
@RequestMapping("/api/v1")
public class ClawHubCompatController {

View file

@ -22,6 +22,10 @@ import java.util.Map;
import java.util.Optional;
import org.springframework.stereotype.Component;
/**
* Facade that assembles registry-style compatibility responses from the platform's canonical search
* and skill services.
*/
@Component
public class ClawHubRegistryFacade {

View file

@ -7,6 +7,10 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
/**
* Declares a dedicated stateless security chain for public compatibility endpoints used by
* registry-style clients.
*/
@Configuration
public class ClawHubRegistrySecurityConfig {

View file

@ -1,3 +1,6 @@
package com.iflytek.skillhub.compat;
/**
* Canonical namespace-and-slug pair used by compatibility adapters to address one skill.
*/
public record SkillCoordinate(String namespace, String slug) {}

View file

@ -5,6 +5,9 @@ import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* Serves well-known compatibility metadata used by external clients to discover the API base.
*/
@RestController
public class WellKnownController {

View file

@ -0,0 +1,5 @@
/**
* DTOs dedicated to compatibility controllers so legacy response contracts do
* not leak into the primary application API surface.
*/
package com.iflytek.skillhub.compat.dto;

View file

@ -0,0 +1,5 @@
/**
* Compatibility endpoints and helpers that expose SkillHub data using
* conventions expected by external or legacy clients.
*/
package com.iflytek.skillhub.compat;

View file

@ -8,6 +8,10 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* Enables asynchronous event handling and other background execution features used by the
* application module.
*/
@Configuration
@EnableAsync
public class AsyncConfig {

View file

@ -8,6 +8,10 @@ import org.springframework.context.annotation.Configuration;
import java.time.Clock;
/**
* Wires application-level Spring beans that adapt configurable infrastructure into domain-facing
* ports.
*/
@Configuration
public class DomainBeanConfig {

View file

@ -8,6 +8,9 @@ import org.springframework.context.annotation.Configuration;
import java.util.List;
/**
* OpenAPI metadata configuration for generated API documentation.
*/
@Configuration
public class OpenApiConfig {

View file

@ -5,6 +5,9 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Registers MVC interceptors related to request rate limiting.
*/
@Configuration
public class WebMvcRateLimitConfig implements WebMvcConfigurer {

View file

@ -0,0 +1,5 @@
/**
* Spring configuration properties and lightweight application wiring for the
* web layer.
*/
package com.iflytek.skillhub.config;

View file

@ -16,6 +16,10 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Endpoints for initiating, verifying, and confirming account merge flows
* across multiple identities owned by the same user.
*/
@RestController
@RequestMapping("/api/v1/account/merge")
public class AccountMergeController extends BaseApiController {

View file

@ -38,6 +38,13 @@ import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Authentication-facing HTTP endpoints.
*
* <p>This controller keeps transport concerns at the boundary and delegates the
* actual authentication, session bootstrap, and direct-login workflows to
* dedicated application or auth services.
*/
@RestController
@RequestMapping("/api/v1/auth")
public class AuthController extends BaseApiController {
@ -68,6 +75,10 @@ public class AuthController extends BaseApiController {
this.userAccountRepository = userAccountRepository;
}
/**
* Returns the current authenticated principal and refreshes the session if
* the persisted user state has diverged from the in-session snapshot.
*/
@GetMapping("/me")
public ApiResponse<AuthMeResponse> me(@AuthenticationPrincipal PlatformPrincipal principal,
Authentication authentication,
@ -103,18 +114,32 @@ public class AuthController extends BaseApiController {
return ok("response.success.read", AuthMeResponse.from(principal));
}
/**
* Lists browser-based authentication providers that can initiate an OAuth
* login flow for the current client.
*/
@GetMapping("/providers")
public ApiResponse<List<AuthProviderResponse>> providers(
@RequestParam(name = "returnTo", required = false) String returnTo) {
return ok("response.success.read", authMethodCatalog.listOAuthProviders(returnTo));
}
/**
* Lists all authentication methods exposed to the UI, including direct and
* OAuth-based flows.
*/
@GetMapping("/methods")
public ApiResponse<List<AuthMethodResponse>> methods(
@RequestParam(name = "returnTo", required = false) String returnTo) {
return ok("response.success.read", authMethodCatalog.listMethods(returnTo));
}
/**
* Rebuilds an authenticated session from an upstream identity assertion.
*
* <p>This endpoint is used by trusted frontends or gateway flows that have
* already authenticated the user elsewhere.
*/
@PostMapping("/session/bootstrap")
@RateLimit(category = "auth-session-bootstrap", authenticated = 30, anonymous = 15, windowSeconds = 60)
public ApiResponse<AuthMeResponse> bootstrapSession(@Valid @RequestBody SessionBootstrapRequest request,
@ -125,6 +150,10 @@ public class AuthController extends BaseApiController {
);
}
/**
* Executes a direct-login flow and establishes a first-party web session on
* success.
*/
@PostMapping("/direct/login")
@RateLimit(category = "auth-direct-login", authenticated = 20, anonymous = 10, windowSeconds = 60)
public ApiResponse<AuthMeResponse> directLogin(@Valid @RequestBody DirectLoginRequest request,

View file

@ -3,6 +3,9 @@ package com.iflytek.skillhub.controller;
import com.iflytek.skillhub.dto.ApiResponse;
import com.iflytek.skillhub.dto.ApiResponseFactory;
/**
* Minimal controller base class that centralizes access to the standard API response factory.
*/
public abstract class BaseApiController {
private final ApiResponseFactory responseFactory;

View file

@ -10,6 +10,9 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* API endpoints for the CLI-style device authorization flow.
*/
@RestController
@RequestMapping("/api/v1/auth/device")
public class DeviceAuthController extends BaseApiController {

View file

@ -14,6 +14,10 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Browser-side endpoint that lets an authenticated user authorize a pending
* device code and records the operation in the audit log.
*/
@RestController
@RequestMapping("/api/v1/device")
public class DeviceAuthWebController extends BaseApiController {

View file

@ -7,6 +7,9 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Minimal liveness endpoint used by tests, probes, and basic uptime checks.
*/
@RestController
@RequestMapping("/api/v1")
public class HealthController extends BaseApiController {

View file

@ -23,6 +23,9 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* HTTP endpoints for local account registration, login, and password changes.
*/
@RestController
@RequestMapping("/api/v1/auth/local")
public class LocalAuthController extends BaseApiController {

View file

@ -19,6 +19,9 @@ import org.springframework.web.bind.annotation.*;
import java.time.Instant;
import java.util.List;
/**
* Self-service API token management endpoints for authenticated users.
*/
@RestController
@RequestMapping("/api/v1/tokens")
public class TokenController extends BaseApiController {

View file

@ -16,6 +16,10 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Administrative skill-governance endpoints reserved for platform-level
* moderation actions such as hide and unhide.
*/
@RestController
@RequestMapping("/api/v1/admin/skills")
public class AdminSkillController extends BaseApiController {

View file

@ -23,6 +23,10 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* Administrative endpoints for reviewing and resolving user-submitted skill
* reports.
*/
@RestController
@RequestMapping("/api/v1/admin/skill-reports")
public class AdminSkillReportController extends BaseApiController {

View file

@ -11,6 +11,9 @@ import org.springframework.web.bind.annotation.*;
import java.time.Instant;
/**
* Read-only audit log endpoints for auditors and super administrators.
*/
@RestController
@RequestMapping("/api/v1/admin/audit-logs")
public class AuditLogController extends BaseApiController {

View file

@ -15,6 +15,10 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
/**
* Administrative endpoints for listing users and mutating user roles or
* account status.
*/
@RestController
@RequestMapping("/api/v1/admin/users")
public class UserManagementController extends BaseApiController {

View file

@ -0,0 +1,5 @@
/**
* Administrative controllers that expose platform-level management operations
* such as audit access, moderation, and user governance.
*/
package com.iflytek.skillhub.controller.admin;

View file

@ -0,0 +1,5 @@
/**
* HTTP controllers for authentication, profile management, and public API
* endpoints that do not belong to a more specialized sub-area.
*/
package com.iflytek.skillhub.controller;

View file

@ -23,6 +23,10 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* Portal endpoints that expose governance dashboards, inbox items, activity,
* and user-facing governance notifications.
*/
@RestController
@RequestMapping({"/api/v1/governance", "/api/web/governance"})
public class GovernanceController extends BaseApiController {

View file

@ -14,6 +14,10 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Portal endpoints scoped to the current authenticated user, such as owned and
* starred skill listings.
*/
@RestController
@RequestMapping({"/api/v1/me", "/api/web/me"})
public class MeController extends BaseApiController {

View file

@ -18,6 +18,10 @@ import java.util.Comparator;
import java.util.List;
import java.util.Map;
/**
* Namespace portal endpoints for discovery, membership management, and
* namespace governance operations.
*/
@RestController
@RequestMapping({"/api/v1", "/api/web"})
public class NamespaceController extends BaseApiController {

View file

@ -40,6 +40,10 @@ import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
import java.util.Set;
/**
* Promotion workflow endpoints that expose submission, review, and query
* operations for cross-namespace promotion requests.
*/
@RestController
@RequestMapping({"/api/v1/promotions", "/api/web/promotions"})
public class PromotionController extends BaseApiController {

View file

@ -41,6 +41,10 @@ import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
import java.util.Set;
/**
* Endpoints for submitting, browsing, approving, rejecting, and withdrawing
* review tasks.
*/
@RestController
@RequestMapping({"/api/v1/reviews", "/api/web/reviews"})
public class ReviewController extends BaseApiController {

View file

@ -34,6 +34,10 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Read-oriented skill endpoints for detail pages, lifecycle inspection, file
* browsing, version resolution, and download delivery.
*/
@RestController
@RequestMapping({"/api/v1/skills", "/api/web/skills"})
public class SkillController extends BaseApiController {
@ -53,6 +57,10 @@ public class SkillController extends BaseApiController {
this.metrics = metrics;
}
/**
* Returns the viewer-specific projection of a skill, including lifecycle
* pointers and interaction permissions derived from the caller context.
*/
@GetMapping("/{namespace}/{slug}")
public ApiResponse<SkillDetailResponse> getSkillDetail(
@PathVariable String namespace,
@ -90,6 +98,10 @@ public class SkillController extends BaseApiController {
return ok("response.success.read", response);
}
/**
* Lists versions visible to the caller rather than every persisted version
* of the skill.
*/
@GetMapping("/{namespace}/{slug}/versions")
public ApiResponse<PageResponse<SkillVersionResponse>> listVersions(
@PathVariable String namespace,
@ -120,6 +132,10 @@ public class SkillController extends BaseApiController {
return ok("response.success.read", response);
}
/**
* Returns metadata for a concrete version that the current caller is
* allowed to inspect.
*/
@GetMapping("/{namespace}/{slug}/versions/{version}")
public ApiResponse<SkillVersionDetailResponse> getVersionDetail(
@PathVariable String namespace,
@ -150,6 +166,10 @@ public class SkillController extends BaseApiController {
return ok("response.success.read", response);
}
/**
* Lists packaged files for a concrete version after visibility checks have
* been applied.
*/
@GetMapping("/{namespace}/{slug}/versions/{version}/files")
public ApiResponse<List<SkillFileResponse>> listFiles(
@PathVariable String namespace,
@ -208,6 +228,10 @@ public class SkillController extends BaseApiController {
return ok("response.success.read", response);
}
/**
* Streams a single packaged file directly from object storage through the
* application API.
*/
@GetMapping("/{namespace}/{slug}/versions/{version}/file")
public ResponseEntity<InputStreamResource> getFileContent(
@PathVariable String namespace,
@ -254,6 +278,10 @@ public class SkillController extends BaseApiController {
.body(new InputStreamResource(content));
}
/**
* Resolves a human-facing version selector to the exact version that would
* be downloaded by the caller.
*/
@GetMapping("/{namespace}/{slug}/resolve")
public ApiResponse<ResolveVersionResponse> resolveVersion(
@PathVariable String namespace,

View file

@ -29,6 +29,10 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Endpoints that mutate skill lifecycle state, including archive, unarchive,
* withdraw-review, delete-version, and rerelease operations.
*/
@RestController
@RequestMapping({"/api/v1/skills", "/api/web/skills"})
public class SkillLifecycleController extends BaseApiController {

View file

@ -19,6 +19,12 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
/**
* Upload endpoints for skill packages.
*
* <p>The controller is responsible for archive extraction and request shaping,
* while the domain service owns all publication validation and state changes.
*/
@RestController
@RequestMapping({"/api/v1/skills", "/api/web/skills"})
public class SkillPublishController extends BaseApiController {
@ -37,6 +43,10 @@ public class SkillPublishController extends BaseApiController {
this.skillHubMetrics = skillHubMetrics;
}
/**
* Publishes an uploaded package into the target namespace after archive
* extraction and visibility parsing.
*/
@PostMapping("/{namespace}/publish")
@RateLimit(category = "publish", authenticated = 10, anonymous = 0)
public ApiResponse<PublishResponse> publish(

View file

@ -12,6 +12,9 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import java.util.Optional;
/**
* Endpoints for reading and mutating the current user's rating on a skill.
*/
@RestController
@RequestMapping({"/api/v1/skills", "/api/web/skills"})
public class SkillRatingController extends BaseApiController {

View file

@ -19,6 +19,9 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Endpoints that let authenticated users report a skill for moderation.
*/
@RestController
@RequestMapping({"/api/v1/skills", "/api/web/skills"})
public class SkillReportController extends BaseApiController {

View file

@ -11,6 +11,10 @@ import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* Portal search endpoint that adapts HTTP query parameters to the search
* application service and visibility scope.
*/
@RestController
@RequestMapping({"/api/web/skills"})
public class SkillSearchController extends BaseApiController {

View file

@ -8,6 +8,9 @@ import com.iflytek.skillhub.domain.social.SkillStarService;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
/**
* Endpoints for starring, unstarring, and checking star state on a skill.
*/
@RestController
@RequestMapping({"/api/v1/skills", "/api/web/skills"})
public class SkillStarController extends BaseApiController {

View file

@ -16,6 +16,9 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Endpoints for reading and mutating named tags that point to skill versions.
*/
@RestController
@RequestMapping({
"/api/v1/skills/{namespace}/{slug}/tags",

View file

@ -0,0 +1,5 @@
/**
* Primary portal-facing API controllers for namespaces, skills, review flows,
* search, and other end-user operations.
*/
package com.iflytek.skillhub.controller.portal;

View file

@ -14,6 +14,10 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Builds a publishable package model from multipart form uploads while enforcing package safety
* and size constraints.
*/
@Component
public class MultipartPackageExtractor {

View file

@ -17,6 +17,9 @@ import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* Extracts zip uploads into validated package entries that can be consumed by the publish flow.
*/
@Component
public class ZipPackageExtractor {

View file

@ -0,0 +1,5 @@
/**
* Controller support utilities for multipart parsing, archive extraction, and
* other transport-specific request preparation concerns.
*/
package com.iflytek.skillhub.controller.support;

View file

@ -0,0 +1,5 @@
/**
* Application DTOs used to keep HTTP request and response contracts separate
* from domain entities.
*/
package com.iflytek.skillhub.dto;

View file

@ -2,6 +2,9 @@ package com.iflytek.skillhub.exception;
import org.springframework.http.HttpStatus;
/**
* Application-layer exception mapped to HTTP 400 with a localized error code.
*/
public class BadRequestException extends LocalizedException {
public BadRequestException(String messageCode, Object... messageArgs) {

View file

@ -2,6 +2,9 @@ package com.iflytek.skillhub.exception;
import org.springframework.http.HttpStatus;
/**
* Application-layer exception mapped to HTTP 403 with a localized error code.
*/
public class ForbiddenException extends LocalizedException {
public ForbiddenException(String messageCode, Object... messageArgs) {

View file

@ -23,6 +23,10 @@ import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* Translates application, domain, auth, and infrastructure exceptions into the platform's JSON API
* error envelope.
*/
@RestControllerAdvice
public class GlobalExceptionHandler {

View file

@ -2,6 +2,9 @@ package com.iflytek.skillhub.exception;
import org.springframework.http.HttpStatus;
/**
* Common contract for errors that can be rendered as localized API responses.
*/
public interface LocalizedError {
String messageCode();

View file

@ -2,6 +2,9 @@ package com.iflytek.skillhub.exception;
import org.springframework.http.HttpStatus;
/**
* Base class for application-layer exceptions that carry a localized message code and HTTP status.
*/
public abstract class LocalizedException extends RuntimeException implements LocalizedError {
private final String messageCode;

View file

@ -2,6 +2,9 @@ package com.iflytek.skillhub.exception;
import org.springframework.http.HttpStatus;
/**
* Application-layer exception mapped to HTTP 401 with a localized error code.
*/
public class UnauthorizedException extends LocalizedException {
public UnauthorizedException(String messageCode, Object... messageArgs) {

View file

@ -0,0 +1,5 @@
/**
* Application-level exception translation and localized error payload support
* for the HTTP boundary.
*/
package com.iflytek.skillhub.exception;

View file

@ -23,6 +23,9 @@ import org.springframework.security.web.context.HttpSessionSecurityContextReposi
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* Projects the authenticated principal into request attributes consumed by the controller layer.
*/
@Component
public class AuthContextFilter extends OncePerRequestFilter {

View file

@ -16,6 +16,13 @@ import java.time.Instant;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
/**
* Prevents duplicate execution of mutating HTTP requests identified by
* {@code X-Request-Id}.
*
* <p>Redis is treated as the fast-path cache, while PostgreSQL remains the
* durable source of truth when cache access fails.
*/
@Component
public class IdempotencyInterceptor implements HandlerInterceptor {
@ -38,6 +45,10 @@ public class IdempotencyInterceptor implements HandlerInterceptor {
this.clock = clock;
}
/**
* Rejects duplicate mutating requests before controller execution and
* creates a processing marker for first-seen request identifiers.
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String method = request.getMethod();
@ -94,6 +105,10 @@ public class IdempotencyInterceptor implements HandlerInterceptor {
return true;
}
/**
* Finalizes the idempotency record with the observed response status once
* request processing has completed.
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
String method = request.getMethod();

View file

@ -13,6 +13,10 @@ import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.UUID;
/**
* Ensures every request has a request identifier for logs, responses, and downstream audit
* correlation.
*/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class RequestIdFilter extends OncePerRequestFilter {

View file

@ -19,6 +19,9 @@ import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
* Logs inbound HTTP requests and responses with truncation suitable for operational debugging.
*/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE + 1)
public class RequestLoggingFilter extends OncePerRequestFilter {

View file

@ -0,0 +1,5 @@
/**
* Servlet filters and MVC interceptors that enrich requests with cross-cutting
* concerns such as logging, idempotency, and caller context.
*/
package com.iflytek.skillhub.filter;

View file

@ -7,6 +7,10 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionalEventListener;
/**
* Updates denormalized skill rating counters when rating events are emitted by
* the social domain.
*/
@Component
public class SkillRatingEventListener {
private final JdbcTemplate jdbcTemplate;

View file

@ -8,6 +8,9 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionalEventListener;
/**
* Keeps the stored star count in sync with the star/unstar event stream.
*/
@Component
public class SkillStarEventListener {
private final JdbcTemplate jdbcTemplate;

View file

@ -0,0 +1,5 @@
/**
* Application event listeners that react to domain events to update read-side
* counters and other eventually consistent projections.
*/
package com.iflytek.skillhub.listener;

View file

@ -3,6 +3,9 @@ package com.iflytek.skillhub.metrics;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.stereotype.Component;
/**
* Small facade over Micrometer that centralizes metric names and tags used by backend flows.
*/
@Component
public class SkillHubMetrics {

View file

@ -0,0 +1,5 @@
/**
* Metrics helpers used to publish application and product telemetry from the
* web layer.
*/
package com.iflytek.skillhub.metrics;

View file

@ -0,0 +1,7 @@
/**
* Application-layer orchestration for the SkillHub backend.
*
* <p>This module adapts HTTP requests, security context, and DTO mapping to the
* domain-layer services exposed by the other backend modules.
*/
package com.iflytek.skillhub;

View file

@ -16,6 +16,10 @@ import javax.crypto.spec.SecretKeySpec;
import org.springframework.http.ResponseCookie;
import org.springframework.stereotype.Component;
/**
* Assigns stable anonymous identities for download rate limiting by combining client IP data with
* a signed cookie.
*/
@Component
public class AnonymousDownloadIdentityService {

View file

@ -5,6 +5,9 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.stereotype.Component;
/**
* Resolves the best-effort client IP address from proxy-aware request headers.
*/
@Component
public class ClientIpResolver {

View file

@ -7,6 +7,9 @@ import java.util.Deque;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
/**
* Test-profile rate limiter that keeps sliding-window counters in memory.
*/
@Component
@Profile("test")
public class InMemorySlidingWindowRateLimiter implements RateLimiter {

View file

@ -5,6 +5,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Declares per-endpoint rate-limit settings for authenticated and anonymous callers.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {

View file

@ -15,6 +15,10 @@ import org.springframework.web.servlet.HandlerMapping;
import java.util.Map;
/**
* Enforces the {@link RateLimit} annotation by resolving caller identity and delegating quota
* checks to the configured rate limiter implementation.
*/
@Component
public class RateLimitInterceptor implements HandlerInterceptor {

View file

@ -1,5 +1,8 @@
package com.iflytek.skillhub.ratelimit;
/**
* Contract for key-based rate limiter implementations used by API interceptors.
*/
public interface RateLimiter {
boolean tryAcquire(String key, int limit, int windowSeconds);

View file

@ -10,6 +10,9 @@ import org.springframework.stereotype.Component;
import java.util.Collections;
/**
* Production rate limiter backed by Redis and a Lua script for atomic sliding-window checks.
*/
@Component
@Profile("!test")
public class RedisSlidingWindowRateLimiter implements RateLimiter {

View file

@ -0,0 +1,5 @@
/**
* Rate-limiting annotations, interceptors, and implementations used to
* protect public APIs from abuse.
*/
package com.iflytek.skillhub.ratelimit;

View file

@ -18,6 +18,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
* Custom query repository that builds pageable admin-user search results with optional filters.
*/
@Repository
public class AdminUserSearchRepository {

View file

@ -0,0 +1,5 @@
/**
* Application-specific query repositories that package read models tailored to
* web and administration use cases.
*/
package com.iflytek.skillhub.repository;

View file

@ -15,6 +15,9 @@ import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* Converts authorization failures on API routes into the platform's standard JSON error envelope.
*/
@Component
public class ApiAccessDeniedHandler implements AccessDeniedHandler {

View file

@ -15,6 +15,9 @@ import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* Converts unauthenticated API access attempts into a consistent JSON 401 response.
*/
@Component
public class ApiAuthenticationEntryPoint implements AuthenticationEntryPoint {

View file

@ -8,6 +8,9 @@ import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
/**
* Tracks repeated authentication failures and throttles abusive identifiers or client addresses.
*/
@Service
public class AuthFailureThrottleService {

View file

@ -8,6 +8,9 @@ import java.util.stream.Collectors;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
/**
* Applies lightweight redaction rules before sensitive strings are written to logs.
*/
@Component
public class SensitiveLogSanitizer {

View file

@ -0,0 +1,5 @@
/**
* Web security helpers that translate authorization failures, sanitize logs,
* and coordinate security-specific application behavior.
*/
package com.iflytek.skillhub.security;

View file

@ -13,6 +13,10 @@ import java.time.Instant;
import java.util.Collection;
import java.util.List;
/**
* Read-only application service that queries audit logs with dynamic filtering
* tailored to administration screens.
*/
@Service
public class AdminAuditLogAppService {

View file

@ -17,6 +17,10 @@ import java.util.stream.Collectors;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
/**
* Application service that enriches raw skill report records with skill and
* namespace context required by admin UIs.
*/
@Service
public class AdminSkillReportAppService {

View file

@ -29,6 +29,10 @@ import java.util.TreeSet;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Administrative user-management application service built around the main
* search and mutation use cases exposed by the admin API.
*/
@Service
public class AdminUserAppService {

View file

@ -24,6 +24,10 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* Alternative user-management aggregation service that combines user records
* with role bindings for management-oriented views.
*/
@Service
public class AdminUserManagementService {

View file

@ -15,6 +15,10 @@ import java.util.List;
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties;
import org.springframework.stereotype.Service;
/**
* Builds the catalog of authentication methods and OAuth providers that the UI
* can render dynamically.
*/
@Service
public class AuthMethodCatalog {

View file

@ -12,6 +12,10 @@ import java.util.Map;
import java.util.function.Function;
import org.springframework.stereotype.Service;
/**
* Dispatches direct-login requests to a configured provider and then binds the
* resulting principal to the current HTTP session.
*/
@Service
public class DirectAuthService {

View file

@ -30,6 +30,12 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
/**
* Application-facing aggregation service for the governance workbench.
*
* <p>It joins review, promotion, report, namespace, and audit sources into the
* composite read models consumed by governance screens.
*/
@Service
public class GovernanceWorkbenchAppService {
@ -75,6 +81,10 @@ public class GovernanceWorkbenchAppService {
this.adminAuditLogAppService = adminAuditLogAppService;
}
/**
* Returns top-level counts for the governance dashboard, scoped by the
* caller's namespace and platform roles.
*/
public GovernanceSummaryResponse getSummary(String userId,
Map<Long, NamespaceRole> namespaceRoles,
Set<String> platformRoles) {
@ -89,6 +99,10 @@ public class GovernanceWorkbenchAppService {
);
}
/**
* Builds the governance inbox by combining pending reviews, promotions, and
* reports that the caller is allowed to see.
*/
public PageResponse<GovernanceInboxItemResponse> listInbox(String userId,
Map<Long, NamespaceRole> namespaceRoles,
Set<String> platformRoles,
@ -121,6 +135,10 @@ public class GovernanceWorkbenchAppService {
return new PageResponse<>(items.subList(fromIndex, toIndex), items.size(), page, size);
}
/**
* Returns audit-derived governance activity entries for callers with
* platform-wide visibility.
*/
public PageResponse<GovernanceActivityItemResponse> listActivity(Set<String> platformRoles, int page, int size) {
if (!canReadActivity(platformRoles)) {
return new PageResponse<>(List.of(), 0, page, size);

View file

@ -25,6 +25,10 @@ import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Application service that assembles the current user's owned and starred
* skill lists with lifecycle context.
*/
@Service
public class MySkillAppService {
private final SkillRepository skillRepository;

View file

@ -19,6 +19,10 @@ import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Finds candidate users that can be invited into a namespace while excluding
* existing members and immutable namespaces.
*/
@Service
public class NamespaceMemberCandidateService {

View file

@ -13,6 +13,10 @@ import java.util.Map;
import java.util.function.Function;
import org.springframework.stereotype.Service;
/**
* Restores a platform session from a passive authenticator and persists the
* resulting principal into Spring Security's session context.
*/
@Service
public class SessionBootstrapService {

View file

@ -23,6 +23,10 @@ import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Application service that adapts search queries to the search backend and
* enriches results with authoritative skill metadata and viewer permissions.
*/
@Service
public class SkillSearchAppService {

View file

@ -0,0 +1,5 @@
/**
* Application services that aggregate multiple domain services or repositories
* for controller-friendly use cases.
*/
package com.iflytek.skillhub.service;

View file

@ -10,6 +10,10 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.Clock;
import java.time.Instant;
/**
* Periodic maintenance task that expires old idempotency records and marks stale processing
* entries as failed.
*/
@Component
public class IdempotencyCleanupTask {

View file

@ -0,0 +1,4 @@
/**
* Scheduled background tasks that maintain read models and operational data.
*/
package com.iflytek.skillhub.task;

View file

@ -0,0 +1,5 @@
/**
* Authentication bootstrap helpers that restore session state from existing
* request context without forcing an explicit login step.
*/
package com.iflytek.skillhub.auth.bootstrap;

View file

@ -9,6 +9,9 @@ import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* Provides the shared Redis template used by authentication and other cross-cutting services.
*/
@Configuration
public class RedisTemplateConfig {

View file

@ -29,6 +29,10 @@ import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWrite
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
/**
* Central Spring Security configuration for browser sessions, API tokens, and
* public versus protected endpoints.
*/
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@ -75,6 +79,13 @@ public class SecurityConfig {
this.mockAuthFilterProvider = mockAuthFilterProvider;
}
/**
* Builds the ordered security filter chain used by both browser and API
* clients.
*
* <p>The chain mixes session-based authentication, bearer token support,
* CSRF rules for browser traffic, and method-level authorization.
*/
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
var csrfHandler = new CsrfTokenRequestAttributeHandler();
@ -210,6 +221,10 @@ public class SecurityConfig {
return http.build();
}
/**
* Provides the password encoder shared by local credentials and bootstrap
* flows.
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12);

View file

@ -0,0 +1,5 @@
/**
* Spring Security and infrastructure configuration for authentication and
* authorization concerns.
*/
package com.iflytek.skillhub.auth.config;

Some files were not shown because too many files have changed in this diff Show more