Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .dockerEnvExample
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
OPENAI_API_KEY=sk-proj-...
PB_SUPERUSER_EMAIL=8eQJuw2mXjpHdxVnhBKF@example.com
PB_SUPERUSER_PASSWORD=8eQJuw2mXjpHdxVnhBKF
PB_VERSION=0.27.0
PB_VERSION=0.34.2
2 changes: 1 addition & 1 deletion .envExample
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ VITE_FUNCTIONS_URL=http://localhost:8081
VITE_POCKETBASE_URL=http://localhost:8080

# PocketBase (used in docker/staging)
PB_VERSION=0.27.0
PB_VERSION=0.34.2
20 changes: 18 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

pocket_base
node_modules
dist
dist-ssr
Expand All @@ -17,6 +16,19 @@ dist-ssr
.env
.dockerEnv

# PocketBase runtime files
*.db
*.db-shm
*.db-wal
pocketbase/pocketbase
pocketbase/LICENSE.md
pocketbase/CHANGELOG.md
pocketbase/pb_data/storage/

# Old PocketBase directories (for migration period)
pb/
pocket_base/

# Editor directories and files
.vscode/*
!.vscode/extensions.json
Expand All @@ -38,4 +50,8 @@ dist-ssr
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.yarn/install-state.gz

# AI
.cursor
.kiro
77 changes: 70 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ Fullstack is a comprehensive full stack project template with React frontend, No
git clone https://github.com/dastron/project.git
cd project

# Rename the project from template (interactive)
yarn rename

# Install dependencies
yarn install

Expand Down Expand Up @@ -46,12 +49,20 @@ yarn build
# Run PocketBase server only
yarn pb

# Generate migrations from Zod schemas
yarn migrate:generate

# Check migration status
yarn migrate:status

# Sync dev database migrations to/from project
yarn pb:sync


# Creates a migration snapshot of the current pb
yarn pb:snapshot

# Create/regenerate base snapshot from PocketBase
yarn pb:base-snapshot
```

### Testing & Quality
Expand All @@ -78,17 +89,69 @@ yarn why # Check why a package is installed

```
project/
├── app/ # Vite React frontend
├── app/ # Vite React frontend
│ └── package.json
├── functions/ # Node.js/Express backend
├── functions/ # Node.js/Express backend
│ └── package.json
├── shared/ # Shared code between workspaces
├── shared/ # Shared code between workspaces
│ ├── src/
│ │ └── schema/ # Zod schemas (source of truth for DB)
│ └── package.json
├── pb/ # PocketBase backend
├── package.json # Root configuration
├── pocketbase/ # PocketBase configuration
│ └── pb_migrations/ # Generated migration files
├── package.json # Root configuration
└── README.md
```

## Schema-Driven Migrations

This project uses a schema-driven approach where Zod schemas in `shared/src/schema/` serve as the single source of truth for the database structure. Migrations are automatically generated from these schemas.

### Base Snapshot

The migration system uses a **base snapshot** (`pocketbase/pb_migrations/000000000_collections_snapshot.js`) that represents PocketBase's initial state with system collections. This file:

- Contains PocketBase's default system collections (`_mfas`, `_otps`, `_externalAuths`, `_authOrigins`, `_superusers`)
- Includes the default `users` collection
- Serves as the starting point for schema comparisons
- Is automatically created during `yarn setup` if it doesn't exist

**When to regenerate the base snapshot:**
- After upgrading PocketBase versions (system collections may change)
- When setting up a new development environment
- If the base snapshot is missing or corrupted

```bash
yarn pb:base-snapshot
```

### Quick Start

1. **Define schema** in `shared/src/schema/entity.ts`:
```typescript
import { z } from "zod";
import { baseSchema } from "./base";

export const EntityInputSchema = z.object({
name: z.string().min(2),
status: z.enum(["active", "inactive"]),
});

export const EntitySchema = EntityInputSchema.extend(baseSchema);
```

2. **Generate migration**:
```bash
yarn migrate:generate
```

3. **Apply migration** (automatic on PocketBase startup):
```bash
yarn pb
```

For complete documentation, see [shared/MIGRATION_GUIDE.md](./shared/MIGRATION_GUIDE.md).

## Development Environment

### Prerequisites
Expand Down Expand Up @@ -120,7 +183,7 @@ project/
VITE_POCKETBASE_URL='http://localhost:8080' # PocketBase URL for frontend

# PocketBase (used in docker/staging)
PB_VERSION=0.27.0 # Specify desired PocketBase version
PB_VERSION=0.34.2 # Specify desired PocketBase version
```

3. Adjust the configuration as needed for your environment.
Expand Down
8 changes: 8 additions & 0 deletions app/setupTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,21 @@ Object.keys(collectionsConfig).forEach((collectionName) => {
>(collectionName);
});

const mockAuthStore = {
record: {
id: "123",
name: "Test User",
},
};

// Export the mock for use in your tests
export const TypedPocketBaseMock = {
...vi.importActual("@/pb"),
getFileUrl: vi.fn((item: any, file: string) => {
return `https://picsum.photos/seed/${item.id}/1200/600`;
}),
filter: vi.fn(),
authStore: mockAuthStore,
collection: vi.fn((name: string) => {
const collection = mockTypedPocketBase[name];
if (!collection) {
Expand Down
33 changes: 15 additions & 18 deletions app/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
import { mergeConfig } from "vite";
import { defineConfig } from "vitest/config";
import path from "path";

import viteConfig from "./vite.config";
import react from "@vitejs/plugin-react";
import tsconfigPaths from "vite-tsconfig-paths";
import { defineConfig } from "vitest/config";

export default mergeConfig(
viteConfig,
defineConfig({
test: {
environment: "happy-dom",
// globals: true,
// clearMocks: true,
// mockReset: true,
// restoreMocks: true,
setupFiles: ["setupTests.ts"],
alias: {
"@/": new URL("./src/", import.meta.url).pathname,
},
export default defineConfig({
plugins: [react(), tsconfigPaths()],
test: {
environment: "happy-dom",
setupFiles: ["setupTests.ts"],
},
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
})
);
},
});
2 changes: 1 addition & 1 deletion config/supervisord.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
nodaemon=true

[program:pocketbase]
command=/pb/pocketbase serve --http=0.0.0.0:8080
command=/pocketbase/pocketbase serve --http=0.0.0.0:8080
stopsignal=SIGTERM
stopasgroup=true
killasgroup=true
Expand Down
110 changes: 0 additions & 110 deletions dev-setup.sh

This file was deleted.

14 changes: 7 additions & 7 deletions dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,18 @@ RUN yarn build
###################################################
FROM alpine:latest AS pocketbase

ARG PB_VERSION=0.27.0
ARG PB_VERSION=0.34.2
ARG TARGETARCH
ENV ACTUAL_PB_VERSION=${PB_VERSION}

RUN apk add --no-cache unzip ca-certificates wget \
&& wget -q https://github.com/pocketbase/pocketbase/releases/download/v${ACTUAL_PB_VERSION}/pocketbase_${ACTUAL_PB_VERSION}_linux_${TARGETARCH}.zip -O /tmp/pb.zip \
&& unzip /tmp/pb.zip -d /pb/ \
&& unzip /tmp/pb.zip -d /pocketbase/ \
&& rm /tmp/pb.zip

COPY pb/pb_migrations /pb/pb_migrations
COPY pb/pb_data /pb/pb_data
COPY pb/pb_hooks /pb/pb_hooks
COPY pocketbase/pb_migrations /pocketbase/pb_migrations
COPY pocketbase/pb_data /pocketbase/pb_data
COPY pocketbase/pb_hooks /pocketbase/pb_hooks


###################################################
Expand All @@ -73,7 +73,7 @@ RUN apk add --no-cache --update nginx supervisor bash
# RUN corepack enable && corepack prepare yarn@4.7.0 --activate

# 1) Copy PocketBase from its build stage
COPY --from=pocketbase /pb /pb
COPY --from=pocketbase /pocketbase /pocketbase

# 2) Set up project workspace
WORKDIR /workspace
Expand All @@ -99,7 +99,7 @@ COPY --from=builder /repo/app/dist /usr/share/nginx/html
# 6) Nginx & Supervisor config and entrypoint
COPY config/nginx.conf /etc/nginx/nginx.conf
COPY config/supervisord.conf /etc/supervisord.conf
COPY entrypoint.sh /usr/local/bin/
COPY scripts/entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/entrypoint.sh

EXPOSE 80 8080 8081
Expand Down
Loading
Loading