138 lines
9.5 KiB
Markdown
138 lines
9.5 KiB
Markdown
Aşağıdaki metni aynen VSCode Copilot’a (veya başka bir kod üretecine) ver — tek istekte tam bir Rust web projesi iskeleti oluşturacak şekilde ayrıntılı, ama gereksiz karmaşıklıktan kaçınan, dosyalar ayrı ayrı olacak ve PostgreSQL kullanacak bir hesap sistemi üretmesini istiyorum. ÖNEMLİ: Kesinlikle bir ORM ve bir web framework kullanılsın — SeaORM (ORM) ve Axum (web framework) kullanılacak. Kod istemiyorum — sadece bu metni Copilot'a yapıştır ve proje oluşturmasını bekle.
|
||
|
||
Ek değişiklikler / kesin gereksinimler:
|
||
- Database: PostgreSQL olacak (default DATABASE_URL örneği .env.example içinde postgres://user:pass@localhost:5432/dbname).
|
||
- Tüm API yolları /api/v1/ prefix'i altında olacak (ör. /api/v1/auth/register, /api/v1/users/me).
|
||
- Auth: access_token (short-lived) ve refresh_token (long-lived) olacak.
|
||
- Parola hash algoritması: Argon2 yerine BCryptSHA256PasswordHasher uygulanacak şekilde iste — yani parola önce SHA-256 ile ön-hash edilecek, sonra bcrypt ile hash edilecek (Rust tarafında sha2 crate ile pre-hash + bcrypt crate ile bcrypt uygulaması). Copilot'a açıkça "Implement BCrypt-SHA256: SHA256(password) then bcrypt on hex/base64 of digest" diye belirt.
|
||
- OAuth: Google ve GitHub OAuth2 desteklenecek.
|
||
|
||
İstek (kopyala-yapıştır için; İngilizce olarak verilecek çünkü Copilot daha iyi anlar):
|
||
|
||
"Generate a complete, minimal and well-structured Rust web project that implements a user account system with these exact characteristics:
|
||
|
||
Project-wide:
|
||
- Use async Rust with Tokio runtime.
|
||
- Use Axum as web framework and SeaORM as ORM (SeaORM entities / ActiveModels).
|
||
- Use tracing for structured logs.
|
||
- Default database: PostgreSQL (connection via DATABASE_URL). The project must be structured so switching DBs only requires changing DATABASE_URL and running migrations via sea-orm-migration / sea-orm-cli.
|
||
- All endpoints MUST be under the prefix /api/v1/.
|
||
- Load configuration and secrets from .env (use dotenvy or envy). Provide a .env.example.
|
||
|
||
Authentication & Security:
|
||
- Email/password registration + login using BCrypt-SHA256 password hasher:
|
||
- Pre-hash the raw password with SHA-256 (use sha2 crate), then hash the resulting digest with bcrypt (use bcrypt crate).
|
||
- Provide helper functions to verify password with the same process.
|
||
- Document clearly in comments where to change to another hasher.
|
||
- Social login via Google and GitHub (OAuth2 flows using oauth2 crate; use reqwest or oauth2's HTTP client for provider calls).
|
||
- JWT access tokens and refresh tokens:
|
||
- Use jsonwebtoken crate.
|
||
- Sign tokens with SECRET_KEY from .env.
|
||
- Respect ACCESS_TOKEN_EXPIRE_MINUTES and REFRESH_TOKEN_EXPIRE_DAYS settings.
|
||
- Include both access_token and refresh_token in responses where applicable.
|
||
- Store refresh tokens in DB (store UUID string; include comment about switching to hashed storage if desired).
|
||
- Validate emails using a validator crate (e.g., validator).
|
||
|
||
Endpoints to implement (minimal but runnable):
|
||
- POST /api/v1/auth/register
|
||
- Accept JSON { "email": "...", "password": "..." }
|
||
- Validate email, pre-hash+bcrypt password, create user, create refresh token record, return { access_token, refresh_token, token_type, expires_in }.
|
||
- POST /api/v1/auth/login
|
||
- Accept JSON { "email": "...", "password": "..." }
|
||
- Verify credentials, return access + refresh tokens.
|
||
- POST /api/v1/auth/refresh
|
||
- Accept JSON { "refresh_token": "..." }
|
||
- Verify refresh token exists and not expired, return new access token (and optionally rotate refresh token).
|
||
- GET /api/v1/auth/oauth/{provider}
|
||
- provider ∈ {"google","github"} — build provider auth URL with required scopes and redirect the client.
|
||
- GET /api/v1/auth/oauth/{provider}/callback
|
||
- Exchange code for token, fetch user info (email), extract primary verified email, create/find user (hashed_password NULL, provider field set), create refresh token, return tokens (or redirect with tokens).
|
||
- POST /api/v1/auth/logout
|
||
- Accept JSON { "refresh_token": "..." } (or use header), delete/invalidate the refresh token in DB.
|
||
- GET /api/v1/users/me
|
||
- Protected with Authorization: Bearer <access_token>, returns current user info.
|
||
|
||
Data models (SeaORM / DB schema):
|
||
- users table / User entity (UUID primary key):
|
||
- id (UUID)
|
||
- email (unique)
|
||
- hashed_password (nullable for OAuth-only accounts)
|
||
- provider (nullable text: "google", "github", or NULL)
|
||
- is_active (boolean)
|
||
- created_at (timestamp)
|
||
- refresh_tokens table / RefreshToken entity:
|
||
- id (UUID)
|
||
- user_id (UUID FK)
|
||
- token (UUID string)
|
||
- created_at
|
||
- expires_at
|
||
|
||
Project layout (generator MUST create these files/modules — produce working Rust code for each):
|
||
- Cargo.toml (include: axum, tokio, sea-orm, sea-orm-migration, sea-orm-macros, dotenvy or envy, serde, serde_json, uuid, bcrypt, sha2, jsonwebtoken, oauth2, reqwest, chrono or time, validator, tracing, anyhow, thiserror)
|
||
- src/
|
||
- main.rs (app startup, router composition with /api/v1 prefix, load config, init SeaORM DB connection and run migrations at startup option)
|
||
- core/
|
||
- config.rs (Config struct loading env vars; typed fields for secrets, expirations, DB URL, OAuth client ids/secrets, OAUTH_REDIRECT_BASE)
|
||
- security.rs (BCrypt-SHA256 password helpers, JWT create/verify helpers, token payload types)
|
||
- oauth.rs (provider configs and helper functions to build auth URLs and exchange codes)
|
||
- db/
|
||
- mod.rs (SeaORM Database connection setup, run migrations helper)
|
||
- entities/ (SeaORM entities: users.rs, refresh_tokens.rs or a generated entities mod)
|
||
- schemas/
|
||
- mod.rs (request/response DTOs: RegisterRequest, LoginRequest, TokenResponse, RefreshRequest, UserResponse)
|
||
- services/
|
||
- auth_service.rs (register/login/refresh/oauth logic; create tokens; persist refresh tokens; rotate tokens if desired)
|
||
- user_service.rs (basic user CRUD and lookup using SeaORM ActiveModels)
|
||
- api/
|
||
- deps.rs (extractors for DB connection, typed config, and current_user extractor/middleware)
|
||
- routers/
|
||
- auth.rs (auth endpoints)
|
||
- users.rs (users/me)
|
||
- errors.rs (custom error types and conversions to HTTP responses)
|
||
- utils.rs (helpers e.g., time helpers, uuid helpers)
|
||
- migrations/
|
||
- sea-orm compatible migrations (or raw SQL) to create users and refresh_tokens for PostgreSQL (include at least initial migration file).
|
||
- .env.example (include all required env vars and example values; for PostgreSQL example: DATABASE_URL=postgres://user:password@localhost:5432/your_db)
|
||
- README.md (how to install, set up environment, run migrations with sea-orm-cli or sea-orm-migration runner, run app, env variables, how to register OAuth apps for Google & GitHub and set callback URLs — note callbacks will like be `${OAUTH_REDIRECT_BASE}/api/v1/auth/oauth/google/callback` and similarly for github)
|
||
- tests/
|
||
- integration_tests.rs (basic integration tests that register a user, login, and call /api/v1/users/me using the access token; minimal and runnable)
|
||
|
||
Config & env vars (must be in .env.example):
|
||
- DATABASE_URL=postgres://user:password@localhost:5432/dbname
|
||
- SECRET_KEY=some_long_random_value
|
||
- ACCESS_TOKEN_EXPIRE_MINUTES=15
|
||
- REFRESH_TOKEN_EXPIRE_DAYS=30
|
||
- GOOGLE_CLIENT_ID=
|
||
- GOOGLE_CLIENT_SECRET=
|
||
- GITHUB_CLIENT_ID=
|
||
- GITHUB_CLIENT_SECRET=
|
||
- OAUTH_REDIRECT_BASE=http://localhost:3000
|
||
- SERVER_HOST=127.0.0.1
|
||
- SERVER_PORT=3000
|
||
|
||
Developer notes for the code generator (be explicit):
|
||
- Use SeaORM entities / ActiveModel for DB operations; keep queries simple and idiomatic.
|
||
- Migrations: provide sea-orm-migration or migration SQL and README instructions using sea-orm-cli:
|
||
- e.g., install: cargo install sea-orm-cli
|
||
- run migrations: DATABASE_URL="postgres://..." sea-orm-cli migrate up
|
||
- Implement BCrypt-SHA256 password hasher: pre-hash the UTF-8 password with SHA-256 (sha2::Sha256), encode digest (hex or base64), then pass that string to bcrypt::hash with a configurable cost. Provide verify routine that repeats pre-hash + bcrypt::verify.
|
||
- For OAuth: use oauth2 crate to construct authorize URL and to exchange code; use reqwest to fetch user info (emails) if needed. Scopes: Google ["openid","email","profile"] and GitHub ["user:email"].
|
||
- JWT tokens: use jsonwebtoken; include standard claims and expiry. Use typed structs for token claims.
|
||
- For refresh tokens: generate UUID strings and store them in DB with expiry. Provide optional rotation logic (brief comment).
|
||
- Provide clear error handling using thiserror and map to HTTP responses (axum::response::IntoResponse with proper status codes).
|
||
- The app should mount routes under /api/v1/ (e.g., router.route("/api/v1/auth/register", post(...)) ).
|
||
- Tests: include at least one integration test that runs a test server, registers a user, logs in, and calls /api/v1/users/me with the access token.
|
||
- Keep functions small, typed, and well-documented with comments explaining major steps.
|
||
|
||
Output expectation from Copilot:
|
||
- Create all files listed above with working Rust code (no pseudocode) and comments.
|
||
- The resulting project must be runnable:
|
||
- cargo build
|
||
- set .env from .env.example
|
||
- run sea-orm-cli migrate up (or provided migration runner)
|
||
- cargo run
|
||
- Test endpoints using curl/Postman at http://SERVER_HOST:SERVER_PORT with prefix /api/v1/
|
||
- README must explain how to switch DBs by changing DATABASE_URL and running migrations with appropriate flags (e.g., to switch to MySQL or Postgres, change features/driver).
|
||
- Language for generated code and docs: English (comments or README may include short Turkish notes if helpful)."
|
||
|
||
Not: Bu metni VSCode Copilot'a yapıştırdığımda tam bir Rust web projesi oluştursun; ben yalnızca prompt istedim — kod istemiyorum. |