diff --git a/backend/.gitignore b/backend/.gitignore
new file mode 100644
index 0000000..fd7b564
--- /dev/null
+++ b/backend/.gitignore
@@ -0,0 +1,4 @@
+target/
+*.iml
+.idea/
+HELP.md
diff --git a/backend/pom.xml b/backend/pom.xml
new file mode 100644
index 0000000..1662a69
--- /dev/null
+++ b/backend/pom.xml
@@ -0,0 +1,104 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.3.5
+
+
+
+ com.xly
+ erp-backend
+ 0.0.1-SNAPSHOT
+ erp-backend
+ 小羚羊 ERP backend
+
+
+ 17
+ UTF-8
+ 3.5.9
+ 0.12.6
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+
+ com.baomidou
+ mybatis-plus-spring-boot3-starter
+ ${mybatis-plus.version}
+
+
+
+ com.mysql
+ mysql-connector-j
+ runtime
+
+
+
+ org.flywaydb
+ flyway-core
+
+
+ org.flywaydb
+ flyway-mysql
+
+
+
+ io.jsonwebtoken
+ jjwt-api
+ ${jjwt.version}
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ ${jjwt.version}
+ runtime
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ ${jjwt.version}
+ runtime
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.springframework.security
+ spring-security-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/backend/src/main/java/com/xly/erp/ErpApplication.java b/backend/src/main/java/com/xly/erp/ErpApplication.java
new file mode 100644
index 0000000..227f5e6
--- /dev/null
+++ b/backend/src/main/java/com/xly/erp/ErpApplication.java
@@ -0,0 +1,15 @@
+package com.xly.erp;
+
+import com.xly.erp.common.config.StubSecurityProperties;
+import com.xly.erp.common.config.TenantProperties;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+
+@SpringBootApplication
+@EnableConfigurationProperties({TenantProperties.class, StubSecurityProperties.class})
+public class ErpApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(ErpApplication.class, args);
+ }
+}
diff --git a/backend/src/main/java/com/xly/erp/common/config/MybatisPlusConfig.java b/backend/src/main/java/com/xly/erp/common/config/MybatisPlusConfig.java
new file mode 100644
index 0000000..2762add
--- /dev/null
+++ b/backend/src/main/java/com/xly/erp/common/config/MybatisPlusConfig.java
@@ -0,0 +1,9 @@
+package com.xly.erp.common.config;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@MapperScan("com.xly.erp.module.**.mapper")
+public class MybatisPlusConfig {
+}
diff --git a/backend/src/main/java/com/xly/erp/common/config/StubSecurityProperties.java b/backend/src/main/java/com/xly/erp/common/config/StubSecurityProperties.java
new file mode 100644
index 0000000..c037c31
--- /dev/null
+++ b/backend/src/main/java/com/xly/erp/common/config/StubSecurityProperties.java
@@ -0,0 +1,25 @@
+package com.xly.erp.common.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@ConfigurationProperties(prefix = "erp.security")
+public class StubSecurityProperties {
+ private String stubUserNo;
+ private String jwtSecret;
+
+ public String getStubUserNo() {
+ return stubUserNo;
+ }
+
+ public void setStubUserNo(String stubUserNo) {
+ this.stubUserNo = stubUserNo;
+ }
+
+ public String getJwtSecret() {
+ return jwtSecret;
+ }
+
+ public void setJwtSecret(String jwtSecret) {
+ this.jwtSecret = jwtSecret;
+ }
+}
diff --git a/backend/src/main/java/com/xly/erp/common/config/TenantProperties.java b/backend/src/main/java/com/xly/erp/common/config/TenantProperties.java
new file mode 100644
index 0000000..21d53d6
--- /dev/null
+++ b/backend/src/main/java/com/xly/erp/common/config/TenantProperties.java
@@ -0,0 +1,25 @@
+package com.xly.erp.common.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@ConfigurationProperties(prefix = "erp.tenant")
+public class TenantProperties {
+ private String brandsId;
+ private String subsidiaryId;
+
+ public String getBrandsId() {
+ return brandsId;
+ }
+
+ public void setBrandsId(String brandsId) {
+ this.brandsId = brandsId;
+ }
+
+ public String getSubsidiaryId() {
+ return subsidiaryId;
+ }
+
+ public void setSubsidiaryId(String subsidiaryId) {
+ this.subsidiaryId = subsidiaryId;
+ }
+}
diff --git a/backend/src/main/resources/application-test.yml b/backend/src/main/resources/application-test.yml
new file mode 100644
index 0000000..001459e
--- /dev/null
+++ b/backend/src/main/resources/application-test.yml
@@ -0,0 +1,9 @@
+spring:
+ flyway:
+ locations: filesystem:../sql/migrations
+ clean-disabled: true
+
+logging:
+ level:
+ org.springframework.jdbc.core: WARN
+ com.xly.erp: DEBUG
diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml
new file mode 100644
index 0000000..3687ac3
--- /dev/null
+++ b/backend/src/main/resources/application.yml
@@ -0,0 +1,35 @@
+spring:
+ application:
+ name: erp-backend
+ datasource:
+ url: jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_SCHEMA}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
+ username: ${DB_USER}
+ password: ${DB_PASSWORD}
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ flyway:
+ enabled: true
+ locations: filesystem:../sql/migrations
+ baseline-on-migrate: true
+
+server:
+ port: 8080
+ servlet:
+ context-path: /
+
+mybatis-plus:
+ mapper-locations: classpath:mapper/**/*.xml
+ configuration:
+ map-underscore-to-camel-case: false
+
+erp:
+ tenant:
+ brands-id: XLY
+ subsidiary-id: XLY
+ security:
+ stub-user-no: STUB_ADMIN
+ jwt-secret: ${JWT_SECRET}
+
+logging:
+ level:
+ root: INFO
+ com.xly.erp: DEBUG
diff --git a/backend/src/main/resources/logback-spring.xml b/backend/src/main/resources/logback-spring.xml
new file mode 100644
index 0000000..232b8af
--- /dev/null
+++ b/backend/src/main/resources/logback-spring.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/backend/src/test/java/com/xly/erp/SmokeTest.java b/backend/src/test/java/com/xly/erp/SmokeTest.java
new file mode 100644
index 0000000..d3f8b93
--- /dev/null
+++ b/backend/src/test/java/com/xly/erp/SmokeTest.java
@@ -0,0 +1,25 @@
+package com.xly.erp;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.test.context.ActiveProfiles;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
+@ActiveProfiles("test")
+class SmokeTest {
+
+ @Autowired
+ private JdbcTemplate jdbcTemplate;
+
+ @Test
+ void contextLoads_andFlywayApplied() {
+ Integer count = jdbcTemplate.queryForObject(
+ "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = 'tModule'",
+ Integer.class);
+ assertThat(count).isEqualTo(1);
+ }
+}