Files
full/apps/base/initial/README.md

559 lines
20 KiB
Markdown
Raw Normal View History

<EFBFBD><EFBFBD># Initial Service
[![Go Version](https://img.shields.io/badge/Go-1.25.1-blue.svg)](https://golang.org/)
[![License](https://img.shields.io/badge/License-Internal-red.svg)](LICENSE)
[![Build Status](https://img.shields.io/badge/Build-Passing-green.svg)](https://git.apinb.com/bsm-apps/initial)
N*Nؚ'`<60><>0<>SibU\<5C>v<EFBFBD>_ g<>R <0C><>W<EFBFBD>N gRPC <00>T HTTP Gateway <00>g<EFBFBD>g <0C><>c<EFBFBD>O<EFBFBD>^(uM<75>n<6E>{t0Hr,g<>f<EFBFBD>e<EFBFBD>h<EFBFBD>g0<>V<EFBFBD>[0W:SpencI{<7B>W@x g<>R<EFBFBD>R<EFBFBD><52>0
## <> yr'`
- **=<3D>'<27> M<>n<6E>{t**: Y<>^(u0Ys^<5E>SM<53>n<6E>Spe<70>{t
- **=<3D><><EFBFBD> Hr,g<>c6R**: zf<7A><66><EFBFBD>^(uHr,g<>f<EFBFBD>e<EFBFBD>h<EFBFBD>g
- **<<3C> <0A> 0Wtpenc**: <00>[te<74>vhQt<>V<EFBFBD>[<5B>T0W:SB\<5C>~penc
- **<<3C><><EFBFBD><0F> <00>|<7C>~penc**: up;m<>v<EFBFBD>|<7C>~h~{<7B>TR{|<7C>{t
- **<00>& ؚ'`<60><>**: RedisX[ + penc<6E>^OS
- **=<3D>3<EFBFBD> <00>[hVS**: <00>[te<74>vDocker/ec
- **=<3D><><EFBFBD> <00>v<EFBFBD>c**: eP<65>^<5E>h<EFBFBD>g<EFBFBD>TAPMƖb
- **=<3D><12> <00>[hQ**: <00>[<5B>U<EFBFBD>v<19><><EFBFBD>Yt<>T<EFBFBD><54>eQ<65><51><EFBFBD><EFBFBD>
## =<3D><><EFBFBD> <00>vU_
- [<00>_<1F>_<>Y](#-<00>_<1F>_<>Y)
- [y<><79>v<EFBFBD>~<7E>g](#-y<><79>v<EFBFBD>~<7E>g)
- [8h<38>_<EFBFBD>R<EFBFBD><52>](#-8h<38>_<EFBFBD>R<EFBFBD><52>)
- [API<00>ech](#-api<00>ech)
- [_<>ScWS](#-_<>ScWS)
- [<00><>r<72><7F>f](#-<00><>r<72><7F>f)
- ['`<60><>OS](#-'`<EFBFBD><EFBFBD>OS)
- [Ee<45><65><EFBFBD>cd<63>](#-Ee<45><65><EFBFBD>cd<63>)
## <> <00>_<1F>_<>Y
### <00>s<EFBFBD>X<EFBFBD><58>Bl
- **Go**: 1.25.1+
- **PostgreSQL**: 12+
- **Redis**: 6+
- **Docker**: 20.10+ (<00>S <09>)
- **Protocol Buffers**: 3.15+ (_<>S<00><><EFBFBD>)
### <00>_<1F><>
```bash
# KQ<4B><51>y<EFBFBD><79>v
git clone git.apinb.com/bsm-apps/initial.git
cd initial
# <00><>OV<4F>
make deps
# ub<>Nx
make proto
# <00>g<EFBFBD>^<5E>^(u
make build
# ЏL<D08F> g<>R
make run
```
### Docker <00>_<1F>/T<>R
```bash
# /T<>R<EFBFBD>[te g<>Rh
docker-compose up -d
# <00>g w g<>R<EFBFBD>r`
docker-compose ps
# <00>g w<>e<EFBFBD>_
docker-compose logs -f initial-service
```
## =<3D><><EFBFBD> y<><79>v<EFBFBD>~<7E>g
```
initial/
%%% =<3D><><EFBFBD> cmd/ # <00>^(u z<>^eQ<65>S
% %%% =<3D><><EFBFBD> main/ # ;N g<>ReQ<65>S
% %%% =<3D><><EFBFBD> cli/ # }T<>NL<4E><4C>]wQ
%%% =<3D><><EFBFBD> internal/ # <00>Q<EFBFBD><51>S
% %%% =<3D><><EFBFBD> cache/ # X[ g<>R
% %%% =<3D><><EFBFBD> config/ # M<>n<6E>{t
% %%% =<3D><><EFBFBD> excode/ # <19><><EFBFBD>x<>[IN
% %%% =<3D><><EFBFBD> impl/ # <00>[<5B>sB\
% %%% =<3D><><EFBFBD> logic/ # N<>R;<3B><><EFBFBD>
% % %%% =<3D><><EFBFBD> check/ # <00>h<EFBFBD>g<EFBFBD>vsQ;<3B><><EFBFBD>
% % %%% =<3D><><EFBFBD> data/ # penc<6E>vsQ;<3B><><EFBFBD>
% %%% =<3D><><EFBFBD> models/ # penc!j<>W
% %%% =<3D><><EFBFBD> server/ # g<>RhV<68>[<5B>s
%%% =<3D><><EFBFBD> pb/ # Protocol Buffers ub<>Nx
%%% =<3D><><EFBFBD> proto/ # Protocol Buffers <00>[IN<49>e<EFBFBD>N
%%% =<3D><><EFBFBD> swagger/ # API <00>ech
%%% =<3D><><EFBFBD> scripts/ # <1A>,g<>TSQL<00>e<EFBFBD>N
%%% =<3D><><EFBFBD> test/ # KmՋ<6D>e<EFBFBD>N
%%% =<3D><><EFBFBD> etc/ # M<>n<6E>e<EFBFBD>N
%%% =<3D>3<EFBFBD> Dockerfile # Docker \<5C><>P<EFBFBD>g<EFBFBD>^
%%% =<3D>3<EFBFBD> docker-compose.yml # Docker <>c
%%% =<3D>'<27> Makefile # <00>g<EFBFBD>^<1A>,g
%%% =<3D><><EFBFBD> README.md # y<><79>v<EFBFBD>ech
```
## =<3D>'<27> 8h<38>_<EFBFBD>R<EFBFBD><52>
### 1. <00>h<EFBFBD>g g<>R (Check Service)
#### <<3C><><EFBFBD> eP<65>^<5E>h<EFBFBD>g (Hello)
```protobuf
rpc Hello(Crc) returns (StatusReply)
```
- **<00>R<EFBFBD><52>**: g<>ReP<65>^<5E>r`<60>h<EFBFBD>g
- **yr'`**: <00><>eQ<65><51><EFBFBD><EFBFBD>0<>r`<EFBFBD>v<EFBFBD>c
- **(u<14>**: <1F>}<7D>GWa<57>hVeP<65>^<5E>h<EFBFBD>g0 g<>R<EFBFBD>S<EFBFBD>s
#### <00>&<0F> M<>n<6E>{t (Config)
```protobuf
rpc Config(ConfigRequest) returns (ConfigReply)
```
- **<00>R<EFBFBD><52>**: Y<>^(uM<75>n<6E>Spe<70>{t
- **yr'`**:
- /ecY<>d\O<>|<7C>~M<>n
- M<>nOHQ<48>~Yt
- ꁨR<EA81A8>S͑:g6R
- RedisX[<5B>R<1F>
#### =<3D><04> Hr,g<>f<EFBFBD>e (Updates)
```protobuf
rpc Updates(CheckForUpdatesRequest) returns (CheckForUpdatesReply)
```
- **<00>R<EFBFBD><52>**: zf<7A><66>Hr,g<>f<EFBFBD>e<EFBFBD>h<EFBFBD>g
- **yr'`**:
- Ys^<5E>S/ec (Windows/Linux/macOS)
- <00>g<EFBFBD>g:SR (amd64/arm64)
- Hr,g<>k<EFBFBD><6B><EFBFBD>{<7B>l
- <00>f<EFBFBD>e<EFBFBD>e<EFBFBD>N<EFBFBD>{t
### 2. penc g<>R (Data Service)
#### <<3C> <0A> <00>V<EFBFBD>[penc (Country)
```protobuf
rpc Country(Empty) returns (CountryReply)
```
- **penc**: ISO<00>Nx0'<27>^0<>e:S05u݋:S<>S
- **yr'`**: /T(u<>r`Ǐ<EFBFBD>n0<>c<EFBFBD>^OS
- **X[**: 24\<5C>e<65>gX[
#### =<3D><><EFBFBD><0F> 0W:Spenc (Areas)
```protobuf
rpc Areas(AreasRequest) returns (AreasReply)
```
- **<00>R<EFBFBD><52>**: B\<5C>~0W:Spenc<6E>g<EFBFBD><67>
- **B\<5C>~**: <00>V<EFBFBD>[ <00>! w/<00>] <00>! ^ <00>! :S/<00>S <00>! aNG<4E>
- **yr'`**:
- c<>V<EFBFBD>[[{ <09>
- B\<5C>~<7E>m<EFBFBD>^<5E>c6R
- <00>b<EFBFBD><62>/ec
#### <<3C><><EFBFBD><0F> <00>|<7C>~penc (Datas)
```protobuf
rpc Datas(Empty) returns (DatasReply)
```
- **<00>R<EFBFBD><52>**: <00>|<7C>~h~{<7B>TR{|<7C>{t
- **(u<14>**: N<>b <09>y<EFBFBD>0R{|h~{0<>|<7C>~M<>n
## =<3D><><EFBFBD> API<00>ech
### gRPC g<>R
| g<>R | <00>e<EFBFBD>l | <00>c<EFBFBD><63> | <00>z<EFBFBD>S |
|------|------|------|------|
| Check | Hello | eP<65>^<5E>h<EFBFBD>g | 12101 |
| Check | Config | M<>n<6E><7F><EFBFBD>S | 12101 |
| Check | Updates | <00>f<EFBFBD>e<EFBFBD>h<EFBFBD>g | 12101 |
| Data | Country | <00>V<EFBFBD>[penc | 12101 |
| Data | Areas | 0W:Spenc | 12101 |
| Data | Datas | <00>|<7C>~penc | 12101 |
### HTTP Gateway
| <00>z<EFBFBD>p | <00>e<EFBFBD>l | <00>c<EFBFBD><63> |
|------|------|------|
| `/initial.Check/Hello` | POST | eP<65>^<5E>h<EFBFBD>g |
| `/initial.Check/Config` | POST | <00><><EFBFBD>SM<53>n |
| `/initial.Check/Updates` | POST | <00>h<EFBFBD>g<EFBFBD>f<EFBFBD>e |
| `/initial.Data/Country` | POST | <00>V<EFBFBD>[Rh<52> |
| `/initial.Data/Areas` | POST | 0W:Spenc |
| `/initial.Data/Datas` | POST | <00>|<7C>~penc |
### Swagger <00>ech
- **,g0W**: http://localhost:12102/initial.swagger.json
- **(W<>~**: <1A>Ǐ HTTP Gateway <00><>[te<74>v API <00>ech
## =<3D><><EFBFBD><0F> _<>ScWS
### _<>S<EFBFBD>s<EFBFBD>X<EFBFBD><58>n
```bash
# <00>_<>S<EFBFBD>]wQ
make install-tools
# <00><>nGit<00><>P[
git config core.hooksPath .githooks
# /T<>R_<>S!j_
make dev
```
### <00>Nxub
```bash
# ub protobuf <00>Nx
make proto
# ub Swagger <00>ech
make swagger
```
### KmՋ
```bash
# ЏL<D08F>@b gKmՋ
make test
# KmՋ<6D><D58B><EFBFBD>v<EFBFBD>s
make test-coverage
# gRPC <00>R<EFBFBD><52>KmՋ
make test-grpc
# <00>Nx<>h<EFBFBD>g
make lint
# <00>[hQkb<6B>c
make security
```
### penc<6E>^<5E>{t
```bash
# R<>YSpenc<6E>^
make init-db
# Y<>Npenc<6E>^
make backup-db
```
## <> <00><>r<72><7F>f
### Docker <00><>r
```bash
# <00>g<EFBFBD>^\<5C><>P
make docker-build
# /T<>R g<>Rh
make docker-compose-up
# <00>g w<>e<EFBFBD>_
make docker-compose-logs
# \Pbk g<>R
make docker-compose-down
```
### u<>N<EFBFBD>s<EFBFBD>X<EFBFBD><58>r
1. **<00>s<EFBFBD>X<EFBFBD>QY**
```bash
# R<>^u<>NM<4E>n
cp etc/initial_dev.yaml etc/initial_prod.yaml
# <><7F>u<>NM<4E>n...
```
2. **penc<6E>^R<>YS**
```bash
# gbL<62>SQL<1A>,g
psql -h your-db-host -U postgres -d initial_db -f scripts/initial_country_202509081640.sql
psql -h your-db-host -U postgres -d initial_db -f scripts/initial_areas_202509081640.sql
```
3. ** g<>R/T<>R**
```bash
# <00>g<EFBFBD>^u<>NHr,g
make build-linux
# /T<>R g<>R
./build/initial-linux-amd64
```
### Kubernetes <00><>r
```yaml
# k8s-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: initial-service
spec:
replicas: 3
selector:
matchLabels:
app: initial-service
template:
metadata:
labels:
app: initial-service
spec:
containers:
- name: initial-service
image: initial:latest
ports:
- containerPort: 12101
- containerPort: 12102
env:
- name: SERVICE_ENV
value: "production"
```
## <00>& '`<60><>OS
### X[V{eu
| penc{|<7C>W | X[<5B>e<EFBFBD><65> | V{eu |
|----------|----------|------|
| M<>npenc | 10R<><52> | c<>^(u+OSX[ |
| <00>V<EFBFBD>[penc | 24\<5C>e | hQϑX[ |
| 0W:Spenc | 12\<5C>e | c<>V<EFBFBD>[X[ |
| <00>|<7C>~penc | 6\<5C>e | hQϑX[ |
### penc<6E>^OS
- **"}_OS**: sQ.<2E>W[<5B>k<EFBFBD>^<5E>z YT"}_
- **<00>g<EFBFBD><67>OS**: O(u CASE WHEN ۏL<DB8F>OHQ<48>~<7E>c<EFBFBD>^
- **ޏ<>c`l**: M<>nT<02><><76>c`l'Y\
- **<00><><EFBFBD>QR<>y**: /ec;N<>Npenc<6E>^M<>n
### <00>v<EFBFBD>cch
```bash
# g<>ReP<65>^<5E>h<EFBFBD>g
curl http://localhost:12102/health
# '`<60><>ch
curl http://localhost:12102/metrics
```
## =<3D>'<27> M<>n<6E><7F>f
### <00>s<EFBFBD>XM<58>n<6E>e<EFBFBD>N
```yaml
# etc/initial_prod.yaml
Service: initial
Port: 12101
# penc<6E>^M<>n
Databases:
Driver: postgres
Source:
- host=db-host user=postgres password=*** dbname=initial_db port=5432 sslmode=require
# X[M<>n
Cache: redis://username:password@redis-host:6379/0
# QsQM<51>n
Gateway:
Enable: true
Port: 12102
# <00>_ g<>RM<52>n
MicroService:
Enable: true
Registry: etcd://etcd-cluster:2379
# APM<00>v<EFBFBD>c
APM:
Platform: elasticAPM
Endpoint: http://apm-server:8200
```
### <00>s<EFBFBD>X<EFBFBD>
| <00>Sϑ T | <00>c<EFBFBD><63> | ؞<><D89E><P |
|--------|------|--------|
| `SERVICE_ENV` | ЏL<D08F><4C>s<EFBFBD>X | `development` |
| `CONFIG_FILE` | M<>n<6E>e<EFBFBD>N_ | `etc/initial_dev.yaml` |
| `LOG_LEVEL` | <00>e<EFBFBD>_<EFBFBD>~+R | `info` |
| `TZ` | <00>e:S<><53>n | `Asia/Shanghai` |
## =<3D><1B> Ee<45><65><EFBFBD>cd<63>
### 8^<5E><><EFBFBD>
1. ** g<>R/T<>R1Y%<25>**
```bash
# <00>h<EFBFBD>g<EFBFBD>z<EFBFBD>S`S(u
netstat -tlnp | grep :12101
# <00>h<EFBFBD>gM<67>n<6E>e<EFBFBD>N
make lint
```
2. **penc<6E><>c1Y%<25>**
```bash
# KmՋpenc<6E><>c
psql -h your-db-host -U postgres -d initial_db -c "SELECT 1;"
```
3. **Redisޏ<>c1Y%<25>**
```bash
# KmՋRedisޏ<>c
redis-cli -h your-redis-host ping
```
### <00>e<EFBFBD>_R<>g
```bash
# <00>g w g<>R<EFBFBD>e<EFBFBD>_
tail -f logs/initial.log
# <00>g w<19><><EFBFBD><EFBFBD>e<EFBFBD>_
grep ERROR logs/initial.log
# <00>g w'`<60><><EFBFBD>e<EFBFBD>_
grep "slow query" logs/initial.log
```
### '`<60><><03>O
1. **<00>QX[OS**
```bash
# <00>v<EFBFBD>c<EFBFBD>QX[O(u
go tool pprof http://localhost:6060/debug/pprof/heap
```
2. **CPUOS**
```bash
# CPU'`<60><>R<>g
go tool pprof http://localhost:6060/debug/pprof/profile
```
## =<3D><><EFBFBD> penc!j<>W
### 8h<38>_h<5F><68>~<7E>g
#### initial_config - M<>nh<7F>
```sql
CREATE TABLE initial_config (
id SERIAL PRIMARY KEY,
identity VARCHAR(255) NOT NULL,
app VARCHAR(255) NOT NULL,
os VARCHAR(255) DEFAULT '',
key TEXT DEFAULT '',
value TEXT DEFAULT '',
version BIGINT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
#### initial_apps - <00>^(uHr,gh<67>
```sql
CREATE TABLE initial_apps (
id SERIAL PRIMARY KEY,
identity VARCHAR(255) NOT NULL,
version VARCHAR(255) DEFAULT '',
app VARCHAR(255) DEFAULT '',
os VARCHAR(255) DEFAULT '',
arch VARCHAR(255) DEFAULT '',
summary TEXT DEFAULT '',
files TEXT DEFAULT '',
pubdate TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
#### initial_country - <00>V<EFBFBD>[h<>
```sql
CREATE TABLE initial_country (
id SERIAL PRIMARY KEY,
iso2 VARCHAR(2) UNIQUE NOT NULL,
iso3 VARCHAR(3) UNIQUE NOT NULL,
num_code VARCHAR(3),
phone_code VARCHAR(10),
currency VARCHAR(24) NOT NULL,
currency_symbol VARCHAR(24) NOT NULL,
region VARCHAR(24) NOT NULL,
name VARCHAR(255) NOT NULL,
local_name VARCHAR(255) NOT NULL,
timezones TEXT,
translations TEXT,
enabled BOOLEAN DEFAULT true,
sort_order INTEGER DEFAULT 0
);
```
## ><3E><1D> !<21>.scWS
### _<>SAm z
1. **Fork y<><79>v**
2. **R<>^yr'`R/e**: `git checkout -b feature/amazing-feature`
3. **<00>c<EFBFBD>N<EFBFBD>f9e**: `git commit -m 'Add amazing feature'`
4. **<00>c<01>R/e**: `git push origin feature/amazing-feature`
5. **R<>^ Pull Request**
### <00>N<03>
- u<><75>_ Go <00>[<5B>e<EFBFBD>N<03>
- O(u `gofmt` <h_S<>Nx
- <00>m<EFBFBD>R<EFBFBD>_<EFBFBD><5F><EFBFBD>v<EFBFBD><6C>T<EFBFBD>ech
- <>QUSCQKmՋ
### <00>c<EFBFBD><03>
```
type(scope): description
[optional body]
[optional footer]
```
{|<7C>W:
- `feat`: <00>e<EFBFBD>R<EFBFBD><52>
- `fix`: <00>O Ybug
- `docs`: <00>ech<63>f<EFBFBD>e
- `style`: <00>Nx<h_
- `refactor`: ͑<>g
- `test`: KmՋ
- `chore`: <00>g<EFBFBD> zb<><62><EFBFBD>R<EFBFBD>]wQ<77>v<EFBFBD>S<EFBFBD>R
## =<3D><><EFBFBD> <00><><EFBFBD>S<EFBFBD><53>
,gy<67><79>vǑ(u<>Q萸<51><E890B8>S<EFBFBD><53> <0C><>N<EFBFBD>O BSM <00>Q<EFBFBD><51>O(u0
## =<3D>e<EFBFBD> <00>V<1F>
- **\O<05>**: David Yan (david.yan@qq.com)
- **<00>~<7E>b<05>**: BSM _<>S<EFBFBD>V<1F>
- **y<><79>v0W@W**: [git.apinb.com/bsm-apps/initial](https://git.apinb.com/bsm-apps/initial)
## =<3D><17> <00>vsQ<73><51><EFBFBD>c
- [BSM SDK](https://git.apinb.com/bsm-sdk)
- [API <00>ech](https://docs.apinb.com/initial)
- [<><EE9598>S<EFBFBD><53>](https://git.apinb.com/bsm-apps/initial/issues)
---
<div align="center">
**P+ <00>Y<EFBFBD>gُ*Ny<4E><79>v<EFBFBD>[`O g.^<5E>R <0C><><EFBFBD><EFBFBD>~<7E>[N*Nfh<01>**
Made with d'<0F> by BSM Team
</div>