@ -36,7 +36,6 @@ This application is built on a privacy-preserving claims architecture (via endor
- **Merkle-Chained Claims** : Claims are cryptographically chained for verification and integrity
- **Native and Web App** : Works on iOS, Android, and web browsers
## User Journey
The typical progression of usage follows these stages:
@ -47,7 +46,6 @@ The typical progression of usage follows these stages:
3. **Action Triggers** : Offers of help serve as triggers and motivations to execute proposed projects, moving from ideas to action.
## Context for LLM Development
When developing new functionality for Time Safari, consider these design principles:
@ -66,7 +64,6 @@ When developing new functionality for Time Safari, consider these design princip
7. **Low Resource Requirements** : The system should be lightweight enough to run on inexpensive devices users already own.
## Use Cases to Support
LLM development should focus on enhancing these key use cases:
@ -79,7 +76,6 @@ LLM development should focus on enhancing these key use cases:
4. **Governance Experimentation** : Features that facilitate decision-making and collective governance.
## Constraints
When developing new features, be mindful of these constraints:
@ -94,7 +90,38 @@ When developing new features, be mindful of these constraints:
5. **Offline-First When Possible** : Key functionality should work offline when feasible.
# Core Development Principles
## Project Technologies
- Typescript using ES6 classes
- TailwindCSS
- Vite Build Tool
- Playwright E2E testing
- IndexDB
- Camera, Image uploads, QR Code reader, ...
## Mobile Features
- Deep Linking
- Local Notifications via a custom Capacitor plugin
## Project Architecture
- The application must work on web browser, PWA (Progressive Web Application), desktop via Electron, and mobile via Capacitor
- Building for each platform is managed via Vite
## Core Development Principles
- DRY development
- SOLID principles
- Law of Demeter
- Composition over Inheritence
- Interface Segregation
- Fail Fast
- Principle of Least Astonishment
- Information Hiding
- Single Source of Truth
- Principle of Least Privilege
- Continuous Integration/Continuous Deployment (CI/CD)
- Ensure all components support accessibility first design
- Implement privacy-preserving features by default
- Support progressive enhancement across devices
@ -102,229 +129,62 @@ When developing new features, be mindful of these constraints:
- Build trust-enabling interactions
- Optimize for low resource requirements
- Support offline-first functionality where possible
- Use class-based syntax with decorators from vue-facing-decorators.
- Should attempt to maximize Lighthouse Score as close to 100 as possible.
- Use Lighthouse for performance scoring
## Vue Component Structure
# Vue Component Structure
- Use `@Options` , `@Ref` , `@Prop` , `@Emit` , and `@Watch` decorators for clear component structure
- Use `@Options` , `@Ref` , `@Prop` , `@Emit` , and `@Watch` Typescript decorators for clear component structure
- Extend `Vue` class with proper type annotations for props, refs, and methods
- Use Tailwind utility classes for accessible and responsive design
- Avoid `setup()` or Composition API; use class syntax consistently
- Keep methods pure when possible; extract logic into utilities
- Ensure lifecycle methods are clearly defined inside class
- Use semantic HTML + Tailwind classes for styling
[rules.component-class]
description = "Create a privacy-aware Vue 3 component"
trigger = "vfd-component"
insert = """
import { Options, Vue } from 'vue-facing-decorator'
import { PlatformService } from '@/services/platform'
@Options ({
name: 'MyComponent',
props: {},
emits: ['error', 'privacy-consent'],
})
export default class MyComponent extends Vue {
private platformService = new PlatformService()
// Lifecycle
mounted() {
this.checkPrivacyConsent()
}
// Privacy check
private async checkPrivacyConsent() {
const hasConsent = await this.platformService.getPrivacyConsent()
if (!hasConsent) {
this.$emit('privacy-consent-needed')
}
}
// Error handling
protected handleError(error: Error) {
console.error('Component error:', error)
this.$emit('error', error)
}
}
"""
[rules.decorator-prop]
description = "Add a validated prop with privacy considerations"
trigger = "vfd-prop"
insert = """
@Prop ({
required: true,
validator: (value: any) => {
// Add validation logic
return typeof value === 'string' & & value.length > 0
}
})
propName!: string
"""
[rules.decorator-watch]
description = "Watch a property with offline support"
trigger = "vfd-watch"
insert = """
@Watch ('myProp')
async onMyPropChanged(newVal: any, oldVal: any) {
try {
// Handle offline state
if (!navigator.onLine) {
await this.queueOfflineChange(newVal)
return
}
await this.processChange(newVal)
} catch (error) {
this.handleError(error as Error)
}
}
"""
[rules.decorator-emit]
description = "Emit a privacy-aware event"
trigger = "vfd-emit"
insert = """
@Emit ('data-update')
async emitPrivateData() {
const privateData = await this.platformService.getEncryptedData()
return privateData
}
"""
[rules.component-template]
description = "Create an accessible component template"
trigger = "vfd-component-full"
insert = """
< template >
< div
class="p-4 bg-white dark:bg-gray-800"
:aria-label="accessibilityLabel"
>
< h2
class="text-lg font-semibold text-gray-900 dark:text-white"
:id="headingId"
>
{{ title }}
< / h2 >
< div
class="mt-4"
:aria-labelledby="headingId"
>
< slot > < / slot >
< / div >
<!-- Offline indicator -->
< div
v-if="!isOnline"
class="text-sm text-amber-600 mt-2"
role="alert"
>
Currently offline - changes will sync when connection is restored
< / div >
< / div >
< / template >
< script lang = "ts" >
import { Options, Vue } from 'vue-facing-decorator'
import { generateUniqueId } from '@/utils/accessibility'
@Options ({
name: 'MyComponent',
props: {
title: String,
accessibilityLabel: String
}
})
export default class MyComponent extends Vue {
title!: string
accessibilityLabel!: string
headingId = generateUniqueId()
isOnline = navigator.onLine
mounted() {
window.addEventListener('online', this.updateOnlineStatus)
window.addEventListener('offline', this.updateOnlineStatus)
}
beforeUnmount() {
window.removeEventListener('online', this.updateOnlineStatus)
window.removeEventListener('offline', this.updateOnlineStatus)
}
updateOnlineStatus() {
this.isOnline = navigator.onLine
}
}
< / script >
"""
[rules.async-method]
description = "Add an async method with offline support and error handling"
trigger = "vfd-async"
insert = """
async fetchData(): Promise< void > {
try {
if (!navigator.onLine) {
const cachedData = await this.getCachedData()
if (cachedData) {
this.data = cachedData
return
}
throw new Error('No cached data available offline')
}
const response = await this.apiService.getData()
this.data = response
await this.cacheData(response)
} catch (error) {
this.handleError(error as Error)
this.$emit('error', error)
}
}
"""
[rules.privacy-aware-component]
description = "Create a privacy-aware component with DID handling"
trigger = "vfd-privacy"
insert = """
import { Options, Vue } from 'vue-facing-decorator'
import { PlatformService } from '@/services/platform'
import { DidService } from '@/services/did'
@Options ({
name: 'PrivacyAwareComponent',
props: {
requiredPermissions: Array
}
})
export default class PrivacyAwareComponent extends Vue {
private platformService = new PlatformService()
private didService = new DidService()
requiredPermissions!: string[]
userDid = ''
async mounted() {
await this.checkPermissions()
await this.initializeDid()
}
private async initializeDid() {
try {
this.userDid = await this.didService.getCurrentDid()
} catch (error) {
this.handleError(error as Error)
}
}
private async checkPermissions() {
for (const permission of this.requiredPermissions) {
const hasPermission = await this.platformService.checkPermission(permission)
if (!hasPermission) {
this.$emit('permission-required', permission)
return
}
}
}
}
"""
- Pinia for state management
## Vue Facing Decorators
- Ensure all Vue 3 components are written using TypeScript with strict type checking enabled.
- Always include explicit types for props, emits, and reactive properties.
- When using @Options , ensure it includes metadata like name, template, or styles.
- Use @Prop for defining props with validation and default values.
- Use @Emit for emitting events with proper payload typing.
- Use @Watch for reactive property changes, and @Ref for DOM references."
- Organize Vue 3 components with a clear structure: imports at the top, followed by @Options metadata, then class properties (props, refs, reactive state), lifecycle hooks, methods, and finally @Watch or @Emit handlers.
- Ensure all props have explicit types and optional validation.
- Use TypeScript interfaces or types for complex prop structures.
- Validate default values for props where applicable.
- Use lifecycle hooks (e.g., onMounted, onUnmounted) sparingly and document their purpose.
- Avoid side effects in lifecycle hooks unless absolutely necessary.
- Use @Emit for emitting events with strongly typed payloads.
- Ensure event names are descriptive and match the action being performed.
- Use ref or reactive for managing internal state.
- Avoid overusing reactive state for simple values. Prefer computed properties for derived state.
- Write unit tests for components using Vue Test Utils and Jest/Vitest.
- Ensure tests cover props, events, and lifecycle behavior.
- Avoid unnecessary re-renders by using v-once for static content and memoizing expensive computations with computed properties.
- Ensure components are accessible by using semantic HTML and ARIA attributes.
- Use scoped styles or CSS modules to encapsulate styles.
## es6 classes
- Use ES6 class syntax with decorators (@Options, @Prop , @Emit ).
- Use modular imports and default exports.
- Use arrow functions for methods and callbacks.
- Use destructuring for props and state.
- Provide default parameters for optional props or arguments.
- Use template literals for dynamic strings.
- Use spread/rest operators for object manipulation and arguments.
- Use const/let appropriately for variable declarations.
- Use enhanced object literals for cleaner syntax.
- Use async/await for asynchronous operations.
- Add scoped styles for encapsulation.
- Ensure accessibility with semantic HTML and ARIA attributes.
## Documentation
- Include JSDoc comments for all public methods and props.
- Files must have comments explaing contents and workflow of file
- Methods and props should explain role and workflow of each