Add seed service to initialize default admin and organization

- Implement `SeedService` to create a default admin account and organization on app startup.
- Update `PrismaModule` to include `SeedService` as a provider.
- Remove seeded credentials display from login page.
- Refactor existing seed script for consistency with the new service.
main
Pau Costa Ferrer 2026-03-28 18:07:22 +01:00
parent 5fe893c7ce
commit 93bd2808ac
5 changed files with 67 additions and 22 deletions

View File

@ -4,17 +4,10 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="6c8b3c54-eabb-40e5-967f-c7b594c750bc" name="Changes" comment="Add rotation support for spaces in floorplan editor &#10;&#10;- Extend `Space` model and Prisma schema to include `rotation` property. &#10;- Update API services and DTOs to handle rotation data. &#10;- Add UI controls in `FloorplanEditor.svelte` for rotating spaces. &#10;- Refactor space rendering logic in both editor and viewer to support rotation.">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/web/src/lib/components/BookingModal.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/lib/components/BookingModal.svelte" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/web/src/lib/components/FloorplanViewer.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/lib/components/FloorplanViewer.svelte" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/web/src/lib/i18n/locales/en.json" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/lib/i18n/locales/en.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/web/src/lib/i18n/locales/es-ES.json" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/lib/i18n/locales/es-ES.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/web/src/routes/admin/reports/+page.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/routes/admin/reports/+page.svelte" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/web/src/routes/admin/users/+page.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/routes/admin/users/+page.svelte" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/web/src/routes/dashboard/+page.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/routes/dashboard/+page.svelte" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/web/src/routes/dashboard/building/[id]/+page.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/routes/dashboard/building/[id]/+page.svelte" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/web/src/routes/dashboard/my-bookings/+page.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/routes/dashboard/my-bookings/+page.svelte" afterDir="false" />
<list default="true" id="6c8b3c54-eabb-40e5-967f-c7b594c750bc" name="Changes" comment="Add i18n integration and translations for improved localization&#10;&#10;- Extend English (`en.json`) and Spanish (`es-ES.json`) locale files with additional keys for buildings, bookings, reports, and user management. &#10;- Update Svelte components and pages to use `svelte-i18n` for dynamic translations across the app. &#10;- Refactor labels, titles, and error messages for multilingual support. &#10;- Improve date formatting based on locale preferences.">
<change beforePath="$PROJECT_DIR$/apps/api/prisma/seed.ts" beforeDir="false" afterPath="$PROJECT_DIR$/apps/api/prisma/seed.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/api/src/prisma/prisma.module.ts" beforeDir="false" afterPath="$PROJECT_DIR$/apps/api/src/prisma/prisma.module.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/apps/web/src/routes/login/+page.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/routes/login/+page.svelte" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -136,7 +129,7 @@
<updated>1774643312599</updated>
<workItem from="1774643313611" duration="74000" />
<workItem from="1774643422240" duration="5278000" />
<workItem from="1774706361502" duration="10700000" />
<workItem from="1774706361502" duration="11023000" />
</task>
<task id="LOCAL-00001" summary="Initialize Hot Desking app with web and API services &#10;&#10;- Set up SvelteKit for the web interface with Tailwind CSS. &#10;- Build the API using NestJS with Prisma ORM for database interaction. &#10;- Add environment variable management and docker-compose for PostgreSQL and PgAdmin instances. &#10;- Create shared data models for consistent typing across services. &#10;- Establish basic routing and layouts for web and API services.">
<option name="closed" value="true" />
@ -298,7 +291,15 @@
<option name="project" value="LOCAL" />
<updated>1774716452045</updated>
</task>
<option name="localTasksCounter" value="21" />
<task id="LOCAL-00021" summary="Add i18n integration and translations for improved localization&#10;&#10;- Extend English (`en.json`) and Spanish (`es-ES.json`) locale files with additional keys for buildings, bookings, reports, and user management. &#10;- Update Svelte components and pages to use `svelte-i18n` for dynamic translations across the app. &#10;- Refactor labels, titles, and error messages for multilingual support. &#10;- Improve date formatting based on locale preferences.">
<option name="closed" value="true" />
<created>1774717104130</created>
<option name="number" value="00021" />
<option name="presentableId" value="LOCAL-00021" />
<option name="project" value="LOCAL" />
<updated>1774717104130</updated>
</task>
<option name="localTasksCounter" value="22" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
@ -327,6 +328,7 @@
<MESSAGE value="Update prompts to include progress indicator for documentation readability" />
<MESSAGE value="Add Docker deployment support for API and Web services&#10;&#10;- Add Dockerfiles for API and Web apps with multi-stage builds.&#10;- Configure `docker-compose.yml` to manage services (Postgres, API, Web, pgAdmin).&#10;- Add `.dockerignore` for optimized builds.&#10;- Include `DOCKER_SETUP.md` for deployment steps and guidance." />
<MESSAGE value="Add rotation support for spaces in floorplan editor &#10;&#10;- Extend `Space` model and Prisma schema to include `rotation` property. &#10;- Update API services and DTOs to handle rotation data. &#10;- Add UI controls in `FloorplanEditor.svelte` for rotating spaces. &#10;- Refactor space rendering logic in both editor and viewer to support rotation." />
<option name="LAST_COMMIT_MESSAGE" value="Add rotation support for spaces in floorplan editor &#10;&#10;- Extend `Space` model and Prisma schema to include `rotation` property. &#10;- Update API services and DTOs to handle rotation data. &#10;- Add UI controls in `FloorplanEditor.svelte` for rotating spaces. &#10;- Refactor space rendering logic in both editor and viewer to support rotation." />
<MESSAGE value="Add i18n integration and translations for improved localization&#10;&#10;- Extend English (`en.json`) and Spanish (`es-ES.json`) locale files with additional keys for buildings, bookings, reports, and user management. &#10;- Update Svelte components and pages to use `svelte-i18n` for dynamic translations across the app. &#10;- Refactor labels, titles, and error messages for multilingual support. &#10;- Improve date formatting based on locale preferences." />
<option name="LAST_COMMIT_MESSAGE" value="Add i18n integration and translations for improved localization&#10;&#10;- Extend English (`en.json`) and Spanish (`es-ES.json`) locale files with additional keys for buildings, bookings, reports, and user management. &#10;- Update Svelte components and pages to use `svelte-i18n` for dynamic translations across the app. &#10;- Refactor labels, titles, and error messages for multilingual support. &#10;- Improve date formatting based on locale preferences." />
</component>
</project>

