Skip to content

Commit 66509e7

Browse files
committed
Add settings table
1 parent f3d7103 commit 66509e7

File tree

11 files changed

+680
-7
lines changed

11 files changed

+680
-7
lines changed

backend/cmd/server/main.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,23 @@ func main() {
162162
leaderboardService := services.NewLeaderboardService(db.Queries, cacheInstance.Cache, dataLoaders)
163163
slog.Info("LeaderboardService initialized with caching and loaders")
164164

165+
// Initialize SettingsService
166+
settingsService, err := services.NewSettingsService(ctx, db.Queries, lgr)
167+
if err != nil {
168+
slog.Error("Failed to initialize SettingsService", "error", err)
169+
os.Exit(1)
170+
}
171+
defer settingsService.Stop()
172+
slog.Info("SettingsService initialized with background refresh")
173+
165174
// Initialize GraphQL resolver
166175
apiResolver := &api.Resolver{
167176
DB: db,
168177
Loaders: dataLoaders,
169178
Cache: cacheInstance,
170179
RoleService: roleService,
171180
LeaderboardService: leaderboardService,
181+
Settings: settingsService,
172182
}
173183

174184
apiHandler := handler.New(api.NewExecutableSchema(api.Config{
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
-- +goose Up
2+
-- +goose StatementBegin
3+
4+
-- Settings table stores runtime configuration as key-value pairs
5+
CREATE TABLE settings (
6+
key TEXT PRIMARY KEY,
7+
value_text TEXT,
8+
value_int BIGINT,
9+
value_bool BOOLEAN,
10+
value_float DOUBLE PRECISION,
11+
value_json JSONB,
12+
value_type TEXT NOT NULL CHECK (value_type IN ('text', 'int', 'bool', 'float', 'json')),
13+
description TEXT,
14+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
15+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
16+
);
17+
18+
COMMENT ON TABLE settings IS 'Runtime configuration key-value store';
19+
COMMENT ON COLUMN settings.key IS 'Unique setting identifier (e.g., current_project_id, log_level)';
20+
COMMENT ON COLUMN settings.value_type IS 'Indicates which value column to use: text, int, bool, float, or json';
21+
COMMENT ON COLUMN settings.description IS 'Human-readable description of the setting';
22+
23+
-- Auto-update updated_at timestamp
24+
CREATE TRIGGER settings_updated_at
25+
BEFORE UPDATE ON settings
26+
FOR EACH ROW
27+
EXECUTE FUNCTION update_updated_at_column();
28+
29+
-- Insert default settings
30+
INSERT INTO settings (key, value_text, value_type, description) VALUES
31+
('current_project_id', 'PR01K9VZ8684DP9R4W3ZEV526E5X', 'text', 'Default project ID for unauthenticated queries');
32+
33+
INSERT INTO settings (key, value_text, value_type, description) VALUES
34+
('log_level', 'info', 'text', 'Logging verbosity: debug, info, warn, error');
35+
36+
INSERT INTO settings (key, value_bool, value_type, description) VALUES
37+
('db_log_queries', false, 'bool', 'Toggle query logging for debugging');
38+
39+
INSERT INTO settings (key, value_bool, value_type, description) VALUES
40+
('otel_enabled', true, 'bool', 'Toggle OpenTelemetry tracing on/off');
41+
42+
INSERT INTO settings (key, value_float, value_type, description) VALUES
43+
('otel_sampling_ratio', 0.1, 'float', 'OpenTelemetry sampling rate (0.0-1.0)');
44+
45+
INSERT INTO settings (key, value_bool, value_type, description) VALUES
46+
('ssf_debug_mode', false, 'bool', 'SSF API debug logging');
47+
48+
-- Index for faster lookups by type (likely unnecessary given small table size, but follows best practices)
49+
CREATE INDEX idx_settings_value_type ON settings(value_type);
50+
51+
-- +goose StatementEnd
52+
53+
-- +goose Down
54+
-- +goose StatementBegin
55+
56+
DROP TABLE IF EXISTS settings CASCADE;
57+
58+
-- +goose StatementEnd

backend/internal/database/queries/projects.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,6 @@ RETURNING id, name, description, rules, start_date, end_date, logo_url,
265265
color_dark_text_default, color_dark_text_muted, color_dark_text_hint,
266266
color_dark_shadow_default, color_dark_shadow_blank, color_dark_border_default,
267267
rounding, archived;
268+
269+
-- name: ProjectExists :one
270+
SELECT EXISTS(SELECT 1 FROM projects WHERE id = @projectid::text);
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
-- name: GetSettingByKey :one
2+
SELECT key, value_text, value_int, value_bool, value_float, value_json, value_type, description, created_at, updated_at
3+
FROM settings
4+
WHERE key = @key::text;
5+
6+
-- name: GetSettingText :one
7+
SELECT value_text
8+
FROM settings
9+
WHERE key = @key::text
10+
AND value_type = 'text';
11+
12+
-- name: GetSettingInt :one
13+
SELECT value_int
14+
FROM settings
15+
WHERE key = @key::text
16+
AND value_type = 'int';
17+
18+
-- name: GetSettingBool :one
19+
SELECT value_bool
20+
FROM settings
21+
WHERE key = @key::text
22+
AND value_type = 'bool';
23+
24+
-- name: GetSettingFloat :one
25+
SELECT value_float
26+
FROM settings
27+
WHERE key = @key::text
28+
AND value_type = 'float';
29+
30+
-- name: GetSettingJSON :one
31+
SELECT value_json
32+
FROM settings
33+
WHERE key = @key::text
34+
AND value_type = 'json';
35+
36+
-- name: GetAllSettings :many
37+
SELECT key, value_text, value_int, value_bool, value_float, value_json, value_type, description, created_at, updated_at
38+
FROM settings
39+
ORDER BY key;
40+
41+
-- name: SetSettingText :exec
42+
INSERT INTO settings (key, value_text, value_type, description)
43+
VALUES (@key::text, @value_text::text, 'text', @description::text)
44+
ON CONFLICT (key) DO UPDATE
45+
SET value_text = EXCLUDED.value_text,
46+
value_type = 'text',
47+
description = COALESCE(EXCLUDED.description, settings.description),
48+
updated_at = NOW();
49+
50+
-- name: SetSettingInt :exec
51+
INSERT INTO settings (key, value_int, value_type, description)
52+
VALUES (@key::text, @value_int::bigint, 'int', @description::text)
53+
ON CONFLICT (key) DO UPDATE
54+
SET value_int = EXCLUDED.value_int,
55+
value_type = 'int',
56+
description = COALESCE(EXCLUDED.description, settings.description),
57+
updated_at = NOW();
58+
59+
-- name: SetSettingBool :exec
60+
INSERT INTO settings (key, value_bool, value_type, description)
61+
VALUES (@key::text, @value_bool::boolean, 'bool', @description::text)
62+
ON CONFLICT (key) DO UPDATE
63+
SET value_bool = EXCLUDED.value_bool,
64+
value_type = 'bool',
65+
description = COALESCE(EXCLUDED.description, settings.description),
66+
updated_at = NOW();
67+
68+
-- name: SetSettingFloat :exec
69+
INSERT INTO settings (key, value_float, value_type, description)
70+
VALUES (@key::text, @value_float::double precision, 'float', @description::text)
71+
ON CONFLICT (key) DO UPDATE
72+
SET value_float = EXCLUDED.value_float,
73+
value_type = 'float',
74+
description = COALESCE(EXCLUDED.description, settings.description),
75+
updated_at = NOW();
76+
77+
-- name: SetSettingJSON :exec
78+
INSERT INTO settings (key, value_json, value_type, description)
79+
VALUES (@key::text, @value_json::jsonb, 'json', @description::text)
80+
ON CONFLICT (key) DO UPDATE
81+
SET value_json = EXCLUDED.value_json,
82+
value_type = 'json',
83+
description = COALESCE(EXCLUDED.description, settings.description),
84+
updated_at = NOW();
85+
86+
-- name: DeleteSetting :exec
87+
DELETE FROM settings WHERE key = @key::text;

backend/internal/database/sqlc/models.go

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/internal/database/sqlc/projects.sql.go

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)