diff --git a/backend/pom.xml b/backend/pom.xml
new file mode 100644
index 0000000..963c923
--- /dev/null
+++ b/backend/pom.xml
@@ -0,0 +1,126 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.3.4
+
+
+
+ com.xly.erp
+ xly-erp-backend
+ 0.0.1-SNAPSHOT
+ jar
+ xly-erp-backend
+ 小羚羊 ERP 后端
+
+
+ 17
+ 17
+ 17
+ UTF-8
+ 3.5.7
+ 0.12.5
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+ org.springframework.security
+ spring-security-crypto
+
+
+
+ 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.projectlombok
+ lombok
+ true
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ ${env.DB_HOST}
+ ${env.DB_PORT}
+ ${env.DB_USER}
+ ${env.DB_PASSWORD}
+ ${env.DB_SCHEMA}
+ ${env.JWT_SECRET}
+
+
+
+
+
+
diff --git a/backend/src/main/java/com/xly/erp/Application.java b/backend/src/main/java/com/xly/erp/Application.java
new file mode 100644
index 0000000..87b3550
--- /dev/null
+++ b/backend/src/main/java/com/xly/erp/Application.java
@@ -0,0 +1,13 @@
+package com.xly.erp;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@MapperScan("com.xly.erp.module.*.mapper")
+public class Application {
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
diff --git a/backend/src/main/resources/application-test.yml b/backend/src/main/resources/application-test.yml
new file mode 100644
index 0000000..69e0d31
--- /dev/null
+++ b/backend/src/main/resources/application-test.yml
@@ -0,0 +1,18 @@
+spring:
+ datasource:
+ url: jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_SCHEMA}?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
+ username: ${DB_USER}
+ password: ${DB_PASSWORD}
+ flyway:
+ enabled: true
+ locations: filesystem:../sql/migrations
+
+jwt:
+ secret: ${JWT_SECRET:test-secret-please-replace-with-256bit-random-string-xxxxxxx}
+ ttl-sec: 7200
+
+logging:
+ level:
+ root: WARN
+ com.xly.erp: DEBUG
+ com.zaxxer.hikari: WARN
diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml
new file mode 100644
index 0000000..d08ab3b
--- /dev/null
+++ b/backend/src/main/resources/application.yml
@@ -0,0 +1,34 @@
+server:
+ port: 9090
+
+spring:
+ application:
+ name: xly-erp-backend
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_SCHEMA}?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
+ username: ${DB_USER}
+ password: ${DB_PASSWORD}
+ flyway:
+ enabled: true
+ locations: filesystem:../sql/migrations
+ baseline-on-migrate: true
+ baseline-version: 0
+ validate-on-migrate: true
+
+mybatis-plus:
+ configuration:
+ map-underscore-to-camel-case: false
+ log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
+ global-config:
+ db-config:
+ id-type: auto
+
+jwt:
+ secret: ${JWT_SECRET}
+ ttl-sec: 7200
+
+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..7c2338d
--- /dev/null
+++ b/backend/src/main/resources/logback-spring.xml
@@ -0,0 +1,14 @@
+
+
+
+
+ %d{HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%n
+
+
+
+
+
+
+
+
+
diff --git a/backend/src/test/java/com/xly/erp/ApplicationContextTest.java b/backend/src/test/java/com/xly/erp/ApplicationContextTest.java
new file mode 100644
index 0000000..cc7d10b
--- /dev/null
+++ b/backend/src/test/java/com/xly/erp/ApplicationContextTest.java
@@ -0,0 +1,26 @@
+package com.xly.erp;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.ApplicationContext;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+/**
+ * REQ-USR-001 — Boot smoke test:
+ * verifies Spring Boot context starts and Flyway has applied V1 against the
+ * MySQL schema configured via .env.local (DB_HOST/DB_PORT/DB_USER/DB_PASSWORD/DB_SCHEMA).
+ */
+@SpringBootTest
+@org.springframework.test.context.ActiveProfiles("test")
+class ApplicationContextTest {
+
+ @Autowired
+ private ApplicationContext ctx;
+
+ @Test
+ void contextLoads() {
+ assertNotNull(ctx, "Spring ApplicationContext should be initialised");
+ }
+}