- Merge delta-force-guide-server into server/ subdirectory - Merge delta-force-guide-web into web/ subdirectory - Rename Java package com.onixbyte.deltaforceguide to com.onixbyte.ahsarahguide - Rename DeltaForceGuideApplication to AhsarahGuideApplication - Update all config files, Dockerfiles, and CI workflows - Update frontend display name and repo links - Update legal documents (EULA, PrivacyPolicy) - Create root-level CLAUDE.md, README.md, LICENCE, .gitignore, .gitattributes - Move CI workflows to root .gitea/workflows/ with working-directory - Delete .gitlab-ci.yml (legacy) - Preserve git history from both original repositories
8.1 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Monorepo Structure
server/— Java 21 + Spring Boot 3.5 + Gradle (Kotlin DSL) REST API backendweb/— React 19 + Vite 8 + TypeScript + Ant Design 6 + Tailwind CSS 4 frontend
Server
Coding Standards
- Style: Follow the Google Java Coding Style as the foundation.
- Indentation: Use 4 spaces — no tabs.
- Line length: Maximum 100 characters per line.
- Comments: All code comments must use British English spelling (e.g. "colour" not "color", "behaviour" not "behavior", "serialise" not "serialize", "analyse" not "analyze", "traveller" not "traveler").
Build & Test Commands
cd server
# Build the project (skip tests)
./gradlew build -x test
# Run all tests
./gradlew test
# Run a single test class
./gradlew test --tests "com.onixbyte.ahsarahguide.service.PasswordEncoderTest"
# Build the full JAR
./gradlew bootJar
The project uses Gradle with Java 21 (Amazon Corretto). Tests use JUnit 5 with the Spring Boot test framework, H2 in-memory database for test runtime, and Spring Security test support. Tests require an active dev profile.
Code Architecture
Ahsarah Guide Server — A REST API backend for managing firearm builds/modifications.
Package structure
com.onixbyte.ahsarahguide
├── client/ # External service clients (TokenClient for JWT)
├── config/ # Spring beans: Security, CORS, Cache/Redis, Jackson, MyBatis, Spring Data
├── controller/ # REST controllers (Firearm, Modification, Tag, Auth)
├── domain/
│ ├── converter/ # JPA attribute converters (FirearmTypeConverter)
│ ├── dto/ # Request/response records (FirearmRequest, ModificationResponse, etc.)
│ └── entity/ # JPA entities (Firearm, Modification, User, Accessory, Tuning)
├── enumeration/ # Enums (FirearmType)
├── exeption/ # BizException (custom runtime exception with HTTP status)
├── filter/ # TokenAuthenticationFilter (JWT auth via OncePerRequestFilter)
├── manager/ # Thin @Transactional wrappers around repositories
├── mapper/ # MyBatis mappers (configured but currently unused)
├── properties/ # @ConfigurationProperties records (Cors, Token, Cookie)
├── repository/ # Spring Data JPA repositories
├── security/
│ ├── authentication/ # Custom UsernamePasswordAuthentication impl
│ └── provider/ # UsernamePasswordAuthenticationProvider
├── service/ # Business logic layer (FirearmService, ModificationService, AuthService, etc.)
├── shared/ # Constants and utility classes (CookieName, CredentialProvider, JacksonModules)
└── utils/ # Helpers (DateTimeUtil)
Key design decisions
- JPA + native queries: Most CRUD uses Spring Data JPA. Native queries (in
ModificationRepository) handle JSONB tag filtering with Postgres@>operator. - Custom auth flow: JWT tokens in httpOnly cookies (
AccessToken). Spring Security with a customUsernamePasswordAuthenticationProviderandTokenAuthenticationFilter. Tokens are auto-renewed within 5 min of expiry. - JSONB storage:
Modification.tagsandModification.accessories(including nestedTuningobjects) are stored as JSONB columns using Hypersistence UtilsJsonType. - Strict layering: The call chain must follow
Controller → Service → Manager → Repository/Mapper. Skipping layers (e.g. Controller calling Manager directly, Service calling Repository directly) is not permitted. - DTOs as Java records: All request/response objects are immutable records with static
from()factory methods for entity→DTO conversion. - Flyway migrations: SQL migrations in
src/main/resources/db/migration/.
API endpoints
| Path | Methods | Auth |
|---|---|---|
/firearms |
GET, POST | GET public, POST requires auth |
/firearms/{id} |
GET, PUT, DELETE | GET public, PUT/DELETE requires auth |
/modifications |
GET, POST | GET public, POST requires auth |
/modifications/{id} |
GET, PUT, DELETE | GET public, PUT/DELETE requires auth |
/modifications/batch |
POST | Requires auth |
/modifications/batch-delete |
DELETE | Requires auth |
/tags |
GET | Public |
/auth/login |
POST | Public |
/auth/logout |
POST | Authenticated |
Commit convention
Conventional commits: feat:, chore:, fix:. Messages are in English, present tense imperative style.
Web
Commands
cd web
pnpm install # Install dependencies (pnpm required)
pnpm dev # Start Vite dev server
pnpm build # TypeScript check + Vite production build
pnpm build:tar # Build + tar.gz archive (used by CI)
pnpm preview # Preview production build locally
pnpm lint # ESLint
No test suite exists in this project.
Architecture
Chinese-language SPA for browsing and managing Ahsarah Guide (阿萨拉向导). The frontend talks to the Spring Boot backend via REST APIs.
App shell (src/main.tsx): React 19 + React Router 7 + Redux Toolkit + Ant Design 6 + Tailwind CSS 4. Wraps the router in Redux Provider → PersistGate (Redux Persist) → Ant Design StyleProvider/ConfigProvider (locale zh_CN).
Routing (src/router/index.tsx): Two layout groups:
HeroLayout(nav header + footer) for/,/firearms,/mod-codesEmptyLayout(minimal) for/loginAll page components are lazy-loaded viacreateBrowserRouter+lazy().
State (src/store/): Redux Toolkit with two slices — auth (current user) and firearms (paginated firearm list). State is persisted to localStorage or sessionStorage based on the VITE_REDUX_STORAGE env var. Use typed hooks from src/hooks/store.ts (useAppDispatch, useAppSelector).
API layer (src/api/): Axios instance (src/shared/web-client/) with base URL from VITE_API_BASE_URL, 10s timeout, and credentials. API modules: FirearmApi, ModificationApi, TagApi, AuthApi.
Pages:
FirearmsPage— paginated card grid with type filter, create/edit modals (admin-only), delete with popconfirmModCodesPage— paginated list with tag multi-select and firearmId query param filter, create/edit modals with nested accessory/tuning form listsLoginPage— simple username/password form, dispatchessetCurrentUseron success
Shared form components: FirearmForm and ModificationForm are reused by both create and edit modals. ModificationForm fetches all firearms for its weapon selector and supports a lockFirearmId prop that disables the selector (used when navigating from a specific firearm).
Type system (src/types/): Firearm with weapon stats, Modification with nested Accessory[] → Tuning[], Page<T> for paginated API responses, User for auth.
Vite config: Alias @ → ./src. Plugins: React, Tailwind CSS 4, port checker. Build uses rolldown with manual chunk splitting for React, Redux, Ant Design, React Router, and rc-* packages.
Styling: Tailwind CSS 4 with CSS layers (theme, base, antd, components, utilities). Responsive grid for mod code cards (1→2→3→4 columns). Prettier: 100 print width, no semicolons, double quotes, trailing commas ES5.
Environment variables
VITE_API_BASE_URL=/api # Backend API base URL
VITE_REDUX_STORAGE=local # "local" or "session" for Redux persistence
Contributing conventions
- User-facing copy, documentation, and code comments in British English
- Commit messages use
chore:prefix for dependency updates (per Dependabot config)