Data Layer
Most data access relationships between skuilder components are mediated by interface definitions:
interface UserDBInterface { /* ... */ }
interface CourseDBInterface { /* ... */ }
interface StudyContentSource { /* ... */ }
interface ClassroomDBInterface { /* ... */ }
// etcThis abstraction enables different deployment contexts (local-first static sites, live CouchDB backends, hybrid) to share the same application logic.
Initialization
Applications configure their data provider once at startup:
import { initializeDataLayer } from '@vue-skuilder/db';
await initializeDataLayer({
type: 'couch',
options: {
COUCHDB_SERVER_PROTOCOL: ENV.COUCHDB_SERVER_PROTOCOL,
COUCHDB_SERVER_URL: ENV.COUCHDB_SERVER_URL,
},
});import { initializeDataLayer } from '@vue-skuilder/db';
await initializeDataLayer({
type: 'static',
options: {
courseManifest: '/courses/manifest.json',
},
});After initialization, use getDataLayer() for access to specific resources:
import { getDataLayer } from '@vue-skuilder/db';
const courseDB = getDataLayer().getCourseDB('course-123');
const userDB = getDataLayer().getUserDB();Core Interfaces
UserDBInterface
Manages user-specific data: course registrations, card history, ELO ratings, scheduled reviews.
interface UserDBInterface {
// Course registration
getCourseRegistrations(): Promise<CourseRegistration[]>;
registerForCourse(courseId: string): Promise<void>;
// Card history
getCardHistory(cardId: string): Promise<CardHistory>;
putCardRecord(record: CardRecord): Promise<void>;
// Review scheduling
getPendingReviews(courseId: string): Promise<ScheduledCard[]>;
// ELO ratings
getCourseElo(courseId: string): Promise<CourseElo>;
}CourseDBInterface
Provides read access to course content: cards, tags, data shapes, and navigation strategies.
interface CourseDBInterface {
getCourseID(): string;
getCourseConfig(): Promise<CourseConfig>;
// Content access
getCard(cardId: string): Promise<CardData>;
getCardsByTag(tagId: string): Promise<CardData[]>;
getAppliedTags(cardId: string): Promise<string[]>;
// Navigation
createNavigator(user: UserDBInterface): Promise<StudyContentSource>;
getAllNavigationStrategies(): Promise<NavigationStrategyDoc[]>;
}StudyContentSource
The interface between course content and the study session. Navigation strategies implement this interface.
interface StudyContentSource {
getNewCards(n?: number): Promise<StudySessionNewItem[]>;
getPendingReviews(): Promise<StudySessionReviewItem[]>;
}The createNavigator() method on CourseDBInterface constructs an appropriate StudyContentSource based on the course's configured navigation strategies.
Implementations
Skuilder aims to be both local-first and platform-ready.
CouchDB / PouchDB
The primary implementation uses PouchDB on the client and CouchDB on the server:
- Client: PouchDB stores user data locally, syncs when online
- Server: CouchDB provides persistence, replication, and multi-user support
- Sync: Automatic bidirectional sync when connectivity allows
This enables offline study sessions with eventual consistency.
Static
For standalone deployments without a backend:
- Course data: Bundled as static JSON, served from CDN or local files
- User data: Stored in browser IndexedDB via PouchDB
- No sync: User data stays on the device
Ideal for single-course deployments, demos, and local development.
Navigation Strategies
Navigation strategies are stored as documents in the course database:
interface NavigationStrategyDoc {
_id: string;
docType: 'NAVIGATION_STRATEGY';
name: string;
strategyType: 'elo' | 'srs' | 'hierarchyDefinition' | 'interferenceMitigator' | 'relativePriority';
serializedData: string; // JSON config specific to strategy type
}When createNavigator() is called, the system:
- Fetches all navigation strategy documents for the course
- Assembles them into a pipeline (generators produce candidates, filters refine scores)
- Returns a
StudyContentSourcethat uses this pipeline
If no strategies are configured, a default ELO-based navigator is used.
See the Pedagogy System doc for details on available strategy types and their configuration.
Extending the Data Layer
To support a new backend or storage mechanism:
- Implement the core interfaces (
UserDBInterface,CourseDBInterface, etc.) - Create an initialization function that sets up the provider
- Register it as an option in
initializeDataLayer()
The application logic — study sessions, card rendering, SRS scheduling — remains unchanged.