View File

@ -7,13 +7,13 @@ async function main() {
const hashedPassword = await bcrypt.hash('admin123', 10);
const org = await prisma.organization.upsert({
where: { id: 'test-org-id' },
where: { id: 'default-org-id' },
update: {
logoUrl: 'https://images.unsplash.com/photo-1542744173-8e7e53415bb0?q=80&w=200&h=200&auto=format&fit=crop',
},
create: {
id: 'test-org-id',
name: 'Test Organization',
id: 'default-org-id',
name: 'Default Organization',
logoUrl: 'https://images.unsplash.com/photo-1542744173-8e7e53415bb0?q=80&w=200&h=200&auto=format&fit=crop',
},
});

View File

@ -1,9 +1,10 @@
import { Global, Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';
import { SeedService } from './seed.service';
@Global()
@Module({
providers: [PrismaService],
providers: [PrismaService, SeedService],
exports: [PrismaService],
})
export class PrismaModule {}

View File

@ -0,0 +1,46 @@
import { Injectable, OnModuleInit, Logger } from '@nestjs/common';
import { PrismaService } from './prisma.service';
import * as bcrypt from 'bcrypt';
import { Role } from '@prisma/client';
@Injectable()
export class SeedService implements OnModuleInit {
private readonly logger = new Logger(SeedService.name);
constructor(private prisma: PrismaService) {}
async onModuleInit() {
await this.seed();
}
async seed() {
const userCount = await this.prisma.user.count();
if (userCount === 0) {
this.logger.log('No users found in database. Seeding default admin account...');
const hashedPassword = await bcrypt.hash('admin123', 10);
const org = await this.prisma.organization.upsert({
where: { id: 'default-org-id' },
update: {},
create: {
id: 'default-org-id',
name: 'Default Organization',
logoUrl: 'https://images.unsplash.com/photo-1542744173-8e7e53415bb0?q=80&w=200&h=200&auto=format&fit=crop',
},
});
await this.prisma.user.create({
data: {
email: 'admin@example.com',
password: hashedPassword,
role: Role.ADMIN,
organizationId: org.id,
},
});
this.logger.log('Default admin account created: admin@example.com / admin123');
}
}
}

View File

@ -74,10 +74,6 @@
</div>
<button type="submit" class="w-full bg-blue-600 text-white p-2 rounded hover:bg-blue-700 font-semibold transition-colors">Sign In</button>
</form>
<div class="mt-6 text-center text-sm text-gray-500">
<p>Use seeded credentials:</p>
<p class="font-mono mt-1">admin@example.com / admin123</p>
</div>
{/if}
</div>
</div>