mirror of
https://github.com/rjNemo/auth
synced 2026-06-06 00:16:40 +00:00
chore: scaffold database tooling
This commit is contained in:
parent
19d94a6349
commit
49d3722b44
10 changed files with 200 additions and 16 deletions
42
AUTH_PLAN.md
42
AUTH_PLAN.md
|
|
@ -40,3 +40,45 @@
|
||||||
- Add structured logging: text encoder for development, JSON for production deployments.
|
- Add structured logging: text encoder for development, JSON for production deployments.
|
||||||
- Consolidate templates with a base layout to remove duplication across pages.
|
- Consolidate templates with a base layout to remove duplication across pages.
|
||||||
- Introduce configuration loading that sources environment variables, validates them, and exposes typed settings at startup.
|
- Introduce configuration loading that sources environment variables, validates them, and exposes typed settings at startup.
|
||||||
|
|
||||||
|
## Database Roadmap
|
||||||
|
|
||||||
|
- **users**
|
||||||
|
- `id uuid PRIMARY KEY DEFAULT gen_random_uuid()`
|
||||||
|
- `email citext NOT NULL UNIQUE`
|
||||||
|
- `display_name text`
|
||||||
|
- `created_at timestamptz NOT NULL DEFAULT now()`
|
||||||
|
- `updated_at timestamptz NOT NULL DEFAULT now()`
|
||||||
|
- **user_passwords**
|
||||||
|
- `user_id uuid PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE`
|
||||||
|
- `password_hash bytea NOT NULL`
|
||||||
|
- `password_salt bytea NOT NULL`
|
||||||
|
- `algorithm text NOT NULL`
|
||||||
|
- `created_at timestamptz NOT NULL DEFAULT now()`
|
||||||
|
- `updated_at timestamptz NOT NULL DEFAULT now()`
|
||||||
|
- **user_oauth_accounts**
|
||||||
|
- `id uuid PRIMARY KEY DEFAULT gen_random_uuid()`
|
||||||
|
- `user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE`
|
||||||
|
- `provider text NOT NULL`
|
||||||
|
- `subject text NOT NULL`
|
||||||
|
- `email text`
|
||||||
|
- `email_verified boolean NOT NULL DEFAULT false`
|
||||||
|
- `profile jsonb`
|
||||||
|
- `created_at timestamptz NOT NULL DEFAULT now()`
|
||||||
|
- `updated_at timestamptz NOT NULL DEFAULT now()`
|
||||||
|
- Indexes: `UNIQUE(provider, subject)` and `INDEX(user_id)`
|
||||||
|
- **login_events**
|
||||||
|
- `id uuid PRIMARY KEY DEFAULT gen_random_uuid()`
|
||||||
|
- `user_id uuid REFERENCES users(id)`
|
||||||
|
- `provider text`
|
||||||
|
- `success boolean NOT NULL`
|
||||||
|
- `ip inet`
|
||||||
|
- `user_agent text`
|
||||||
|
- `created_at timestamptz NOT NULL DEFAULT now()`
|
||||||
|
- Indexes: `INDEX(user_id)`, `INDEX(created_at)`
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- All timestamps default to UTC via `now()`.
|
||||||
|
- Authentication data stays normalized; optional password/OAuth records live in dedicated tables for clarity and extension.
|
||||||
|
- `login_events` remains a standard logged table to preserve audit history; revisit storage strategy if write volume demands partitioning later.
|
||||||
|
|
|
||||||
31
Makefile
31
Makefile
|
|
@ -1,8 +1,15 @@
|
||||||
BIN_DIR := bin
|
BIN_DIR := bin
|
||||||
BIN_NAME := auth-server
|
BIN_NAME := auth-server
|
||||||
FMT_PATHS := $(shell go list -f '{{.Dir}}' ./...)
|
FMT_PATHS := $(shell go list -f '{{.Dir}}' ./...)
|
||||||
|
MIGRATIONS_DIR := internal/driver/db/migrations
|
||||||
|
SQLC_CONFIG := internal/driver/db/sqlc.yaml
|
||||||
|
DB_URL ?= $(AUTH_DATABASE_URL)
|
||||||
|
DB_URL := $(strip $(DB_URL))
|
||||||
|
ifeq ($(DB_URL),)
|
||||||
|
DB_URL := postgres://localhost/auth_dev?sslmode=disable
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: run dev build test fmt lint tidy clean
|
.PHONY: run dev build test fmt lint tidy clean migrate-status migrate-up migrate-down migrate-reset migrate-new sqlc-generate
|
||||||
|
|
||||||
run:
|
run:
|
||||||
go run ./cmd/server
|
go run ./cmd/server
|
||||||
|
|
@ -28,3 +35,25 @@ tidy:
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(BIN_DIR)
|
rm -rf $(BIN_DIR)
|
||||||
|
|
||||||
|
migrate-status:
|
||||||
|
goose -dir $(MIGRATIONS_DIR) postgres "$(DB_URL)" status
|
||||||
|
|
||||||
|
migrate-up:
|
||||||
|
goose -dir $(MIGRATIONS_DIR) postgres "$(DB_URL)" up
|
||||||
|
|
||||||
|
migrate-down:
|
||||||
|
goose -dir $(MIGRATIONS_DIR) postgres "$(DB_URL)" down
|
||||||
|
|
||||||
|
migrate-reset:
|
||||||
|
goose -dir $(MIGRATIONS_DIR) postgres "$(DB_URL)" reset
|
||||||
|
|
||||||
|
migrate-new:
|
||||||
|
@if [ -z "$(name)" ]; then \
|
||||||
|
echo "usage: make migrate-new name=add_feature"; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
goose -dir $(MIGRATIONS_DIR) create $(name) sql
|
||||||
|
|
||||||
|
sqlc-generate:
|
||||||
|
sqlc generate -f $(SQLC_CONFIG)
|
||||||
|
|
|
||||||
19
README.md
19
README.md
|
|
@ -20,11 +20,17 @@ templates/assets for single-binary deployment.
|
||||||
2. Use the targets in the [Makefile](./Makefile):
|
2. Use the targets in the [Makefile](./Makefile):
|
||||||
|
|
||||||
| Target | Description |
|
| Target | Description |
|
||||||
| ------------ | --------------------------------------------------------------------------------------- |
|
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| `make run` | Start the HTTP server with the current environment. |
|
| `make run` | Start the HTTP server with the current environment. |
|
||||||
| `make dev` | Launch [Air](https://github.com/cosmtrek/air) for live reload (requires `air` on PATH). |
|
| `make dev` | Launch [Air](https://github.com/cosmtrek/air) for live reload (requires `air` on PATH). |
|
||||||
| `make build` | Compile to `./bin/auth-server`. |
|
| `make build` | Compile to `./bin/auth-server`. |
|
||||||
| `make test` | Run `go test ./... -cover -count=1`. |
|
| `make test` | Run `go test ./... -cover -count=1`. |
|
||||||
|
| `make migrate-status` | Show Goose migration status for the configured database. |
|
||||||
|
| `make migrate-up` | Apply pending migrations to the database at `AUTH_DATABASE_URL` (defaults to `postgres://localhost/auth_dev?sslmode=disable`). |
|
||||||
|
| `make migrate-down` | Roll back the most recent migration in the target database. |
|
||||||
|
| `make migrate-reset` | Reset the schema by rolling back all migrations, then re-applying them. |
|
||||||
|
| `make migrate-new name=` | Create a timestamped SQL migration (e.g. `make migrate-new name=add_users`). |
|
||||||
|
| `make sqlc-generate` | Regenerate data-access code from SQL queries via `sqlc`. |
|
||||||
|
|
||||||
3. Visit the login page (default <http://localhost:8000>) and authenticate with
|
3. Visit the login page (default <http://localhost:8000>) and authenticate with
|
||||||
the demo credentials displayed on screen.
|
the demo credentials displayed on screen.
|
||||||
|
|
@ -34,8 +40,9 @@ templates/assets for single-binary deployment.
|
||||||
Settings are sourced from environment variables (see [.env](./.env)).
|
Settings are sourced from environment variables (see [.env](./.env)).
|
||||||
|
|
||||||
| Variable | Required | Default | Description |
|
| Variable | Required | Default | Description |
|
||||||
| --------------------------- | ----------- | ------------- | ----------------------------------------------------------------------------- |
|
| --------------------------- | ----------- | ------------- | ------------------------------------------------------------------------------------ |
|
||||||
| `AUTH_SESSION_SECRET` | Yes | — | Base64-encoded secret used to sign session cookies. |
|
| `AUTH_SESSION_SECRET` | Yes | — | Base64-encoded secret used to sign session cookies. |
|
||||||
|
| `AUTH_DATABASE_URL` | Yes | — | PostgreSQL connection string (e.g. `postgres://localhost/auth_dev?sslmode=disable`). |
|
||||||
| `AUTH_LISTEN_ADDR` | No | `:8000` | Address the HTTP server binds to. |
|
| `AUTH_LISTEN_ADDR` | No | `:8000` | Address the HTTP server binds to. |
|
||||||
| `AUTH_ENV` | No | `development` | Environment label, controls logger source annotation. |
|
| `AUTH_ENV` | No | `development` | Environment label, controls logger source annotation. |
|
||||||
| `AUTH_LOG_MODE` | No | `text` | Structured log encoder (`text` or `json`). |
|
| `AUTH_LOG_MODE` | No | `text` | Structured log encoder (`text` or `json`). |
|
||||||
|
|
@ -43,6 +50,14 @@ Settings are sourced from environment variables (see [.env](./.env)).
|
||||||
| `AUTH_GOOGLE_CLIENT_SECRET` | Conditional | — | Google OAuth 2.0 client secret matching the ID above. |
|
| `AUTH_GOOGLE_CLIENT_SECRET` | Conditional | — | Google OAuth 2.0 client secret matching the ID above. |
|
||||||
| `AUTH_GOOGLE_REDIRECT_URL` | Conditional | — | Registered redirect URL (e.g. `http://localhost:8000/login/google/callback`). |
|
| `AUTH_GOOGLE_REDIRECT_URL` | Conditional | — | Registered redirect URL (e.g. `http://localhost:8000/login/google/callback`). |
|
||||||
|
|
||||||
|
## Database Tooling
|
||||||
|
|
||||||
|
Migrations live in [`internal/driver/db/migrations`](./internal/driver/db/migrations) and are managed with
|
||||||
|
[Goose](https://github.com/pressly/goose). Point `AUTH_DATABASE_URL` at your PostgreSQL instance—`postgres://localhost/auth_dev?sslmode=disable`
|
||||||
|
is a good local default—then use the Makefile helpers (`make migrate-up`, `make migrate-status`, etc.) to evolve the schema. The same DSN drives
|
||||||
|
[`sqlc`](https://sqlc.dev/) generation with `make sqlc-generate`, which reads [`internal/driver/db/sqlc.yaml`](./internal/driver/db/sqlc.yaml) and
|
||||||
|
emits typed data-access code alongside the queries.
|
||||||
|
|
||||||
## Project Layout
|
## Project Layout
|
||||||
|
|
||||||
- `cmd/server` — application entrypoint.
|
- `cmd/server` — application entrypoint.
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ const (
|
||||||
envLogMode = "AUTH_LOG_MODE"
|
envLogMode = "AUTH_LOG_MODE"
|
||||||
envEnvironment = "AUTH_ENV"
|
envEnvironment = "AUTH_ENV"
|
||||||
envSessionSecret = "AUTH_SESSION_SECRET"
|
envSessionSecret = "AUTH_SESSION_SECRET"
|
||||||
|
envDatabaseURL = "AUTH_DATABASE_URL"
|
||||||
envGoogleClientID = "AUTH_GOOGLE_CLIENT_ID"
|
envGoogleClientID = "AUTH_GOOGLE_CLIENT_ID"
|
||||||
envGoogleClientSecret = "AUTH_GOOGLE_CLIENT_SECRET"
|
envGoogleClientSecret = "AUTH_GOOGLE_CLIENT_SECRET"
|
||||||
envGoogleRedirectURL = "AUTH_GOOGLE_REDIRECT_URL"
|
envGoogleRedirectURL = "AUTH_GOOGLE_REDIRECT_URL"
|
||||||
|
|
@ -29,6 +30,7 @@ type Config struct {
|
||||||
LogMode logging.Mode
|
LogMode logging.Mode
|
||||||
Environment string
|
Environment string
|
||||||
SessionSecret []byte
|
SessionSecret []byte
|
||||||
|
DatabaseURL string
|
||||||
GoogleOAuth GoogleOAuthConfig
|
GoogleOAuth GoogleOAuthConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,6 +65,11 @@ func New() (*Config, error) {
|
||||||
return nil, fmt.Errorf("invalid %s: %w", envSessionSecret, err)
|
return nil, fmt.Errorf("invalid %s: %w", envSessionSecret, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
databaseURL := strings.TrimSpace(os.Getenv(envDatabaseURL))
|
||||||
|
if databaseURL == "" {
|
||||||
|
return nil, fmt.Errorf("missing required configuration: set %s", envDatabaseURL)
|
||||||
|
}
|
||||||
|
|
||||||
googleOAuth := GoogleOAuthConfig{
|
googleOAuth := GoogleOAuthConfig{
|
||||||
ClientID: strings.TrimSpace(os.Getenv(envGoogleClientID)),
|
ClientID: strings.TrimSpace(os.Getenv(envGoogleClientID)),
|
||||||
ClientSecret: strings.TrimSpace(os.Getenv(envGoogleClientSecret)),
|
ClientSecret: strings.TrimSpace(os.Getenv(envGoogleClientSecret)),
|
||||||
|
|
@ -78,6 +85,7 @@ func New() (*Config, error) {
|
||||||
LogMode: logMode,
|
LogMode: logMode,
|
||||||
Environment: environment,
|
Environment: environment,
|
||||||
SessionSecret: secret,
|
SessionSecret: secret,
|
||||||
|
DatabaseURL: databaseURL,
|
||||||
GoogleOAuth: googleOAuth,
|
GoogleOAuth: googleOAuth,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
func TestNewDefaults(t *testing.T) {
|
func TestNewDefaults(t *testing.T) {
|
||||||
t.Setenv("AUTH_SESSION_SECRET", base64.StdEncoding.EncodeToString(bytesOfLength(32)))
|
t.Setenv("AUTH_SESSION_SECRET", base64.StdEncoding.EncodeToString(bytesOfLength(32)))
|
||||||
|
t.Setenv("AUTH_DATABASE_URL", "postgres://localhost/auth_test?sslmode=disable")
|
||||||
cfg, err := New()
|
cfg, err := New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
|
@ -30,6 +31,7 @@ func TestNewDefaults(t *testing.T) {
|
||||||
func TestNewOverrides(t *testing.T) {
|
func TestNewOverrides(t *testing.T) {
|
||||||
secret := base64.StdEncoding.EncodeToString(bytesOfLength(40))
|
secret := base64.StdEncoding.EncodeToString(bytesOfLength(40))
|
||||||
t.Setenv("AUTH_SESSION_SECRET", secret)
|
t.Setenv("AUTH_SESSION_SECRET", secret)
|
||||||
|
t.Setenv("AUTH_DATABASE_URL", "postgres://localhost/auth_test?sslmode=disable")
|
||||||
t.Setenv("AUTH_LISTEN_ADDR", "127.0.0.1:9000")
|
t.Setenv("AUTH_LISTEN_ADDR", "127.0.0.1:9000")
|
||||||
t.Setenv("AUTH_LOG_MODE", "json")
|
t.Setenv("AUTH_LOG_MODE", "json")
|
||||||
t.Setenv("AUTH_ENV", "production")
|
t.Setenv("AUTH_ENV", "production")
|
||||||
|
|
@ -54,6 +56,7 @@ func TestNewOverrides(t *testing.T) {
|
||||||
|
|
||||||
func TestNewMissingSecret(t *testing.T) {
|
func TestNewMissingSecret(t *testing.T) {
|
||||||
t.Setenv("AUTH_SESSION_SECRET", "")
|
t.Setenv("AUTH_SESSION_SECRET", "")
|
||||||
|
t.Setenv("AUTH_DATABASE_URL", "postgres://localhost/auth_test?sslmode=disable")
|
||||||
if _, err := New(); err == nil {
|
if _, err := New(); err == nil {
|
||||||
t.Fatalf("expected error for missing secret")
|
t.Fatalf("expected error for missing secret")
|
||||||
}
|
}
|
||||||
|
|
@ -61,6 +64,7 @@ func TestNewMissingSecret(t *testing.T) {
|
||||||
|
|
||||||
func TestNewInvalidSecret(t *testing.T) {
|
func TestNewInvalidSecret(t *testing.T) {
|
||||||
t.Setenv("AUTH_SESSION_SECRET", "not-base64")
|
t.Setenv("AUTH_SESSION_SECRET", "not-base64")
|
||||||
|
t.Setenv("AUTH_DATABASE_URL", "postgres://localhost/auth_test?sslmode=disable")
|
||||||
if _, err := New(); err == nil {
|
if _, err := New(); err == nil {
|
||||||
t.Fatalf("expected error for invalid secret")
|
t.Fatalf("expected error for invalid secret")
|
||||||
}
|
}
|
||||||
|
|
@ -68,6 +72,7 @@ func TestNewInvalidSecret(t *testing.T) {
|
||||||
|
|
||||||
func TestNewShortSecretAccepted(t *testing.T) {
|
func TestNewShortSecretAccepted(t *testing.T) {
|
||||||
t.Setenv("AUTH_SESSION_SECRET", base64.StdEncoding.EncodeToString(bytesOfLength(16)))
|
t.Setenv("AUTH_SESSION_SECRET", base64.StdEncoding.EncodeToString(bytesOfLength(16)))
|
||||||
|
t.Setenv("AUTH_DATABASE_URL", "postgres://localhost/auth_test?sslmode=disable")
|
||||||
if _, err := New(); err != nil {
|
if _, err := New(); err != nil {
|
||||||
t.Fatalf("expected short secret to pass config load, got %v", err)
|
t.Fatalf("expected short secret to pass config load, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -77,6 +82,7 @@ func TestNewGoogleOAuthPartialConfiguration(t *testing.T) {
|
||||||
t.Setenv("AUTH_SESSION_SECRET", base64.StdEncoding.EncodeToString(bytesOfLength(32)))
|
t.Setenv("AUTH_SESSION_SECRET", base64.StdEncoding.EncodeToString(bytesOfLength(32)))
|
||||||
t.Setenv("AUTH_GOOGLE_CLIENT_ID", "client")
|
t.Setenv("AUTH_GOOGLE_CLIENT_ID", "client")
|
||||||
t.Setenv("AUTH_GOOGLE_CLIENT_SECRET", "")
|
t.Setenv("AUTH_GOOGLE_CLIENT_SECRET", "")
|
||||||
|
t.Setenv("AUTH_DATABASE_URL", "postgres://localhost/auth_test?sslmode=disable")
|
||||||
if _, err := New(); err == nil {
|
if _, err := New(); err == nil {
|
||||||
t.Fatalf("expected error for partial google oauth config")
|
t.Fatalf("expected error for partial google oauth config")
|
||||||
}
|
}
|
||||||
|
|
@ -87,6 +93,7 @@ func TestNewGoogleOAuthConfigured(t *testing.T) {
|
||||||
t.Setenv("AUTH_GOOGLE_CLIENT_ID", "client")
|
t.Setenv("AUTH_GOOGLE_CLIENT_ID", "client")
|
||||||
t.Setenv("AUTH_GOOGLE_CLIENT_SECRET", "secret")
|
t.Setenv("AUTH_GOOGLE_CLIENT_SECRET", "secret")
|
||||||
t.Setenv("AUTH_GOOGLE_REDIRECT_URL", "http://localhost:8000/login/google/callback")
|
t.Setenv("AUTH_GOOGLE_REDIRECT_URL", "http://localhost:8000/login/google/callback")
|
||||||
|
t.Setenv("AUTH_DATABASE_URL", "postgres://localhost/auth_test?sslmode=disable")
|
||||||
|
|
||||||
cfg, err := New()
|
cfg, err := New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
6
internal/driver/db/goose.toml
Normal file
6
internal/driver/db/goose.toml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
[goose]
|
||||||
|
dir = "migrations"
|
||||||
|
|
||||||
|
[goose.envs.local]
|
||||||
|
driver = "postgres"
|
||||||
|
open = "postgres://localhost/auth_dev?sslmode=disable"
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
-- +goose Up
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||||
|
CREATE EXTENSION IF NOT EXISTS citext;
|
||||||
|
|
||||||
|
CREATE TABLE users (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
email CITEXT NOT NULL UNIQUE,
|
||||||
|
display_name TEXT,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE user_passwords (
|
||||||
|
user_id UUID PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
password_hash BYTEA NOT NULL,
|
||||||
|
password_salt BYTEA NOT NULL,
|
||||||
|
algorithm TEXT NOT NULL,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE user_oauth_accounts (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
provider TEXT NOT NULL,
|
||||||
|
subject TEXT NOT NULL,
|
||||||
|
email TEXT,
|
||||||
|
email_verified BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
profile JSONB,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX user_oauth_accounts_provider_subject_idx
|
||||||
|
ON user_oauth_accounts (provider, subject);
|
||||||
|
|
||||||
|
CREATE INDEX user_oauth_accounts_user_id_idx
|
||||||
|
ON user_oauth_accounts (user_id);
|
||||||
|
|
||||||
|
CREATE TABLE login_events (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
user_id UUID REFERENCES users(id),
|
||||||
|
provider TEXT,
|
||||||
|
success BOOLEAN NOT NULL,
|
||||||
|
ip INET,
|
||||||
|
user_agent TEXT,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX login_events_user_id_idx ON login_events (user_id);
|
||||||
|
CREATE INDEX login_events_created_at_idx ON login_events (created_at);
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
DROP TABLE IF EXISTS login_events;
|
||||||
|
DROP TABLE IF EXISTS user_oauth_accounts;
|
||||||
|
DROP TABLE IF EXISTS user_passwords;
|
||||||
|
DROP TABLE IF EXISTS users;
|
||||||
|
DROP EXTENSION IF EXISTS citext;
|
||||||
|
DROP EXTENSION IF EXISTS pgcrypto;
|
||||||
0
internal/driver/db/queries/.gitkeep
Normal file
0
internal/driver/db/queries/.gitkeep
Normal file
16
internal/driver/db/sqlc.yaml
Normal file
16
internal/driver/db/sqlc.yaml
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
version: "2"
|
||||||
|
sql:
|
||||||
|
- engine: "postgresql"
|
||||||
|
schema: migrations
|
||||||
|
queries:
|
||||||
|
- queries
|
||||||
|
gen:
|
||||||
|
go:
|
||||||
|
package: db
|
||||||
|
out: internal/driver/db/sqlc
|
||||||
|
emit_json_tags: true
|
||||||
|
sql_package: pgx/v5
|
||||||
|
emit_interface: false
|
||||||
|
overrides:
|
||||||
|
- db_type: "uuid"
|
||||||
|
go_type: github.com/google/uuid.UUID
|
||||||
|
|
@ -21,6 +21,7 @@ func newTestServer(t *testing.T) *Server {
|
||||||
LogMode: logging.ModeText,
|
LogMode: logging.ModeText,
|
||||||
Environment: "test",
|
Environment: "test",
|
||||||
SessionSecret: bytes.Repeat([]byte("s"), 32),
|
SessionSecret: bytes.Repeat([]byte("s"), 32),
|
||||||
|
DatabaseURL: "postgres://localhost/auth_test?sslmode=disable",
|
||||||
}
|
}
|
||||||
|
|
||||||
logger := logging.New(io.Discard, logging.ModeText, nil)
|
logger := logging.New(io.Discard, logging.ModeText, nil)
|
||||||
|
|
@ -45,6 +46,7 @@ func newGoogleTestServer(t *testing.T) *Server {
|
||||||
ClientSecret: "secret",
|
ClientSecret: "secret",
|
||||||
RedirectURL: "http://localhost/login/google/callback",
|
RedirectURL: "http://localhost/login/google/callback",
|
||||||
},
|
},
|
||||||
|
DatabaseURL: "postgres://localhost/auth_test?sslmode=disable",
|
||||||
}
|
}
|
||||||
|
|
||||||
logger := logging.New(io.Discard, logging.ModeText, nil)
|
logger := logging.New(io.Discard, logging.ModeText, nil)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue