name: database description: Understand onepixel database topology by environment, data ownership across app/events stores, and initialization/migration behavior.
Database Skill
Use this skill when changing config, models, controllers, or test setup that touches persistence.
Which databases are used in each environment
- Local/dev defaults (
onepixel.local.env):- App DB:
sqlite(DB_DIALECT=sqlite,DATABASE_URL=app.db) - Events DB:
duckdb(EVENTDB_DIALECT=duckdb,EVENTDB_URL=events.db) USE_FILE_DB=trueenables file-backed providers.
- App DB:
- Test (
ENV=test+onepixel.test.env):- App DB:
sqlite(app.db) - Events DB:
duckdb(events.db) - Tests import
onepixel_backend/tests/providersto inject test DB providers.
- App DB:
- Production template (
onepixel.production.env):USE_FILE_DB=falseenables network DB providers.- App DB:
postgres(DB_DIALECT=postgres). - Events DB: also
postgresby default becauseCOMMON_APP_EVENT_DB=trueandEVENTDB_DIALECT=postgres. - Note: code supports
clickhousefor events whenEVENTDB_DIALECT=clickhouseandCOMMON_APP_EVENT_DB=false.
What data is stored in which database
- App DB (OLTP/domain entities):
users(models.User)url_groups(models.UrlGroup)urls(models.Url)
- Events DB (analytics/time-series style):
events_redirect(models.EventRedirect)- Stores redirect telemetry: short URL identifiers, creator/group IDs, IP/user-agent, referer, and GeoIP fields.
- GeoIP DB:
- Separate MMDB file (
./GeoLite2-City.mmdb), opened bydb.GetGeoIPDB()for enrichment; not managed by GORM migrations.
- Separate MMDB file (
How DBs are initialized
- Initialization is singleton-based in
src/db/init.go:GetAppDB,GetEventsDB, andGetGeoIPDBeach guarded bysync.Once.
- Runtime startup in
src/main.goeagerly initializes all three DB clients. - Providers are registered in
db.init()based onconfig.UseFileDB:- file mode:
sqlite,duckdb - network mode:
postgres,clickhouse
- file mode:
- Provider implementations live in
src/db/providers.go:postgres/clickhouseopen with retry (attemptToOpen, 10 attempts with 1s delay).sqlite/duckdbopen directly.
How schema changes (migrations) work
- Migrations are automatic via GORM
AutoMigrateinsrc/db/init.go. - App DB migration flow (
GetAppDB):- Migrates
User,UrlGroup,Url. - Failures panic (
lo.Must0), so startup/first access fails fast.
- Migrates
- Events DB migration flow (
GetEventsDB):- Attempts to migrate
EventRedirect. - Failure is logged but not fatal (
lo.TryWithErrorValue+applogger.Error).
- Attempts to migrate
- There are no SQL migration files or versioned migration runner; model changes are applied opportunistically at DB initialization time.
Test-specific DB wiring details
tests/providers/test_db_providers.gooverridessqliteandduckdbproviders viadb.InjectDBProvider.- Tests activate overrides through side-effect imports (
_ "onepixel_backend/tests/providers"). make test_cleanremovesapp.dbandevents.dbbefore each test suite target.ENV=testalso changes cwd to repo root insrc/config/env.go, ensuring relative DB paths resolve consistently.