From 0ad2f8a2b03fa28abc2c01e304f63aa9330215c9 Mon Sep 17 00:00:00 2001 From: Dmitri Date: Thu, 16 Apr 2026 09:07:21 +0200 Subject: [PATCH] rust --- .gitignore | 38 -------------- Cargo.toml | 6 +++ Dockerfile | 45 ---------------- README.md | 107 -------------------------------------- cmd/api/main.go | 11 ---- compose.yaml | 57 -------------------- example.env | 5 -- go.mod | 5 -- go.sum | 2 - internal/config/config.go | 61 ---------------------- internal/db/db.go | 1 - internal/db/postgres.go | 1 - src/main.rs | 3 ++ 13 files changed, 9 insertions(+), 333 deletions(-) delete mode 100644 .gitignore create mode 100644 Cargo.toml delete mode 100644 Dockerfile delete mode 100644 README.md delete mode 100644 cmd/api/main.go delete mode 100644 compose.yaml delete mode 100644 example.env delete mode 100644 go.mod delete mode 100644 go.sum delete mode 100644 internal/config/config.go delete mode 100644 internal/db/db.go delete mode 100644 internal/db/postgres.go create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore deleted file mode 100644 index ebe15f8..0000000 --- a/.gitignore +++ /dev/null @@ -1,38 +0,0 @@ -HELP.md -# Track jOOQ generated sources -!target/generated-sources/jooq/ -target/ -.mvn/wrapper/maven-wrapper.jar -!**/src/main/**/target/ -!**/src/test/**/target/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ -!**/src/main/**/build/ -!**/src/test/**/build/ - -### VS Code ### -.vscode/ -.env - - diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..bac0322 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rhythm_backend" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 34d9428..0000000 --- a/Dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -# ---- STAGE 1: Build ---- -# Use an OpenJDK image that matches the version you develop with. -# It contains the JDK, but not Maven. -FROM eclipse-temurin:25-jdk-jammy AS builder - -# Set the working directory -WORKDIR /app - -# ---- Caching Dependencies ---- -# First, copy the files that define the build, including the Maven Wrapper -COPY mvnw . -COPY .mvn .mvn -COPY pom.xml . - -# Make the wrapper executable -RUN chmod +x ./mvnw - -# Run a Maven command to download dependencies. -# Since pom.xml and wrapper files rarely change, this layer will be cached by Docker, -# speeding up subsequent builds significantly. -RUN ./mvnw dependency:go-offline - -# ---- Building the Application ---- -# Now, copy the source code. If only source code changes, the layers above are cached. -COPY src ./src - -# Build the application JAR using the Maven Wrapper -RUN ./mvnw clean package -DskipTests -Djooq.codegen.skip=true -Dflyway.skip=true - - -# ---- STAGE 2: Runtime ---- -# Use a lean Eclipse Temurin JRE image for a small and secure final container. -FROM eclipse-temurin:25-jre-jammy - -# Set the working directory -WORKDIR /app - -# Copy only the built JAR file from the 'builder' stage -COPY --from=builder /app/target/*.jar app.jar - -# Expose the application port -EXPOSE 8080 - -# Command to run the application -ENTRYPOINT ["java", "-jar", "app.jar"] diff --git a/README.md b/README.md deleted file mode 100644 index fa8fc3d..0000000 --- a/README.md +++ /dev/null @@ -1,107 +0,0 @@ -# Rhythm Backend (Go) - -Lean Go API backend for ISeeU Tracker. - -## Current Project State - -- [x] Go module initialized (`go.mod`) -- [x] Entry point created (`cmd/api/main.go`) -- [x] Env config package created (`internal/config/config.go`) -- [x] `.env` loading added with required DB variables -- [x] DB URL builder added in config (`DatabaseURL`) with schema `search_path` -- [x] DB package scaffold created (`internal/db/`) -- [x] Local Postgres service available in `compose.yaml` (dev profile) -- [ ] Database connection package (`internal/db`) not implemented yet -- [ ] Goose migrations folder/files not created yet -- [ ] HTTP router and handlers not implemented yet -- [ ] User DTO/model/repository/service not implemented yet - -## General Folder Structure - -```text -cmd/ - api/ - main.go # application entrypoint - -internal/ - config/ # env and app config - db/ # postgres/sqlx connection + migrations - http/ # router, middleware, handlers - auth/ # jwt, password hashing, auth middleware - service/ # business logic - repository/ # SQLx queries (no ORM) - model/ # domain models + request/response DTOs - -migrations/ # Goose SQL migrations -scripts/ # optional local/dev scripts -``` - -## Roadmap Checklist (Do Not Delete) - -### Chapter 1 - Bootstrap and Config - -- [x] Create `cmd/api/main.go` -- [x] Create `internal/config` package -- [x] Load `.env` and validate required DB env vars -- [x] Add DB URL builder method in config -- [ ] Add `APP_PORT` env var with default fallback -- [ ] Improve startup logs (without printing secrets) - -### Chapter 2 - Database and Goose - -- [ ] Implement `internal/db/postgres.go` with `sqlx` connection (`pgx` driver) -- [ ] Add `internal/db/migrate.go` to run Goose at startup -- [ ] Create `migrations/` directory -- [ ] Create first migration for `users` table -- [ ] Wire migration call into app startup (before HTTP server) -- [ ] Add `goose status` and rollback notes in README - -### Chapter 3 - User Vertical Slice (First Feature) - -- [ ] Add user DTO (`username`, `password`) in `internal/model` -- [ ] Add user DB model (`id`, `username`, `password_hash`, timestamps) -- [ ] Add user repository with SQLx (`CreateUser`, `GetByUsername`) -- [ ] Add user service with bcrypt hashing -- [ ] Add `POST /users/register` handler -- [ ] Add input validation and proper error responses - -### Chapter 4 - HTTP Layer and Health - -- [ ] Add router setup in `internal/http/router.go` -- [ ] Add `GET /health` endpoint -- [ ] Add JSON response helpers -- [ ] Add request logging middleware -- [ ] Add panic recovery middleware - -### Chapter 5 - Security Foundation - -- [ ] Add password hashing and compare helpers -- [ ] Add JWT generation/verification package -- [ ] Add auth middleware for protected routes -- [ ] Add `POST /auth/login` -- [ ] Add `GET /auth/me` - -### Chapter 6 - Developer Experience - -- [ ] Add `Makefile` targets (`run`, `db-up`, `migrate-up`, `migrate-down`) -- [ ] Add graceful shutdown in `main.go` -- [ ] Add structured logging (`log/slog`) -- [ ] Add `.env.example` updates for all required vars -- [ ] Add basic project usage section in README - -### Chapter 7 - Testing - -- [ ] Add unit tests for config package -- [ ] Add unit tests for user service -- [ ] Add repository integration test setup (test DB) -- [ ] Add handler tests for register endpoint -- [ ] Add CI step to run tests - -## Notes - -- Keep handlers thin, business logic in `service`, SQL in `repository`. -- Use `sqlx` for explicit SQL and scan helpers. -- Use `goose` for schema versioning and run migrations automatically at startup. -- Never store plain passwords; always use `password_hash`. -- Keep one shared `*sqlx.DB` pool for the app lifetime; do not open DB per request. -- Pass `context.Context` from handler (`r.Context()`) to service/repository methods. diff --git a/cmd/api/main.go b/cmd/api/main.go deleted file mode 100644 index 7eab523..0000000 --- a/cmd/api/main.go +++ /dev/null @@ -1,11 +0,0 @@ -package main - -import ( - "git.kanopo.dev/rhythm/rhythm-backend/internal/config" - "log" -) - -func main() { - cfg := config.Load() - log.Println(cfg) -} diff --git a/compose.yaml b/compose.yaml deleted file mode 100644 index 2cbcf64..0000000 --- a/compose.yaml +++ /dev/null @@ -1,57 +0,0 @@ -services: - # api-prod: - # build: . - # restart: unless-stopped - # container_name: qrcode-api - # ports: - # - "8080:8080" - # environment: - # DB_HOST: db-prod - # env_file: - # - ".env" - # depends_on: - # db-prod: - # condition: service_healthy - # profiles: - # - prod - # - # db-prod: - # image: postgres:18.0-alpine - # restart: unless-stopped - # container_name: qrcode-database-prod - # ports: - # - "${DB_PORT:-5432}:5432" - # environment: - # POSTGRES_USER: ${DB_USERNAME} - # POSTGRES_PASSWORD: ${DB_PASSWORD} - # POSTGRES_DB: ${DB_NAME} - # volumes: - # - postgres_data:/var/lib/postgresql/data - # profiles: - # - prod - # healthcheck: - # test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME} -d ${DB_NAME}"] - # interval: 5s - # timeout: 3s - # retries: 10 - - db-dev: - image: postgres:18.0-alpine - restart: unless-stopped - container_name: rhythm-db-dev - ports: - - "${DB_PORT:-5432}:5432" - environment: - POSTGRES_USER: ${DB_USERNAME} - POSTGRES_PASSWORD: ${DB_PASSWORD} - POSTGRES_DB: ${DB_NAME} - profiles: - - dev - healthcheck: - test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME} -d ${DB_NAME}"] - interval: 5s - timeout: 3s - retries: 10 - -volumes: - postgres_data: diff --git a/example.env b/example.env deleted file mode 100644 index 6433895..0000000 --- a/example.env +++ /dev/null @@ -1,5 +0,0 @@ -DB_USERNAME=user -DB_PASSWORD=password -DB_NAME=rhythm-dev -DB_PORT=5432 -DB_HOST=localhost diff --git a/go.mod b/go.mod deleted file mode 100644 index 334e121..0000000 --- a/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module git.kanopo.dev/rhythm/rhythm-backend - -go 1.26.2 - -require github.com/joho/godotenv v1.5.1 diff --git a/go.sum b/go.sum deleted file mode 100644 index d61b19e..0000000 --- a/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= diff --git a/internal/config/config.go b/internal/config/config.go deleted file mode 100644 index ad985f4..0000000 --- a/internal/config/config.go +++ /dev/null @@ -1,61 +0,0 @@ -package config - -import ( - "log" - "net" - "net/url" - "os" - - "github.com/joho/godotenv" -) - -type Config struct { - DBHost string - DBPort string - DBName string - DBUser string - DBPassword string - DBSchema string -} - -func getEnv(key string) string { - v := os.Getenv(key) - if v == "" { - log.Fatalf("missing required env var: %s", key) - } - return v -} -func getEnvOrDefault(key, default_string string) string { - v := os.Getenv(key) - if v == "" { - return default_string - } - return v -} - -func Load() Config { - _ = godotenv.Load() - - return Config{ - DBHost: getEnv("DB_HOST"), - DBPort: getEnv("DB_PORT"), - DBName: getEnv("DB_NAME"), - DBUser: getEnv("DB_USERNAME"), - DBPassword: getEnv("DB_PASSWORD"), - DBSchema: getEnvOrDefault("DB_SCHEMA", "public"), - } -} - -func (cfg Config) DatabaseURL() string { - u := &url.URL{ - Scheme: "postgres", - User: url.UserPassword(cfg.DBUser, cfg.DBPassword), - Host: net.JoinHostPort(cfg.DBHost, cfg.DBPort), - Path: cfg.DBName, - } - q := u.Query() - q.Set("sslmode", "false") - q.Set("search_path", cfg.DBSchema) - u.RawQuery = q.Encode() - return u.String() -} diff --git a/internal/db/db.go b/internal/db/db.go deleted file mode 100644 index 3a49c63..0000000 --- a/internal/db/db.go +++ /dev/null @@ -1 +0,0 @@ -package db diff --git a/internal/db/postgres.go b/internal/db/postgres.go deleted file mode 100644 index 3a49c63..0000000 --- a/internal/db/postgres.go +++ /dev/null @@ -1 +0,0 @@ -package db diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +}