chore: pull all docs into sources/
This commit is contained in:
1
worker-toolkit-stocks-in-the-future/explore/repo
Symbolic link
1
worker-toolkit-stocks-in-the-future/explore/repo
Symbolic link
@@ -0,0 +1 @@
|
||||
/home/ericbell/workspaces/dataannotation/current-project/worker-toolkit-stocks-in-the-future/repo
|
||||
10
worker-toolkit-stocks-in-the-future/explore/toolkit.json
Normal file
10
worker-toolkit-stocks-in-the-future/explore/toolkit.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"repo": "stocks-in-the-future",
|
||||
"defaultCommit": "63732df2",
|
||||
"version": "ecee90d5cb",
|
||||
"explorePorts": {
|
||||
"clientHost": 3700,
|
||||
"serverHost": null,
|
||||
"corpusHost": null
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
# Stocks for Good developer documentation
|
||||
|
||||
Welcome to the internal documentation for _Stocks for Good_.
|
||||
|
||||
This section of the repository is dedicated to **technical documentation**
|
||||
intended for developers, contributors, and future maintainers. It covers system
|
||||
architecture, development practices, and design decisions that influence how the
|
||||
app is built and evolves.
|
||||
|
||||
---
|
||||
|
||||
## 📚 Index
|
||||
|
||||
- [Architecture Overview](architecture/index.md)
|
||||
- [Database seeds](seeds.md)
|
||||
- [Background job scheduling](scheduling.md)
|
||||
- [Schema](schema.md)
|
||||
- [Orders And Transactions](orders-and-transactions.md)
|
||||
- [GradeBook Earnings](gradebook-earnings.md)
|
||||
- [Old site](old-site/README.md)
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
While the main `README.md` in the root of the repository is designed to help users
|
||||
and new developers get started quickly, this `/docs` directory provides deeper
|
||||
insight into:
|
||||
|
||||
- **How** the system works under the hood
|
||||
- **Why** certain frameworks, gems, and patterns were chosen
|
||||
- **What** trade-offs were considered during development
|
||||
|
||||
This documentation serves as both a knowledge base and a decision log.
|
||||
|
||||
---
|
||||
|
||||
## Writing Guidelines
|
||||
|
||||
- Write in plain Markdown (`.md`) so it remains portable and readable on GitHub
|
||||
and in any editor.
|
||||
- Prefer **clarity over completeness** — focus on what someone else (or future-you)
|
||||
would need to understand.
|
||||
- Include dates and authors on major decisions when helpful.
|
||||
|
||||
---
|
||||
@@ -1,32 +0,0 @@
|
||||
# GradeBook Earnings
|
||||
|
||||
Students earn money in their portfolios through attendance and grades in their classes. This document outlines how these grade book earnings are calculated and recorded in the system.
|
||||
|
||||
## Grade Book Structure
|
||||
- Each classroom has a grade book for each quarter of the school year.
|
||||
- At the end of each quarter, teachers and/or admins enter attendance and grades for each student in the classroom.
|
||||
- *Note*: This grade book is only used to calculate earnings. This system is not responsible for individual grade management or report cards.
|
||||
- The following [entries](../app/models/grade_entry.rb) are supported for each student in the class for the grade book:
|
||||
- Number of days attended
|
||||
- Perfect Attendance (boolean)
|
||||
- Reading Grade
|
||||
- Math Grade
|
||||
|
||||
## Earnings Calculation
|
||||
- Once grades have been entered, an admin can "finalize" the grade book for the quarter. This action will calculate earnings for each student based on their attendance and grades and create the corresponding transactions in their portfolios.
|
||||
- The earnings are calculated as follows:
|
||||
- Attendance:
|
||||
- $0.20 per day attended
|
||||
- $1.00 bonus for perfect attendance
|
||||
- Grades:
|
||||
- Reading Grade in the A range: $3.00
|
||||
- Reading Grade in the B range: $2.00
|
||||
- Math Grade in the A range: $3.00
|
||||
- Math Grade in the B range: $2.00
|
||||
- Grade Improvements
|
||||
- If a student's grade improves from the previous quarter, they receive an additional bonus:
|
||||
- Improvement in Reading Grade: $2.00
|
||||
- Improvement in Math Grade: $2.00
|
||||
- *Note* We currently are not looking at improvements across school years. So there are no improvement bonuses for the first quarter of a school year.
|
||||
|
||||
See the [DistributeEarnings](../app/services/distribute_earnings.rb) class for the implementation of this logic.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.9 KiB |
@@ -1,23 +0,0 @@
|
||||
#### Old Site Documentation
|
||||
|
||||
This folder contains documentation from the previous iteration of the site
|
||||
|
||||
### IMPORTANT DIFFERENCES
|
||||
|
||||
Our current goals for the new application include
|
||||
|
||||
* Reworking the attendence workflow to be much, much simpler
|
||||
* Skipping the extra step of "verifying" the information after it is entered
|
||||
|
||||
Things we are not working on:
|
||||
|
||||
* Not implementing quizzes
|
||||
* Not working on banner messages / message of the day messages
|
||||
* Not working on links or other external information
|
||||
|
||||
If you find yourself starting to work on any of the above, please stop.
|
||||
|
||||
We're also not currently working on dividends at the moment. Maybe someday we'll be ready to add this to the system, though.
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 251 KiB |
@@ -1,40 +0,0 @@
|
||||
# Orders and Transactions
|
||||
|
||||
This document outlines how orders and transactions function in terms of this application.
|
||||
Note that due to the fundamental way in which this system works, these concepts are different than you might typically expect from a stock trading platform.
|
||||
|
||||
## [Orders](../app/models/order.rb)
|
||||
- Students can place buy or sell orders for stocks. These orders are not executed immediately but are pending until they are processed by the [OrderExecutionJob](../app/jobs/order_execution_job.rb) at the end of each day.
|
||||
- Currently, this job runs at midnight Eastern Time.
|
||||
- Students can cancel or update their pending orders at any time before they have been executed.
|
||||
- At this time, orders can only be placed for whole shares of stock (no fractional shares).
|
||||
- When placing an order, the price of the stock is a known value. This is because we only update the stock prices once per day, and we execute all pending orders before updating the prices for the next day.
|
||||
|
||||
### Transaction Fees
|
||||
- There is a flat transaction fee of $1.00 per student per day for executing orders, regardless of the number of orders placed.
|
||||
- Here are some examples:
|
||||
- A student places a buy order for 2 shares of stock A at $10 each. They will be charged $20 for the shares plus a $1 transaction fee, totaling $21.
|
||||
- A student places buy orders for 1 share of stock A at $10 and 1 share of stock B at $15 on the same day. They will be charged $10 + $15 + $1 transaction fee, totaling $26.
|
||||
- A student places a sell order for 3 shares of stock A at $10 each. They will receive $30 from the sale minus the $1 transaction fee, totaling $29.
|
||||
|
||||
### Validations
|
||||
|
||||
#### Buy Orders
|
||||
- When placing a buy order, the system checks if the student has sufficient cash in their portfolio to cover the cost of the shares plus the $1 transaction fee.
|
||||
- Note that the system must correctly consider that multiple buy orders placed on the same day will incur only a single $1 transaction fee.
|
||||
- The system also considers the total cost of all buy orders placed on that day when validating if the student has enough cash.
|
||||
|
||||
#### Sell Orders
|
||||
- When placing a sell order, the system checks if the student has enough shares of the stock they wish to sell in their portfolio.
|
||||
|
||||
## [Transactions](../app/models/portfolio_transaction.rb)
|
||||
- Transactions are records of cash movements in a student's portfolio.
|
||||
- Transactions can be of the following types:
|
||||
- **Deposit** - represents cash added to the portfolio through earnings from gradebook or manual deposits by teachers/admins
|
||||
- **Withdrawal** - represents cash removed from the portfolio by admins
|
||||
- **Credit** - represents cash received from selling stocks
|
||||
- **Debit** - represents cash spent on buying stocks
|
||||
- **Fee** - represents the $1 transaction fee charged for executing orders
|
||||
- Transactions can be associated with an order if they are the result of executing a buy or sell order. However not every transaction is linked to an order (e.g., deposits, withdrawals, and fees).
|
||||
- Transactions are immutable records and should not be edited or deleted after they are created
|
||||
- Note that the transactions table is designed to be a ledger, thus if you want to calculate the current cash balance of a portfolio, you should sum up all the transactions. This is why the portfolios table does not have a cash balance column.
|
||||
@@ -1,299 +0,0 @@
|
||||
# Responsive Design Guidelines
|
||||
|
||||
**Target Users:** Students on Chromebooks
|
||||
**Last Updated:** 2025-10-19
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
- [Overview](#overview)
|
||||
- [Breakpoints](#breakpoints)
|
||||
- [Touch Targets](#touch-targets)
|
||||
- [Typography](#typography)
|
||||
- [Spacing & Layout](#spacing--layout)
|
||||
- [Tables](#tables)
|
||||
- [Forms](#forms)
|
||||
- [Images & Media](#images--media)
|
||||
- [Navigation](#navigation)
|
||||
- [Testing Requirements](#testing-requirements)
|
||||
- [Common Patterns](#common-patterns)
|
||||
- [Quick Reference](#quick-reference)
|
||||
- [Checklist](#checklist)
|
||||
- [Additional Resources](#additional-resources)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
> ✅ Use only `base` and `lg:` responsive tiers.
|
||||
> Test all UI components at **375px** and **1366px** before submitting PRs.
|
||||
|
||||
These guidelines ensure a consistent, accessible responsive design across the **Stocks in the Future** application.
|
||||
All contributors working on responsive features must follow these standards.
|
||||
|
||||
**Core Principles**
|
||||
- 🎯 **Mobile-first:** Design for the smallest screen and scale up.
|
||||
- 💻 **Chromebook-focused:** 1366×768 is our main target.
|
||||
- ✋ **Touch-friendly:** Minimum 44px touch targets.
|
||||
- 🎨 **Tailwind-only:** No custom CSS.
|
||||
- ♿ **Accessible:** WCAG AA minimum compliance.
|
||||
|
||||
---
|
||||
|
||||
## Breakpoints
|
||||
|
||||
We only support **two responsive tiers**:
|
||||
|
||||
| Mode | Screen Size | Tailwind Prefix | Example Devices | Priority |
|
||||
|------|--------------|----------------|------------------|-----------|
|
||||
| **Base (mobile)** | up to 1023px | *(no prefix)* | Phones, tablets | Medium |
|
||||
| **Chromebook/Desktop** | 1024px+ | `lg:` | Chromebooks, desktops | **CRITICAL** |
|
||||
|
||||
### Why Only Two?
|
||||
|
||||
- 1366×768 is the **most common Chromebook resolution**.
|
||||
- Simplifies layout logic and testing.
|
||||
- Matches real classroom usage.
|
||||
- Keeps Tailwind classes minimal and maintainable.
|
||||
|
||||
### Example
|
||||
|
||||
```html
|
||||
<!-- Mobile-first base styles -->
|
||||
<div class="px-4">Mobile padding</div>
|
||||
|
||||
<!-- Add styles for larger screens -->
|
||||
<div class="px-4 lg:px-8">Responsive padding</div>
|
||||
|
||||
<!-- Show/hide elements -->
|
||||
<div class="lg:hidden">Mobile only</div>
|
||||
<div class="hidden lg:block">Desktop only</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Touch Targets
|
||||
|
||||
### Minimum Sizes
|
||||
|
||||
| Element | Minimum | Preferred | Notes |
|
||||
|----------|----------|------------|--------|
|
||||
| Buttons | 44×44px | 48×48px | Use `min-h-[44px]` or larger |
|
||||
| Inputs | 44px height | 48px height | Use `py-3` minimum |
|
||||
| Checkboxes | 24×24px | 32×32px | Make label clickable |
|
||||
| Icon buttons | 44×44px | 48×48px | Hamburger, close, etc. |
|
||||
|
||||
### Spacing
|
||||
|
||||
```html
|
||||
<!-- Minimum 8px spacing between targets -->
|
||||
<div class="flex gap-2">
|
||||
<button class="min-h-[44px] px-4">Action</button>
|
||||
<button class="min-h-[44px] px-4">Action</button>
|
||||
</div>
|
||||
|
||||
<!-- Preferred 16px spacing -->
|
||||
<div class="flex gap-4">
|
||||
<button class="min-h-[48px] px-6">Primary</button>
|
||||
<button class="min-h-[48px] px-6">Secondary</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Typography
|
||||
|
||||
| Element | Mobile (`base`) | Chromebook (`lg:`) |
|
||||
|----------|------------------|--------------------|
|
||||
| H1 | `text-2xl` (24px) | `lg:text-4xl` (36px) |
|
||||
| H2 | `text-xl` (20px) | `lg:text-3xl` (30px) |
|
||||
| Body | `text-base` (16px) | `lg:text-lg` (18px) |
|
||||
| Small | `text-sm` (14px) | `lg:text-base` (16px) |
|
||||
|
||||
**Rules**
|
||||
1. Never go below 14px (`text-sm`) for body text.
|
||||
2. Use responsive Tailwind typography classes (`text-xl lg:text-3xl`).
|
||||
3. Maintain heading hierarchy.
|
||||
|
||||
**Example**
|
||||
```html
|
||||
<h1 class="text-2xl lg:text-4xl font-bold">Welcome to Your Financial Journey</h1>
|
||||
<p class="text-base lg:text-lg">This is your launchpad to earn, invest, and grow.</p>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Spacing & Layout
|
||||
|
||||
### Container Padding
|
||||
|
||||
```html
|
||||
<main class="px-4 lg:px-8">
|
||||
<!-- Content -->
|
||||
</main>
|
||||
|
||||
<div class="p-4 lg:p-8">
|
||||
<!-- Card content -->
|
||||
</div>
|
||||
```
|
||||
|
||||
### Grids and Flex Layouts
|
||||
|
||||
```html
|
||||
<!-- Stack on mobile, row on desktop -->
|
||||
<div class="flex flex-col lg:flex-row gap-4">
|
||||
<div class="flex-1">Left</div>
|
||||
<div class="flex-1">Right</div>
|
||||
</div>
|
||||
|
||||
<!-- Stack to grid -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
||||
<div>Card 1</div>
|
||||
<div>Card 2</div>
|
||||
<div>Card 3</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tables
|
||||
|
||||
### Responsive Table Pattern
|
||||
|
||||
```html
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full border-collapse">
|
||||
<thead>
|
||||
<tr class="border-b border-black">
|
||||
<th class="px-4 lg:px-7 py-3 text-left text-sm lg:text-base">Stock</th>
|
||||
<th class="hidden lg:table-cell px-7 py-3 text-right">Price</th>
|
||||
<th class="px-4 lg:px-7 py-3 text-right text-sm lg:text-base">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="border-b">
|
||||
<td class="px-4 lg:px-7 py-2 text-sm lg:text-base">AAPL</td>
|
||||
<td class="hidden lg:table-cell px-7 py-2 text-right">$150.00</td>
|
||||
<td class="px-4 lg:px-7 py-2 text-right">
|
||||
<button class="min-h-[44px] px-4">Buy</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Forms
|
||||
|
||||
```html
|
||||
<input
|
||||
type="text"
|
||||
class="w-full lg:max-w-md px-4 py-3 text-base border rounded-lg"
|
||||
placeholder="Enter amount"
|
||||
/>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full lg:w-auto px-6 py-3 min-h-[48px] bg-blue-600 text-white rounded-lg"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Images & Media
|
||||
|
||||
```html
|
||||
<img src="piggy-bank.png" class="w-24 lg:w-32 h-auto" alt="Piggy bank">
|
||||
|
||||
<div class="overflow-hidden rounded-lg">
|
||||
<img src="chart.png" class="w-full h-auto" alt="Stock chart">
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Navigation
|
||||
|
||||
```html
|
||||
<input type="checkbox" id="menu-toggle" class="hidden peer" />
|
||||
|
||||
<label for="menu-toggle" class="lg:hidden flex items-center justify-center w-10 h-10">
|
||||
<svg class="w-6 h-6">...</svg>
|
||||
</label>
|
||||
|
||||
<nav class="fixed top-0 bottom-0 left-0 w-64 transform -translate-x-full peer-checked:translate-x-0 lg:translate-x-0 transition-transform">
|
||||
<!-- Nav links -->
|
||||
</nav>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Requirements
|
||||
|
||||
### Test at Two Sizes
|
||||
|
||||
- ✅ 375px — Mobile (base)
|
||||
- ✅ 1366px — Chromebook (lg)
|
||||
|
||||
### Checklist
|
||||
|
||||
- [ ] No horizontal scroll
|
||||
- [ ] Minimum text size 14px
|
||||
- [ ] All touch targets ≥44px
|
||||
- [ ] Forms and buttons are touch-friendly
|
||||
- [ ] Navigation accessible
|
||||
- [ ] Layout consistent on Chromebook
|
||||
|
||||
---
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Card
|
||||
|
||||
```html
|
||||
<div class="bg-white border-2 border-black rounded-[20px] p-4 lg:p-8">
|
||||
<h2 class="text-xl lg:text-3xl font-bold mb-4">Card Title</h2>
|
||||
<p class="text-base lg:text-lg">Card content</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Button Group
|
||||
|
||||
```html
|
||||
<div class="flex flex-col lg:flex-row gap-3">
|
||||
<button class="w-full lg:w-auto px-6 py-3 min-h-[48px] bg-blue-600 text-white rounded-lg">Primary</button>
|
||||
<button class="w-full lg:w-auto px-6 py-3 min-h-[48px] border-2 border-black rounded-lg">Secondary</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
```
|
||||
(no prefix) = up to 1023px (mobile-first)
|
||||
lg: = 1024px+ (Chromebook/Desktop)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Checklist
|
||||
- [ ] Uses Tailwind-only classes
|
||||
- [ ] Works at 375px and 1366px
|
||||
- [ ] No horizontal scroll
|
||||
- [ ] All touch targets ≥44px
|
||||
- [ ] Accessible labels and contrast
|
||||
|
||||
---
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Tailwind CSS Responsive Design](https://tailwindcss.com/docs/responsive-design)
|
||||
- [WCAG Touch Target Guidelines](https://www.w3.org/WAI/WCAG21/Understanding/target-size.html)
|
||||
- [Mobile-First Design Principles](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Responsive/Mobile_first)
|
||||
|
||||
---
|
||||
@@ -1,275 +0,0 @@
|
||||
# Job Scheduling with Solid Queue
|
||||
|
||||
This document explains how stock-related jobs are scheduled to run automatically using Rails 8's **Solid Queue** system.
|
||||
|
||||
## Overview
|
||||
|
||||
The application uses **Solid Queue** for both job processing and recurring job scheduling. This provides a unified, database-backed system that works identically across all environments (development, staging, production).
|
||||
|
||||
### Scheduled Jobs
|
||||
|
||||
1. **OrderExecutionJob** - Executes pending stock orders (both buy and sell) at 1:00 AM ET weekdays only (Monday-Friday)
|
||||
2. **StockPricesUpdateJob** - Updates stock prices from Alpha Vantage API (automatically triggered after OrderExecutionJob)
|
||||
3. **MonthlyPortfolioSnapshotJob** - Creates portfolio snapshots on the last day of each month at 11:00 PM ET
|
||||
|
||||
## Configuration
|
||||
|
||||
### Recurring Jobs Configuration
|
||||
The scheduling configuration is defined in [`config/recurring.yml`](../config/recurring.yml):
|
||||
|
||||
```yaml
|
||||
development: &default
|
||||
daily_order_execution:
|
||||
class: OrderExecutionJob
|
||||
queue: default
|
||||
schedule: "0 6 * * 1-5" # Monday-Friday at 6 AM UTC (1 AM EST)
|
||||
|
||||
monthly_portfolio_snapshot:
|
||||
class: MonthlyPortfolioSnapshotJob
|
||||
queue: default
|
||||
schedule: "0 23 L * *" # Last day of month at 11 PM UTC
|
||||
|
||||
production:
|
||||
<<: *default
|
||||
```
|
||||
|
||||
### Worker Configuration
|
||||
Worker settings are configured in [`config/queue.yml`](../config/queue.yml):
|
||||
|
||||
```yaml
|
||||
default: &default
|
||||
dispatchers:
|
||||
- polling_interval: 1
|
||||
batch_size: 500
|
||||
workers:
|
||||
- queues: "*"
|
||||
threads: 3
|
||||
processes: <%= ENV.fetch("JOB_CONCURRENCY", 1) %>
|
||||
polling_interval: 0.1
|
||||
```
|
||||
|
||||
## Job Execution Flow
|
||||
|
||||
### Daily Stock Processing (1:00 AM ET, Weekdays Only)
|
||||
1. **OrderExecutionJob** runs first (scheduled via recurring.yml)
|
||||
- Processes all pending buy/sell orders
|
||||
- Applies transaction fees
|
||||
- **Automatically triggers** StockPricesUpdateJob upon completion
|
||||
- **Only runs Monday through Friday** (weekdays)
|
||||
|
||||
2. **StockPricesUpdateJob** runs second (triggered by OrderExecutionJob)
|
||||
- Updates current stock prices from Alpha Vantage API
|
||||
- Saves yesterday's prices for historical tracking
|
||||
- **Only runs on weekdays** (when OrderExecutionJob runs)
|
||||
|
||||
### Monthly Portfolio Snapshots (Last Day, 11:00 PM ET)
|
||||
3. **MonthlyPortfolioSnapshotJob** runs monthly
|
||||
- Creates portfolio snapshots for all students
|
||||
- Used for performance tracking and reporting
|
||||
|
||||
## Deployment Instructions
|
||||
|
||||
### Development Environment
|
||||
|
||||
Start the Solid Queue worker to process jobs:
|
||||
|
||||
```bash
|
||||
# Start worker in development
|
||||
bin/jobs
|
||||
|
||||
# Or run in background
|
||||
bin/jobs &
|
||||
```
|
||||
|
||||
Test job scheduling:
|
||||
```bash
|
||||
# Test manual job execution
|
||||
rails console
|
||||
OrderExecutionJob.perform_later
|
||||
SolidQueue::Job.count # Should show queued jobs
|
||||
```
|
||||
|
||||
### Staging Deployment
|
||||
|
||||
#### Heroku
|
||||
```bash
|
||||
# Deploy code changes
|
||||
git push heroku main
|
||||
|
||||
# Scale up job worker (uses Procfile configuration)
|
||||
heroku ps:scale job=1 -a your-app-name
|
||||
|
||||
# Verify worker is running
|
||||
heroku ps -a your-app-name
|
||||
```
|
||||
|
||||
#### AWS/Traditional Servers
|
||||
Create a systemd service for the worker:
|
||||
|
||||
```ini
|
||||
# /etc/systemd/system/stocks-solid-queue.service
|
||||
[Unit]
|
||||
Description=Stocks in the Future - Solid Queue Worker
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=deploy
|
||||
WorkingDirectory=/path/to/your/app
|
||||
ExecStart=/path/to/your/app/bin/jobs
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
Environment=RAILS_ENV=production
|
||||
Environment=JOB_CONCURRENCY=3
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
```bash
|
||||
# Enable and start service
|
||||
sudo systemctl enable stocks-solid-queue
|
||||
sudo systemctl start stocks-solid-queue
|
||||
sudo systemctl status stocks-solid-queue
|
||||
```
|
||||
|
||||
## Job Dependencies
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. **Database Access**: All job data is stored in PostgreSQL
|
||||
2. **Active Worker Process**: Must have `bin/jobs` running
|
||||
3. **API Access**: StockPricesUpdateJob requires Alpha Vantage API access
|
||||
4. **Environment Variables**: `ALPHA_VANTAGE_API_KEY` must be set
|
||||
|
||||
### Database Tables
|
||||
|
||||
Solid Queue uses these database tables:
|
||||
- `solid_queue_jobs` - Main job queue
|
||||
- `solid_queue_ready_executions` - Jobs ready to run
|
||||
- `solid_queue_recurring_executions` - Recurring job schedules
|
||||
- `solid_queue_failed_executions` - Failed jobs for debugging
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Job Status Monitoring
|
||||
|
||||
```bash
|
||||
# Check job counts
|
||||
rails console
|
||||
SolidQueue::Job.count # Total jobs
|
||||
SolidQueue::Job.where(finished_at: nil).count # Pending jobs
|
||||
SolidQueue::FailedExecution.count # Failed jobs
|
||||
|
||||
# View recent jobs
|
||||
SolidQueue::Job.last(10).each do |job|
|
||||
puts "#{job.class_name} - #{job.finished_at ? 'Complete' : 'Pending'}"
|
||||
end
|
||||
```
|
||||
|
||||
### Heroku Monitoring
|
||||
|
||||
```bash
|
||||
# View job logs
|
||||
heroku logs --tail -a your-app-name | grep -E "(OrderExecutionJob|StockPricesUpdateJob)"
|
||||
|
||||
# Check worker status
|
||||
heroku ps -a your-app-name
|
||||
|
||||
# Check job queue
|
||||
heroku run rails runner "puts SolidQueue::Job.count" -a your-app-name
|
||||
```
|
||||
|
||||
### Log Files
|
||||
|
||||
Monitor execution through:
|
||||
- Rails logs: `log/production.log` (contains job execution details)
|
||||
- Worker logs: Output from `bin/jobs` process
|
||||
- Heroku logs: `heroku logs --tail -a your-app-name`
|
||||
|
||||
## Manual Execution
|
||||
|
||||
For testing or emergency runs:
|
||||
|
||||
```bash
|
||||
# Rails console
|
||||
rails console
|
||||
OrderExecutionJob.perform_later # Queue job
|
||||
OrderExecutionJob.perform_now # Run immediately
|
||||
StockPricesUpdateJob.perform_later # Queue job
|
||||
MonthlyPortfolioSnapshotJob.perform_later # Queue monthly job
|
||||
|
||||
# Command line
|
||||
rails runner "OrderExecutionJob.perform_later"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Jobs not running**:
|
||||
- Check worker process is running (`bin/jobs`)
|
||||
- Verify database connection
|
||||
- Check `solid_queue_jobs` table exists
|
||||
|
||||
2. **Jobs failing**:
|
||||
- Check `SolidQueue::FailedExecution.all` for error details
|
||||
- Verify API keys are set (`ALPHA_VANTAGE_API_KEY`)
|
||||
- Check database connectivity
|
||||
|
||||
3. **Recurring jobs not scheduling**:
|
||||
- Verify `config/recurring.yml` syntax
|
||||
- Check worker is running with recurring job support
|
||||
- Confirm time zone settings
|
||||
|
||||
4. **Performance issues**:
|
||||
- Adjust `JOB_CONCURRENCY` environment variable
|
||||
- Monitor database table sizes
|
||||
- Check API rate limits
|
||||
|
||||
### Debugging Commands
|
||||
|
||||
```bash
|
||||
# View failed jobs with errors
|
||||
rails console
|
||||
SolidQueue::FailedExecution.all.each do |failed_job|
|
||||
puts "#{failed_job.job.class_name}: #{failed_job.error}"
|
||||
end
|
||||
|
||||
# Check recurring job schedules
|
||||
SolidQueue::RecurringTask.all.each do |task|
|
||||
puts "#{task.class_name}: #{task.schedule}"
|
||||
end
|
||||
|
||||
# Clear all jobs (emergency only)
|
||||
SolidQueue::Job.delete_all
|
||||
```
|
||||
|
||||
## Time Zone Considerations
|
||||
|
||||
- **Recurring jobs use server time zone**
|
||||
- **Jobs are scheduled in Eastern Time (America/New_York)**
|
||||
- **Heroku**: Runs in UTC, so 1 AM ET = 6 AM UTC (EST) or 5 AM UTC (EDT)
|
||||
- **AWS**: Configure server time zone or adjust schedule accordingly
|
||||
- **Weekday scheduling**: OrderExecutionJob and StockPricesUpdateJob only run Monday-Friday
|
||||
|
||||
## Migration from Previous System
|
||||
|
||||
This system replaces the previous setup that used:
|
||||
- ❌ **whenever gem** (removed) - No longer needed
|
||||
- ❌ **Heroku Scheduler** (removed) - No longer needed
|
||||
- ❌ **Delayed Job** (removed) - Replaced by Solid Queue
|
||||
- ❌ **cron jobs** (removed) - No longer needed
|
||||
|
||||
### Benefits of New System
|
||||
- ✅ **Environment independent** - Works same on Heroku and AWS
|
||||
- ✅ **Database-backed** - More reliable than cron
|
||||
- ✅ **Built-in monitoring** - Better visibility into job status
|
||||
- ✅ **Job chaining** - Automatic OrderExecution → StockPrices flow
|
||||
- ✅ **Rails 8 native** - Optimized performance and integration
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Solid Queue Migration Guide](solid-queue-migration.md) - Technical migration details
|
||||
- [Heroku Deployment Guide](heroku-deployment-solid-queue.md) - Deployment instructions
|
||||
- [Orders and Transactions](orders-and-transactions.md) - Business logic overview
|
||||
@@ -1,99 +0,0 @@
|
||||
# Schema
|
||||
|
||||
- schools
|
||||
- id
|
||||
- name
|
||||
|
||||
- years
|
||||
- id
|
||||
- year
|
||||
|
||||
- school_years
|
||||
- id
|
||||
- school_id
|
||||
- year_id
|
||||
|
||||
- classrooms
|
||||
- id
|
||||
- school_year_id
|
||||
- name
|
||||
- grade
|
||||
- teacher_id
|
||||
|
||||
Inheritance?
|
||||
- users
|
||||
- id
|
||||
- type
|
||||
- student
|
||||
- teacher
|
||||
- admin
|
||||
- username
|
||||
- password
|
||||
- email
|
||||
|
||||
- user_invites
|
||||
- id
|
||||
- invite_code
|
||||
- type
|
||||
- student
|
||||
- teacher
|
||||
- admin
|
||||
- date
|
||||
|
||||
- stocks
|
||||
- id
|
||||
- name
|
||||
- ticker
|
||||
- ...company details
|
||||
|
||||
- stock_prices
|
||||
- id
|
||||
- stock_id
|
||||
- date
|
||||
- open
|
||||
- high
|
||||
- low
|
||||
- close
|
||||
- volume
|
||||
- adj_close
|
||||
|
||||
- stock_dividends
|
||||
- id
|
||||
- stock_id
|
||||
- date
|
||||
- dividend
|
||||
|
||||
!!!! Use Transactions
|
||||
- portfolio
|
||||
- id
|
||||
- user_id
|
||||
- cash_amount
|
||||
|
||||
- portfolio_transactions
|
||||
- id
|
||||
- portfolio_id
|
||||
- actor_id
|
||||
- date
|
||||
- amount
|
||||
- type
|
||||
- deposit
|
||||
- withdrawal
|
||||
|
||||
- portfolio_stocks
|
||||
- id
|
||||
- portfolio_id
|
||||
- stock_id
|
||||
- shares
|
||||
|
||||
- portfolio_stock_transactions
|
||||
- id
|
||||
- portfolio_stock_id
|
||||
- stock_id
|
||||
- date
|
||||
- shares
|
||||
- price
|
||||
- type
|
||||
- buy
|
||||
- sell
|
||||
- dividend
|
||||
- ...other details
|
||||
@@ -1,39 +0,0 @@
|
||||
# Seeds
|
||||
|
||||
## Objectives
|
||||
|
||||
- We want to maintain a rich database seed for development since that lays a good
|
||||
foundation for easy contributions.
|
||||
- We want to ensure production data integrity by putting stops in place to ensure
|
||||
the development seed is never accidentally run in production.
|
||||
- We want to keep our seeds separated into partials to keep things organized
|
||||
and easy to maintain.
|
||||
|
||||
## Running the seeds
|
||||
|
||||
To seed your database, simply execute:
|
||||
```
|
||||
rails db:seed
|
||||
```
|
||||
In either the Development or Production environments. Seeds are idempotent.
|
||||
|
||||
## Split between Production and Development
|
||||
|
||||
To ensure the execution of seeds in only the appropriate environment the default
|
||||
```db/seeds.rb``` file has been edited to check the environment and execute the
|
||||
appropriate seed. **Do not edit this file to add your seeds.**
|
||||
|
||||
In the ```db/seeds``` directory you will find files named for each environment:
|
||||
- ```development.rb```
|
||||
- ```production.rb```
|
||||
- ```test.rb```
|
||||
|
||||
These are where you will add your seeds.
|
||||
|
||||
## Seed partials
|
||||
|
||||
The ```db/seeds/partials``` directory contains partials that are loaded by the
|
||||
respective environment seeds (see above). These will contain the bulk of our seed
|
||||
code.
|
||||
|
||||
As far as is practical we will split these into one file per model.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.0 MiB |
Reference in New Issue
Block a user