A personal portfolio website showcasing design and development work. Built with clean architecture, layered design patterns, and modern web technologies.
/talkThis project follows a layered architecture for better separation of concerns:
Components ā Stores ā Services ā API Client ā API Endpoints
ā ā
UI State PocketBase
src/lib/services.ts)src/lib/store.svelte.ts)src/lib/server/index.ts)package.json)# Clone the repository
git clone <repository-url>
cd folio
# Install dependencies
pnpm install
# Start PocketBase (in a separate terminal)
./pb/pocketbase serve
# Start development server
pnpm dev
The site will be available at http://localhost:5173
Create a .env file:
# PocketBase connection
PUBLIC_POCKETBASE_URL=http://127.0.0.1:8090
# Admin credentials for PocketBase
PB_ADMIN_EMAIL=your_admin_email
PB_ADMIN_PASSWORD=your_admin_password
# Legacy admin token (optional fallback)
ADMIN_TOKEN=your_secret_admin_token
# IP whitelist for /start admin route (optional)
ADMIN_IP=your_ip_address
src/
āāā lib/
ā āāā services.ts # API service layer
ā āāā store.svelte.ts # Reactive stores (Svelte 5 runes)
ā āāā apiClient.ts # Enhanced fetch with auth
ā āāā types.ts # TypeScript interfaces
ā āāā pocketbase-types.ts # PocketBase collection types
ā āāā markdown.ts # Markdown parser
ā āāā seo.ts # SEO utilities
ā āāā theme.svelte.ts # Theme management
ā āāā components/ # Reusable UI components
ā ā āāā start/ # Admin components
ā ā āāā chat/ # Chat components
ā āāā _fx/ # Visual effects
ā āāā server/ # Server-side utilities
ā āāā index.ts # Barrel export
ā āāā pb.ts # PocketBase client
ā āāā security.server.ts
ā āāā api-utils.server.ts
ā āāā talk.server.ts
āāā routes/
ā āāā (public)/ # Public pages
ā ā āāā about/
ā ā āāā projects/
ā āāā (private)/ # Admin interface
ā ā āāā start/
ā āāā (canvas)/ # Experimental projects
ā ā āāā talk/
ā āāā api/ # REST API endpoints
ā āāā projects/
ā āāā talk/
āāā hooks.server.ts # Server hooks (auth, IP whitelist, theme)
āāā static/ # Static assets
āāā assets/
āāā videos/
pb/ # PocketBase binary and data
# Development mode with hot reload
pnpm dev
# Type checking
pnpm check
# Linting and formatting
pnpm lint
pnpm format
# Build for production
pnpm build
# Preview production build
pnpm preview
All API calls are centralized in src/lib/services.ts:
import { ProjectService } from '$lib/services';
// Fetch all projects
const projects = await ProjectService.fetchAll();
// Create project (with auto auth)
const newProjects = await ProjectService.create(project);
Stores manage reactive state using $state and $derived:
import { Projects } from '$lib/store.svelte';
// Access reactive state
const allProjects = Projects.all;
const filteredProjects = Projects.selected;
// Trigger actions
await Projects.fetchProjects();
Server-side utilities are centralized via barrel export:
import { withAdmin, respondJson, createPBClient } from '$lib/server';
// Use in API endpoints
export const POST = withAdmin(async ({ request, locals }) => {
// locals.pb is the authenticated PocketBase client
const data = await request.json();
return respondJson({ success: true });
});
Access the admin dashboard at /start (requires auth + IP whitelist):
Access PocketBase admin UI at http://127.0.0.1:8090/_/:
Case studies support rich markdown with custom syntax:
!# Build the application
pnpm build
# Start the server
node build
Set environment variables:
PUBLIC_POCKETBASE_URL - PocketBase server URLPB_ADMIN_EMAIL / PB_ADMIN_PASSWORD - Admin credentialsADMIN_TOKEN - Legacy admin token (optional)PocketBase can be:
The project supports multiple sub-projects under /(canvas):
app.csssrc/lib/componentsSee LICENSE file.