26 - Add nix-shell and rewrite README
This commit is contained in:
parent
7c19684159
commit
ba6bb62e73
2 changed files with 221 additions and 122 deletions
195
README.md
195
README.md
|
|
@ -1,157 +1,108 @@
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
# 📈 incr
|
# incr
|
||||||
|
|
||||||
**A minimalist investment tracker for VWCE shares with milestone-driven progress**
|
**A minimalist counter with milestone-driven progress**
|
||||||
|
|
||||||
*Track your portfolio growth with visual progress indicators and milestone reinforcement*
|
*Track anything you accumulate — with visual progress and milestone reinforcement*
|
||||||
|
|
||||||
[](https://www.gnu.org/licenses/gpl-3.0)
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
||||||
[](https://www.docker.com/)
|
|
||||||
[](https://laravel.com/)
|
[](https://laravel.com/)
|
||||||
[](https://reactjs.org/)
|
[](https://reactjs.org/)
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**[Introduction](#introduction) • [Features](#features) • [Tech Stack](#tech-stack) • [Getting Started](#getting-started) • [Development](#development) • [Contributing](#contributing) • [License](#license)**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## Introduction
|
## About
|
||||||
|
|
||||||
Incr is a minimalist, one-page investment tracking application designed specifically for VWCE (Vanguard FTSE All-World UCITS ETF) shareholders. It combines the satisfaction of visual progress tracking with practical portfolio management, featuring a distinctive LED-style digital display and milestone-based goal setting.
|
incr is a minimalist, self-hosted tracking app. Pick something you want to accumulate — shares, books, workouts, anything — log your progress, and watch milestones fall.
|
||||||
|
|
||||||
The application emphasizes simplicity and focus, providing just what you need to track your investment journey without overwhelming complexity.
|
It features a distinctive LED-style digital display, configurable milestones, and optional price tracking.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **LED-style display**: Large red digital counter showing current share count
|
- **LED-style display** — large red digital counter
|
||||||
- **Progress tracking**: Visual progress bar toward configurable milestones
|
- **Milestone tracking** — set targets, cycle through them as you progress
|
||||||
- **Purchase management**: Add and track share purchases with historical data
|
- **Purchase logging** — add entries with date and optional price
|
||||||
- **Financial insights**: Portfolio value and withdrawal estimates
|
- **Price tracking** — optional; log a current price to see portfolio value and P/L
|
||||||
- **Milestone cycling**: Track progress toward multiple investment goals (1500→3000→4500→6000)
|
- **Self-hosted** — your data stays on your server
|
||||||
|
|
||||||
## Tech Stack
|
## Tech Stack
|
||||||
|
|
||||||
- **Backend**: Laravel 12 (PHP 8.2+) with MySQL database
|
- **Backend**: Laravel 12 (PHP 8.3+) with MySQL
|
||||||
- **Frontend**: React 19 + TypeScript with Inertia.js
|
- **Frontend**: React 19 + TypeScript with Inertia.js
|
||||||
- **Styling**: Tailwind CSS 4 with shadcn/ui components
|
- **Styling**: Tailwind CSS 4 with shadcn/ui components
|
||||||
- **Deployment**: Docker with multi-stage builds
|
- **Deployment**: Docker / Podman with multi-stage builds
|
||||||
|
|
||||||
## Getting Started
|
## Self-hosting
|
||||||
|
|
||||||
### Quick Start (Production)
|
```yaml
|
||||||
|
# docker-compose.yml
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
image: forge.lvl0.xyz/lvl0/incr:latest
|
||||||
|
container_name: incr-app
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- APP_ENV=production
|
||||||
|
- APP_DEBUG=false
|
||||||
|
- APP_KEY=base64:YOUR_APP_KEY_HERE
|
||||||
|
- DB_CONNECTION=mysql
|
||||||
|
- DB_HOST=db
|
||||||
|
- DB_PORT=3306
|
||||||
|
- DB_DATABASE=incr
|
||||||
|
- DB_USERNAME=incr_user
|
||||||
|
- DB_PASSWORD=change_me
|
||||||
|
ports:
|
||||||
|
- "5001:80"
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- incr-network
|
||||||
|
|
||||||
#### Docker
|
db:
|
||||||
|
image: mysql:8.0
|
||||||
|
container_name: incr-db
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- MYSQL_DATABASE=incr
|
||||||
|
- MYSQL_USER=incr_user
|
||||||
|
- MYSQL_PASSWORD=change_me
|
||||||
|
- MYSQL_ROOT_PASSWORD=change_me_root
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/mysql
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "incr_user", "-pchange_me"]
|
||||||
|
timeout: 10s
|
||||||
|
retries: 10
|
||||||
|
interval: 10s
|
||||||
|
start_period: 10s
|
||||||
|
networks:
|
||||||
|
- incr-network
|
||||||
|
|
||||||
Clone the repository and run with Docker Compose:
|
networks:
|
||||||
|
incr-network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
```bash
|
volumes:
|
||||||
git clone https://github.com/your-username/incr.git
|
db_data:
|
||||||
cd incr
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Run the application using the provided docker-compose configuration:
|
Generate an app key with: `php artisan key:generate --show`
|
||||||
|
|
||||||
|
The app will be available at `http://localhost:5001`.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
Requires [Nix](https://nixos.org/download/). Enter the dev shell:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Using Docker Compose
|
nix-shell
|
||||||
docker-compose -f docker/production/docker-compose.yml up --build
|
dev-up
|
||||||
|
|
||||||
# Or using Podman Compose
|
|
||||||
podman-compose -f docker/production/docker-compose.yml up --build
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The application will be available at `http://localhost:5001`.
|
Available commands inside the shell: `dev-up`, `dev-down`, `dev-rebuild`, `dev-logs`, `dev-shell`, `dev-artisan`, `dev-composer`.
|
||||||
|
|
||||||
### Development
|
|
||||||
|
|
||||||
#### Local Development Setup
|
|
||||||
|
|
||||||
**Option 1: Laravel Sail (Docker)**
|
|
||||||
|
|
||||||
For local development with Laravel Sail:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Install Laravel Sail
|
|
||||||
composer install
|
|
||||||
sail artisan sail:install
|
|
||||||
|
|
||||||
# Start development environment
|
|
||||||
sail up -d
|
|
||||||
|
|
||||||
# Install frontend dependencies and build assets
|
|
||||||
npm install
|
|
||||||
npm run dev
|
|
||||||
|
|
||||||
# Run migrations
|
|
||||||
sail artisan migrate
|
|
||||||
```
|
|
||||||
|
|
||||||
**Option 2: Podman Development**
|
|
||||||
|
|
||||||
For Fedora Atomic or other Podman-based systems:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Quick start with helper script
|
|
||||||
bash docker/dev/podman/start-dev.sh
|
|
||||||
|
|
||||||
# Or manually:
|
|
||||||
# Install podman-compose if not available
|
|
||||||
pip3 install --user podman-compose
|
|
||||||
|
|
||||||
# Start development environment
|
|
||||||
podman-compose -f docker/dev/podman/docker-compose.yml up -d
|
|
||||||
|
|
||||||
# Run migrations
|
|
||||||
podman exec incr-dev-app php artisan migrate
|
|
||||||
```
|
|
||||||
|
|
||||||
**Option 3: Sail with Podman (Compatibility Layer)**
|
|
||||||
|
|
||||||
To use Laravel Sail commands with Podman:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Source the alias script
|
|
||||||
source docker/dev/podman/podman-sail-alias.sh
|
|
||||||
|
|
||||||
# Now you can use sail commands as normal
|
|
||||||
sail up -d
|
|
||||||
sail artisan migrate
|
|
||||||
sail npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
The development server will be available at `http://localhost` with hot reload enabled.
|
|
||||||
|
|
||||||
## Project Structure
|
|
||||||
|
|
||||||
- `app/` - Laravel backend (controllers, models, services)
|
|
||||||
- `resources/js/` - React frontend components and pages
|
|
||||||
- `docker/production/` - Production Docker configuration
|
|
||||||
- `docker/dev/podman/` - Development Podman configuration
|
|
||||||
- `database/migrations/` - Database schema definitions
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
We welcome contributions to incr! Whether you're reporting bugs, suggesting features, or submitting pull requests, your input helps make this project better.
|
|
||||||
|
|
||||||
### How to Contribute
|
|
||||||
|
|
||||||
1. Fork the repository
|
|
||||||
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
||||||
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
||||||
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
||||||
5. Open a Pull Request
|
|
||||||
|
|
||||||
### Bug Reports
|
|
||||||
|
|
||||||
If you find a bug, please create an issue with:
|
|
||||||
- A clear description of the problem
|
|
||||||
- Steps to reproduce the issue
|
|
||||||
- Expected vs actual behavior
|
|
||||||
- Your environment details
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under the GNU General Public License v3.0 - see the [LICENSE](LICENSE) file for details.
|
GNU General Public License v3.0 — see [LICENSE](LICENSE).
|
||||||
|
|
|
||||||
148
shell.nix
Normal file
148
shell.nix
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
{ pkgs ? import <nixpkgs> {} }:
|
||||||
|
|
||||||
|
pkgs.mkShell {
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
# PHP and tools
|
||||||
|
php83
|
||||||
|
php83Packages.composer
|
||||||
|
|
||||||
|
# Node.js (needed for Tailwind CSS / Vite)
|
||||||
|
nodejs_22
|
||||||
|
|
||||||
|
# Container tools
|
||||||
|
podman
|
||||||
|
podman-compose
|
||||||
|
|
||||||
|
# Utilities
|
||||||
|
git
|
||||||
|
curl
|
||||||
|
gnumake
|
||||||
|
];
|
||||||
|
|
||||||
|
shellHook = ''
|
||||||
|
export USER_ID=$(id -u)
|
||||||
|
export GROUP_ID=$(id -g)
|
||||||
|
export PODMAN_USERNS=keep-id
|
||||||
|
|
||||||
|
# Compose file location
|
||||||
|
COMPOSE_FILE="$PWD/docker/dev/podman/docker-compose.yml"
|
||||||
|
|
||||||
|
# ===================
|
||||||
|
# ALIASES
|
||||||
|
# ===================
|
||||||
|
alias pc='podman-compose -f $COMPOSE_FILE'
|
||||||
|
|
||||||
|
# ===================
|
||||||
|
# DEV COMMANDS
|
||||||
|
# ===================
|
||||||
|
dev-up() {
|
||||||
|
echo "Starting services..."
|
||||||
|
PODMAN_USERNS=keep-id podman-compose -f $COMPOSE_FILE up -d "$@"
|
||||||
|
echo ""
|
||||||
|
podman-compose -f $COMPOSE_FILE ps
|
||||||
|
echo ""
|
||||||
|
echo "App available at: http://localhost:8000"
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-down() {
|
||||||
|
if [[ "$1" == "-v" ]]; then
|
||||||
|
echo "Stopping services and removing volumes..."
|
||||||
|
podman-compose -f $COMPOSE_FILE down -v
|
||||||
|
else
|
||||||
|
echo "Stopping services..."
|
||||||
|
podman-compose -f $COMPOSE_FILE down
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-restart() {
|
||||||
|
echo "Restarting services..."
|
||||||
|
podman-compose -f $COMPOSE_FILE restart "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-rebuild() {
|
||||||
|
echo "Rebuilding services (down -v + up)..."
|
||||||
|
podman-compose -f $COMPOSE_FILE down -v
|
||||||
|
PODMAN_USERNS=keep-id podman-compose -f $COMPOSE_FILE up -d "$@"
|
||||||
|
echo ""
|
||||||
|
podman-compose -f $COMPOSE_FILE ps
|
||||||
|
echo ""
|
||||||
|
echo "App available at: http://localhost:8000"
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-logs() {
|
||||||
|
podman-compose -f $COMPOSE_FILE logs -f app "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-logs-db() {
|
||||||
|
podman-compose -f $COMPOSE_FILE logs -f db "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-shell() {
|
||||||
|
podman-compose -f $COMPOSE_FILE exec app bash
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-artisan() {
|
||||||
|
podman-compose -f $COMPOSE_FILE exec app php artisan "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
dev-composer() {
|
||||||
|
podman-compose -f $COMPOSE_FILE exec app composer "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ===================
|
||||||
|
# BUILD COMMANDS
|
||||||
|
# ===================
|
||||||
|
base-build() {
|
||||||
|
local image="forge.lvl0.xyz/lvl0/incr:latest"
|
||||||
|
|
||||||
|
if ! podman login --get-login forge.lvl0.xyz &>/dev/null; then
|
||||||
|
echo "Not logged in to forge.lvl0.xyz"
|
||||||
|
podman login forge.lvl0.xyz || return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Building image: $image"
|
||||||
|
if ! podman build -t "$image" -f Dockerfile .; then
|
||||||
|
echo "Build failed!"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Pushing to registry..."
|
||||||
|
if ! podman push "$image"; then
|
||||||
|
echo "Push failed!"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Done! Image pushed: $image"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ===================
|
||||||
|
# WELCOME MESSAGE
|
||||||
|
# ===================
|
||||||
|
echo ""
|
||||||
|
echo "================================================="
|
||||||
|
echo " incr Dev Environment "
|
||||||
|
echo "================================================="
|
||||||
|
echo ""
|
||||||
|
echo " Podman: $(podman --version | cut -d' ' -f3)"
|
||||||
|
echo ""
|
||||||
|
echo "Commands:"
|
||||||
|
echo " dev-up [services] Start all or specific services"
|
||||||
|
echo " dev-down [-v] Stop services (-v removes volumes)"
|
||||||
|
echo " dev-rebuild Fresh start (down -v + up)"
|
||||||
|
echo " dev-restart Restart services"
|
||||||
|
echo " dev-logs Tail app logs"
|
||||||
|
echo " dev-logs-db Tail database logs"
|
||||||
|
echo " dev-shell Shell into app container"
|
||||||
|
echo " dev-artisan <cmd> Run artisan command"
|
||||||
|
echo " dev-composer <cmd> Run composer command"
|
||||||
|
echo " base-build Build and push image"
|
||||||
|
echo ""
|
||||||
|
echo "Services:"
|
||||||
|
echo " app Laravel http://localhost:8000"
|
||||||
|
echo " vite HMR http://localhost:5173"
|
||||||
|
echo " db MySQL localhost:3307"
|
||||||
|
echo ""
|
||||||
|
'';
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue