Guide for developers contributing to SPAYD Applied.
Required:
For FioFetch:
uv package manager (or pip)1. Clone the repository:
git clone https://github.com/pexmor/spayd-applied.git
cd spayd-applied
2. Install dependencies:
# Main app + Batch app
yarn install
# FioFetch backend
cd fio_fetch_py
uv sync # or: pip install -e .
cd ..
# FioFetch frontend
cd fio_fetch_webui
yarn install
cd ..
3. Verify installation:
# Main app
yarn dev
# FioFetch backend
cd fio_fetch_py
fiofetch
# FioFetch frontend
cd fio_fetch_webui
yarn dev
Recommended VS Code Extensions:
Browser DevTools:
src/
├── components/ # Preact components
│ ├── AccountManager.tsx
│ ├── EventManager.tsx
│ ├── PaymentForm.tsx
│ ├── PaymentHistory.tsx
│ ├── SyncQueue.tsx
│ ├── SettingsDialog.tsx
│ ├── ConfigWizard.tsx
│ ├── HamburgerMenu.tsx
│ ├── LanguageSwitcher.tsx
│ └── Dialog.tsx
├── services/ # Business logic
│ ├── payment-generator.ts
│ └── sync-service.ts
├── i18n/ # Translations
│ ├── index.ts
│ ├── cs.ts
│ └── en.ts
├── db.ts # IndexedDB wrapper
├── I18nContext.tsx # Language context
├── app.tsx # Main app component
└── main.tsx # Entry point
src/batch/
├── BatchApp.tsx # Main batch app
├── components/
│ ├── PeopleDataManager.tsx
│ ├── BatchAccountManager.tsx
│ ├── BatchEventManager.tsx
│ ├── EmailPreview.tsx
│ ├── ManualPaymentEntry.tsx
│ └── DataUpload.tsx
├── services/
│ ├── email-generator.tsx
│ └── storage.ts
├── templates/
│ └── PaymentEmail.tsx
└── utils/
└── iban-generator.ts
fio_fetch_py/
└── fiofetch/
├── __main__.py # CLI entry point
├── main.py # FastAPI app
├── api.py # API endpoints
├── fio.py # Fio Bank client
├── database.py # SQLite wrapper
├── models.py # Pydantic models
├── services.py # Business logic
├── config.py # Configuration
└── utils.py # Utilities
fio_fetch_webui/
└── src/
├── components/
│ ├── Dashboard.jsx
│ ├── TransactionList.jsx
│ ├── FetchControl.jsx
│ └── ConfigPanel.jsx
├── services/
│ ├── api.js
│ └── websocket.js
├── store/
│ └── useAppStore.js
├── App.jsx
└── index.jsx
Main App (SPAYD QR Generator):
yarn dev
# Access at http://localhost:5173
Batch App:
yarn dev
# Access at http://localhost:5173/batch.html
FioFetch Backend:
cd fio_fetch_py
fiofetch --fio-token YOUR_TOKEN --debug
# Access at http://localhost:3000
FioFetch Frontend:
cd fio_fetch_webui
yarn dev
# Access at http://localhost:5174
# Configure proxy to backend at :3000
All development servers support hot module replacement (HMR):
Inspect Storage:
spayd-db, batch-dbClear Storage:
// In browser console
indexedDB.deleteDatabase("spayd-db");
indexedDB.deleteDatabase("batch-db");
location.reload();
Migration Strategy: When changing schema:
db.tsonupgradeneededDatabase Location:
# Development
~/.config/fio_fetch/fio.db
# Docker
/root/.config/fio_fetch/fio.db
Inspect Database:
sqlite3 ~/.config/fio_fetch/fio.db
sqlite> .tables
sqlite> SELECT * FROM transactions LIMIT 5;
sqlite> .quit
Reset Database:
rm ~/.config/fio_fetch/fio.db
# Restart backend - will recreate tables
Style Guide:
Example Component:
import { h } from "preact";
import { useState, useEffect } from "preact/hooks";
interface Props {
accountId: string;
onSave: (data: AccountData) => void;
}
export const AccountForm = ({ accountId, onSave }: Props) => {
const [name, setName] = useState("");
const [iban, setIban] = useState("");
const handleSubmit = (e: Event) => {
e.preventDefault();
onSave({ name, iban });
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={(e) => setName(e.currentTarget.value)}
placeholder="Account Name"
/>
<input
type="text"
value={iban}
onChange={(e) => setIban(e.currentTarget.value)}
placeholder="IBAN"
/>
<button type="submit">Save</button>
</form>
);
};
Naming Conventions:
AccountManager.tsx)payment-generator.ts)generateQRCode)MAX_RETRIES)payment-form)Style Guide:
Example:
from typing import List, Optional
from pydantic import BaseModel
class Transaction(BaseModel):
"""Represents a bank transaction."""
id: int
amount: float
description: Optional[str] = None
async def fetch_transactions(
token: str,
days_back: int = 30
) -> List[Transaction]:
"""
Fetch transactions from Fio Bank API.
Args:
token: Fio Bank API token
days_back: Number of days to fetch (1-365)
Returns:
List of Transaction objects
Raises:
ValueError: If days_back is out of range
ConnectionError: If API is unreachable
"""
if not 1 <= days_back <= 365:
raise ValueError("days_back must be between 1 and 365")
# Implementation
...
Approach:
Example:
// Prefer Tailwind utilities
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Save
</button>
// Custom CSS for special cases
<div className="payment-form-grid">
{/* Complex grid layout */}
</div>
Custom CSS File Structure:
/* app.css */
.payment-form-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
Framework: pytest
Run Tests:
cd fio_fetch_py
pytest
# or
uv run pytest
# With coverage
pytest --cov=fiofetch --cov-report=html
Test Structure:
# tests/test_api.py
import pytest
from fiofetch.api import mask_token
def test_mask_token():
token = "ABC123XYZ789"
masked = mask_token(token)
assert masked == "ABC...789"
assert len(masked) < len(token)
@pytest.mark.asyncio
async def test_fetch_transactions(mock_fio_client):
transactions = await fetch_transactions(mock_fio_client)
assert len(transactions) > 0
assert transactions[0].amount > 0
Writing Tests:
tests/ directorytest_*.pyMain App Testing Checklist:
Batch App Testing:
FioFetch Testing:
Target Browsers:
Mobile Testing:
Tools:
Main App:
yarn build
# Output: dist/
Batch App:
yarn build
# Output: dist/batch.html
FioFetch:
# Backend - no build needed (Python)
# Frontend
cd fio_fetch_webui
yarn build
# Output: dist/
Vite automatically:
Manual Optimization:
# Analyze bundle size
yarn build
npx vite-bundle-visualizer
# Check for unused dependencies
npx depcheck
Automated Deployment:
main branchgh-pages branchManual Deployment:
# Build
yarn build
# Copy to docs/app (for GitHub Pages)
./copy-dist-to-docs.sh
# Commit and push
git add docs/app
git commit -m "Update production build"
git push origin main
Build Image:
./d10_build.sh
# or
docker build -t fiofetch:latest .
Run Container:
./d20_run.sh
# or
docker run -d -p 3000:3000 \
-v ~/.config/fio_fetch:/root/.config/fio_fetch \
fiofetch:latest
Production Considerations:
See DOCKER.md for complete guide.
git checkout -b feature/amazing-feature
git commit -m "feat: Add amazing feature"
git push origin feature/amazing-feature
Follow Conventional Commits:
<type>(<scope>): <subject>
<body>
<footer>
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting)refactor: Code refactoringtest: Adding/updating testschore: Build process, dependenciesExamples:
feat(batch): Add Excel import for people data
fix(fiofetch): Correct Fio API URL
docs(readme): Update installation instructions
refactor(db): Simplify IndexedDB wrapper
Before submitting:
PR Description Template:
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Documentation update
- [ ] Refactoring
## Testing
How to test these changes
## Screenshots (if applicable)
## Checklist
- [ ] Code follows style guidelines
- [ ] Tests added/updated
- [ ] Documentation updated
- [ ] No breaking changes (or documented)
mainQuestions?
yarn upgradeHappy coding! 🚀