feat: implement separate backup jobs for databases with MongoDB support

This commit is contained in:
biersoeckli
2025-12-09 14:46:35 +00:00
parent a2002c0416
commit 4af20278e0
12 changed files with 457 additions and 64 deletions

View File

@@ -1,6 +1,6 @@
# QuickStack AI Coding Instructions
QuickStack is a self-hosted PaaS built with Next.js 14 (App Router) that manages Kubernetes (k3s) deployments. It uses a custom server (`src/server.ts`) that wraps Next.js to handle WebSockets for terminal streaming.
QuickStack is a self-hosted PaaS built with Next.js 14 (App Router) that manages Kubernetes (k3s) deployments. It uses a custom server (`src/server.ts`) that wraps Next.js to handle WebSockets for terminal streaming and pod logs.
## Architecture Overview
@@ -10,18 +10,24 @@ QuickStack is a self-hosted PaaS built with Next.js 14 (App Router) that manages
- **`src/shared/`** - Shared models, utils, and Zod schemas (used by both frontend and server)
### Key Adapters (`src/server/adapter/`)
Adapters provide abstraction over external APIs:
- `kubernetes-api.adapter.ts` - Wraps `@kubernetes/client-node` APIs (`k3s.core`, `k3s.apps`, etc.)
- `db.client.ts` - Prisma singleton (`dataAccess.client`)
- `db.client.ts` - Prisma singleton (`dataAccess.client`) with custom transaction helpers
- `longhorn-api.adapter.ts` - Longhorn storage API
- `aws-s3.adapter.ts` - S3-compatible storage operations
### Service Pattern
Services are singleton classes exported as default instances:
```typescript
class AppService { /* methods */ }
class AppService {
async buildAndDeploy(appId: string) { /* ... */ }
}
const appService = new AppService();
export default appService;
```
**Standalone Services** (`src/server/services/standalone-services/`): Can run outside Next.js request context (e.g., at app startup, scheduled tasks). See `00_info.md` for details.
## Server Actions Pattern
All server actions use wrappers from `src/server/utils/action-wrapper.utils.ts`:
@@ -43,67 +49,104 @@ export const deleteApp = async (id: string) =>
});
```
### Authorization Helpers
- `getAuthUserSession()` - Requires authenticated user, redirects to `/auth` if not
- `getAdminUserSession()` - Requires admin role
- `isAuthorizedReadForApp(appId)` - Checks read permissions for specific app
- `isAuthorizedWriteForApp(appId)` - Checks write permissions for specific app
- `isAuthorizedForBackups()` - Checks backup permissions
## Database & Prisma
- SQLite database at `storage/db/data.db`
- **SQLite** database at `storage/db/data.db` (using `@prisma/adapter-better-sqlite3`)
- Schema: `prisma/schema.prisma`
- Zod schemas auto-generated to `src/shared/model/generated-zod/`
- After schema changes: `yarn prisma-migrate` (runs `prisma migrate dev` + fixes Zod imports)
- Use `dataAccess.client` for queries, supports transactions via `$transaction()`
- After schema changes: **`yarn prisma-migrate`** (runs `prisma migrate dev` + fixes Zod imports via `fix-wrong-zod-imports.js`)
- Access via `dataAccess.client` for queries
- Supports transactions: `dataAccess.client.$transaction(async (tx) => { ... })`
- Custom batch update helpers: `dataAccess.updateManyItems()` and `dataAccess.updateManyItemsWithExistingTransaction()`
**Critical**: After Prisma schema changes, `yarn prisma-migrate` automatically fixes incorrect Zod imports that `zod-prisma` generator produces.
## Kubernetes Naming Conventions
Use `KubeObjectNameUtils` for consistent k8s object names:
- `toProjectId(name)``proj-{name}-{hash}`
Use `KubeObjectNameUtils` (`src/server/utils/kube-object-name.utils.ts`) for consistent k8s object names:
- `toProjectId(name)``proj-{name}-{hash}` (max 30 chars + prefix)
- `toAppId(name)``app-{name}-{hash}`
- `toPvcName(volumeId)``pvc-{volumeId}`
- `toJobName(appId)``build-{appId}`
- `toServiceName(appId)``svc-{appId}`
- `toPvcName(volumeId)``pvc-{volumeId}`
- `addRandomSuffix(str)``{str}-{8-char-hex}`
## Frontend Patterns
All names are snake_case → kebab-case, lowercased, with non-alphanumeric chars removed.
### State Management
Zustand stores in `src/frontend/states/zustand.states.ts`:
- `useConfirmDialog` - Promise-based confirmation dialogs
- `useInputDialog` - Promise-based input dialogs
- `useBreadcrumbs` - Page breadcrumb navigation
## Caching & Revalidation
### UI Components
- shadcn/ui components in `src/components/ui/`
- Custom components in `src/components/custom/`
- Forms use `react-hook-form` with Zod resolvers
Next.js `unstable_cache` with tag-based invalidation using `Tags` utility (`src/server/utils/cache-tag-generator.utils.ts`):
### Real-time Updates
- Socket.IO server at `/pod-terminal` namespace for terminal streaming
- WebSocket server for live pod logs
## Caching
Next.js `unstable_cache` with tag-based invalidation:
```typescript
// Reading with cache
await unstable_cache(
async () => dataAccess.client.app.findMany({ where: { projectId } }),
[Tags.apps(projectId)],
{ tags: [Tags.apps(projectId)] }
)(projectId);
)();
// Invalidating after mutations
revalidateTag(Tags.apps(projectId));
revalidateTag(Tags.app(appId));
```
**Available Tags**: `users()`, `userGroups()`, `projects()`, `apps(projectId)`, `app(appId)`, `appBuilds(appId)`, `s3Targets()`, `volumeBackups()`, `parameter()`, `nodeInfos()`
## Frontend Patterns
### State Management
Zustand stores in `src/frontend/states/zustand.states.ts`:
- `useConfirmDialog()` - Promise-based confirmation dialogs
- `useInputDialog()` - Promise-based input dialogs
- `useBreadcrumbs()` - Page breadcrumb navigation
### UI Components
- **shadcn/ui** components in `src/components/ui/`
- Custom components in `src/components/custom/`
- Forms use `react-hook-form` with `@hookform/resolvers` and Zod schemas
### Real-time Communication
- **Socket.IO** (`src/socket-io.server.ts`): `/pod-terminal` namespace for terminal streaming
- **WebSocket** (`src/websocket.server.ts`): Generic WebSocket server for live pod logs
## Custom Server Entry Point
`src/server.ts` wraps Next.js to handle:
1. WebSocket/Socket.IO initialization
2. Database migration on production startup (`npx prisma migrate deploy`)
3. QuickStack initialization (`quickStackService.initializeQuickStack()`)
4. Standalone services (backups, maintenance, password changes, app logs)
Run with `yarn dev-live` (builds TypeScript from `tsconfig.server.json``dist/server.js`)
## Testing
- Jest with jsdom environment
- Jest with jsdom environment (`jest.config.ts`)
- Tests in `src/__tests__/{frontend,server,shared}/`
- Path alias `@/` maps to `src/`
- Run: `yarn test`
- Coverage: Collected automatically, output to `coverage/`
## Development Setup
1. Use provided devcontainer (includes Node, Bun, Prisma extension)
2. Provide k3s credentials in `kube-config.config` at project root
3. `yarn install``yarn dev` for Next.js or `yarn dev-live` for custom server
3. `yarn install`
4. Development modes:
- `yarn dev` - Standard Next.js dev server
- `yarn dev-live` - Custom server with WebSocket support (rebuilds TypeScript)
- `yarn build` - Production build (Next.js + custom server compilation)
- `yarn start-prod` - Run production build with custom server
## Commit Convention
Follow Conventional Commits: `feat:`, `fix:`, `refactor:`, `docs:`, `test:`, `chore:`
Follow [Conventional Commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `refactor:`, `docs:`, `test:`, `chore:`, `style:`
Example: `feat: add database backup scheduling`