feat(api): seed a dev login account (worker@solelog.local) for testing
db:seed now also creates a ready-made dev account via better-auth (properly hashed), idempotent, and SKIPPED when NODE_ENV=production so no known-password account ships to prod. Credentials: worker@solelog.local / werkplaats123. Documented in the worker README. API tests 37/37 green; verified live (sign-in returns a bearer token; /api/me returns the user).
This commit is contained in:
@@ -1,7 +1,13 @@
|
|||||||
import { pathToFileURL } from 'node:url';
|
import { pathToFileURL } from 'node:url';
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm';
|
||||||
import { db } from './client';
|
import { db } from './client';
|
||||||
import { activities } from './schema';
|
import { activities, user } from './schema';
|
||||||
|
import { auth } from '../auth';
|
||||||
|
|
||||||
|
// Dev-only test account so `db:seed` yields ready-made login credentials for local
|
||||||
|
// testing / phone demos. Created through better-auth (password is properly hashed).
|
||||||
|
// NEVER seeded when NODE_ENV=production — see seedDevUser().
|
||||||
|
const DEV_USER = { email: 'worker@solelog.local', password: 'werkplaats123', name: 'Test Werker' };
|
||||||
|
|
||||||
// Reference activities (realistic Dutch handeling names) — see
|
// Reference activities (realistic Dutch handeling names) — see
|
||||||
// docs/reference/legacy-mobile-app.md §6.2 and the Phase 1 plan.
|
// docs/reference/legacy-mobile-app.md §6.2 and the Phase 1 plan.
|
||||||
@@ -14,6 +20,17 @@ const REFERENCE_ACTIVITIES: { name: string; insoleTypes: string[] }[] = [
|
|||||||
{ name: 'Printen', insoleTypes: ['3D'] },
|
{ name: 'Printen', insoleTypes: ['3D'] },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Idempotent: create the dev account once, and only outside production (it has a
|
||||||
|
// known password). Uses better-auth's server API so the user + hashed-password
|
||||||
|
// account rows are created exactly as a real sign-up would.
|
||||||
|
async function seedDevUser(): Promise<void> {
|
||||||
|
if (process.env.NODE_ENV === 'production') return;
|
||||||
|
const existing = await db.select().from(user).where(eq(user.email, DEV_USER.email));
|
||||||
|
if (existing.length > 0) return;
|
||||||
|
await auth.api.signUpEmail({ body: DEV_USER });
|
||||||
|
console.log(`Seeded dev account: ${DEV_USER.email} / ${DEV_USER.password}`);
|
||||||
|
}
|
||||||
|
|
||||||
// Idempotent: insert each reference activity only if no activity with that name exists.
|
// Idempotent: insert each reference activity only if no activity with that name exists.
|
||||||
export async function seed(): Promise<void> {
|
export async function seed(): Promise<void> {
|
||||||
for (const activity of REFERENCE_ACTIVITIES) {
|
for (const activity of REFERENCE_ACTIVITIES) {
|
||||||
@@ -28,6 +45,7 @@ export async function seed(): Promise<void> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await seedDevUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow running directly: `tsx src/db/seed.ts` (cross-platform — pathToFileURL
|
// Allow running directly: `tsx src/db/seed.ts` (cross-platform — pathToFileURL
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest';
|
|||||||
import { inArray, eq } from 'drizzle-orm';
|
import { inArray, eq } from 'drizzle-orm';
|
||||||
import { seed } from '../src/db/seed';
|
import { seed } from '../src/db/seed';
|
||||||
import { db } from '../src/db/client';
|
import { db } from '../src/db/client';
|
||||||
import { activities } from '../src/db/schema';
|
import { activities, user } from '../src/db/schema';
|
||||||
|
|
||||||
const SEED_NAMES = ['Leerrand', 'Frezen', 'Slijpen', 'Bekleden', 'Afwerken', 'Printen'];
|
const SEED_NAMES = ['Leerrand', 'Frezen', 'Slijpen', 'Bekleden', 'Afwerken', 'Printen'];
|
||||||
|
|
||||||
@@ -31,4 +31,14 @@ describe('seed', () => {
|
|||||||
expect(printen).toHaveLength(1);
|
expect(printen).toHaveLength(1);
|
||||||
expect(printen[0]?.insoleTypes).toEqual(['3D']);
|
expect(printen[0]?.insoleTypes).toEqual(['3D']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('seeds the dev test account idempotently (and only once)', async () => {
|
||||||
|
await seed();
|
||||||
|
const first = await db.select().from(user).where(eq(user.email, 'worker@solelog.local'));
|
||||||
|
expect(first).toHaveLength(1);
|
||||||
|
|
||||||
|
await seed();
|
||||||
|
const second = await db.select().from(user).where(eq(user.email, 'worker@solelog.local'));
|
||||||
|
expect(second).toHaveLength(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -39,8 +39,10 @@ From the repo root:
|
|||||||
yarn workspace @solelog/worker dev # Vite dev server on http://localhost:5173
|
yarn workspace @solelog/worker dev # Vite dev server on http://localhost:5173
|
||||||
```
|
```
|
||||||
|
|
||||||
Open **http://localhost:5173** in any browser. There is a sign-up affordance on the login screen for
|
Open **http://localhost:5173** in any browser. `db:seed` creates a ready-made **dev login**:
|
||||||
creating a test account; after signing in you land on the Stopwatch tab.
|
**`worker@solelog.local`** / **`werkplaats123`** (dev-only — skipped when `NODE_ENV=production`).
|
||||||
|
Or use the sign-up affordance on the login screen to create your own account. After signing in you
|
||||||
|
land on the Stopwatch tab.
|
||||||
|
|
||||||
The API base URL comes from `VITE_API_URL` (default `http://localhost:3000`).
|
The API base URL comes from `VITE_API_URL` (default `http://localhost:3000`).
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user