# ๐Ÿงช Test Users & Credentials โ€” GoHorseJobs All accounts below are provisioned by `seeder-api` against the DEV environment (`local.gohorsejobs.com` / `api-local.gohorsejobs.com`). > **Last verified:** 2026-02-24 > **Environment:** Coolify DEV (Redbull VPS) > **Auth endpoint:** `POST https://api-local.gohorsejobs.com/api/v1/auth/login` --- ## Login Payload Format ```json { "email": "", "password": "" } ``` The `"email"` JSON key accepts **both** the username (`identifier`) and the actual e-mail address. The backend resolves `WHERE email = $1 OR identifier = $1`. --- ## ๐Ÿ‘‘ SuperAdmin | Identifier | Email | Password | Role | |---|---|---|---| | `lol` | `lol@gohorsejobs.com` | `Admin@2025!` | superadmin | | `superadmin` | `admin@gohorsejobs.com` | `Admin@2025!` | superadmin | Both identifiers grant full system access. `lol` is the primary dev account; `superadmin` is the alias created by migration 010. --- ## ๐Ÿข Admins / Recruiters | Identifier | Email | Password | Role | Company | |---|---|---|---|---| | `takeshi_yamamoto` | `takeshi@techcorp.com` | `Takeshi@2025` | admin | TechCorp | | `kenji` | `kenji@appmakers.mobile` | `Takeshi@2025` | admin | AppMakers | | `maria_santos` | `maria@designhub.com` | `User@2025` | recruiter | DesignHub | | `wile_e_coyote` | `wile@acme.corp` | `MeepMeep@123` | admin | ACME Corporation | --- ## ๐Ÿ™‹ Candidates ### Unified Users (identifier-based login) | Identifier | Email | Password | Name | |---|---|---|---| | `paulo_santos` | `paulo@email.com` | `User@2025` | Paulo Santos | | `maria_email` | `maria@email.com` | `User@2025` | Maria Reyes | ### Legacy Candidates (email-based login) | Email | Password | Name | |---|---|---| | `ana.silva@example.com` | `User@2025` | Ana Silva | | `carlos.santos@example.com` | `User@2025` | Carlos Santos | | `maria.oliveira@example.com` | `User@2025` | Maria Oliveira | | `pedro.costa@example.com` | `User@2025` | Pedro Costa | | `juliana.ferreira@example.com` | `User@2025` | Juliana Ferreira | --- ## ๐ŸŒฑ Seeding & Reset ```bash # Reset all data (drops and recreates all public tables) curl -X POST https://s-local.gohorsejobs.com/reset # Re-seed everything (locations, users, companies, jobs, applications) curl https://s-local.gohorsejobs.com/seed/stream # After reset+seed, the backend must be reachable so migrations have already run. # The seeder does NOT apply Go migrations โ€” they run on backend startup. ``` > **Order matters after a full DB wipe:** > 1. Wait for the backend container to finish running migrations (check `GET /api/v1/jobs` returns `[]`) > 2. Then run `POST /reset` โ†’ `GET /seed/stream` --- ## โš ๏ธ Known Issues / Gotchas ### 1. `superadmin` login broken after DB reset (FIXED 2026-02-24) **Bug:** Migration `010_seed_super_admin.sql` creates the `superadmin` user with a hardcoded placeholder hash (`$invalid-placeholder-run-seeder$`). The seeder previously only updated `lol`'s hash, leaving `superadmin` permanently unable to log in after a DB reset. **Root cause:** `ON CONFLICT DO NOTHING` in migration 010 means the user exists in the DB but with an unusable hash. The seeder's upsert only covered the `lol` identifier. **Fix (commit `6b1c058`):** `seeder-api/src/seeders/users.js` now also upserts `superadmin` with the same runtime-generated hash as `lol`: ```js // Uses the same bcrypt(pass + PASSWORD_PEPPER) hash already computed for lol await pool.query(` INSERT INTO users (identifier, password_hash, ...) VALUES ('superadmin', $1, ...) ON CONFLICT (identifier) DO UPDATE SET password_hash = EXCLUDED.password_hash, status = 'active' `, [superAdminHash]); ``` **Affected versions:** All environments before `6b1c058`. Triggered on every fresh DB seed. --- ### 2. `users.status` column too short โ€” backend crash loop on startup (FIXED 2026-02-24) **Bug:** Migration `009_unify_schema.sql` defined `status VARCHAR(20)`. Migration `010_seed_super_admin.sql` tried to insert `'force_change_password'` (21 chars), crashing the backend with `pq: value too long for type character varying(20)` on every restart. **Fix (commit `e5e4397`):** - `009`: `VARCHAR(20)` โ†’ `VARCHAR(30)` - `010`: initial status changed from `'force_change_password'` โ†’ `'pending'` - New migration `046_fix_user_status_varchar.sql`: `ALTER TABLE users ALTER COLUMN status TYPE VARCHAR(30)` for existing deployments --- ### 3. `PASSWORD_PEPPER` must match between seeder and backend All password hashes are stored as `bcrypt(password + PASSWORD_PEPPER)`. Both the seeder-api and backend must have the **same** `PASSWORD_PEPPER` env var, or all logins return `401 invalid credentials`. **DEV value:** `gohorse-pepper` **Confirmed in:** Coolify backend env + Coolify seeder env If logins break after a deploy: check `docker inspect --format '{{.Config.Env}}'` for `PASSWORD_PEPPER`, then re-run the seeder. --- ### 4. Bash `!` expansion breaks login tests via curl When testing logins from the shell, passwords containing `!` (e.g. `Admin@2025!`) must be in a file or use `$'...'` syntax. Using `"Admin@2025!"` in double-quotes causes bash history expansion (`\!`), producing invalid JSON and a `400 Invalid Request`. ```bash # WRONG (bash expands !) curl ... -d '{"email":"lol","password":"Admin@2025!"}' # OK in single quotes curl ... -d "{\"email\":\"lol\",\"password\":\"Admin@2025!\"}" # BROKEN # CORRECT โ€” use a file cat > /tmp/login.json << 'EOF' {"email":"lol","password":"Admin@2025!"} EOF curl -X POST .../auth/login -d @/tmp/login.json ```