feat: move config.py to config.example.py, exclude config.py from git tracking
- Copy config.py to config.example.py as template (tracked in git) - Add config.py to .gitignore (local config per developer) - Update README.md with configuration setup instructions - Fix outdated references (TinyDB -> SQLite, add missing files) - Persist goal selection across task and note pages
This commit is contained in:
parent
3c325bdb0f
commit
2629e8f2cd
3
.gitignore
vendored
3
.gitignore
vendored
@ -23,6 +23,9 @@ uv.lock
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Configuration (each developer must create their own)
|
||||
config.py
|
||||
|
||||
# Environment variables
|
||||
.env
|
||||
.env.local
|
||||
|
||||
55
README.md
55
README.md
@ -26,6 +26,9 @@ A web-based task management application focused on goal-oriented task tracking w
|
||||
git clone <repository-url>
|
||||
cd GoalsBreakDown
|
||||
|
||||
# Create your local configuration from the example
|
||||
cp config.example.py config.py
|
||||
|
||||
# Install dependencies with uv
|
||||
uv sync
|
||||
|
||||
@ -44,32 +47,33 @@ The application will start at **http://127.0.0.1:5000**
|
||||
|
||||
## Configuration
|
||||
|
||||
Edit `config.py` to customize settings:
|
||||
Local configuration is managed via `config.py` (not tracked in git). Use `config.example.py` as a template:
|
||||
|
||||
```python
|
||||
# Database path
|
||||
DB_PATH = "data/db.json"
|
||||
|
||||
# Default admin credentials (change these!)
|
||||
DEFAULT_ADMIN_USERNAME = "admin"
|
||||
DEFAULT_ADMIN_PASSWORD = "admin123"
|
||||
|
||||
# Default max goals for new users
|
||||
DEFAULT_MAX_GOALS = 5
|
||||
|
||||
# Flask settings
|
||||
SECRET_KEY = "your-secret-key-here" # Change in production
|
||||
DEBUG = True
|
||||
HOST = "0.0.0.0"
|
||||
PORT = 5000
|
||||
```bash
|
||||
# Copy the example config and edit it
|
||||
cp config.example.py config.py
|
||||
```
|
||||
|
||||
Available settings in `config.py`:
|
||||
|
||||
| Setting | Description | Default |
|
||||
|---|---|---|
|
||||
| `DB_PATH` | SQLite database path | `data/db.sqlite` |
|
||||
| `DEFAULT_ADMIN_USERNAME` | Default admin username | `admin` |
|
||||
| `DEFAULT_ADMIN_PASSWORD` | Default admin password | `admin123` |
|
||||
| `DEFAULT_MAX_GOALS` | Max goals per new user | `5` |
|
||||
| `SECRET_KEY` | Flask session secret (change in production!) | — |
|
||||
| `DEBUG` | Debug mode | `True` |
|
||||
| `HOST` | Server bind address | `0.0.0.0` |
|
||||
| `PORT` | Server port | `5000` |
|
||||
|
||||
### Production Deployment
|
||||
|
||||
1. Change `SECRET_KEY` to a random secure string
|
||||
2. Set `DEBUG = False`
|
||||
3. Change default admin credentials
|
||||
4. Use a production WSGI server (e.g., gunicorn):
|
||||
1. Copy `config.example.py` to `config.py`
|
||||
2. Change `SECRET_KEY` to a random secure string
|
||||
3. Set `DEBUG = False`
|
||||
4. Change default admin credentials
|
||||
5. Use a production WSGI server (e.g., gunicorn):
|
||||
|
||||
```bash
|
||||
uv add gunicorn
|
||||
@ -81,9 +85,11 @@ uv run gunicorn -w 4 -b 0.0.0.0:5000 app:app
|
||||
```
|
||||
GoalsBreakDown/
|
||||
├── app.py # Flask application
|
||||
├── config.py # Configuration
|
||||
├── database.py # TinyDB operations
|
||||
├── config.example.py # Configuration template (tracked in git)
|
||||
├── config.py # Local configuration (NOT tracked in git)
|
||||
├── database.py # SQLite operations
|
||||
├── auth.py # Authentication helpers
|
||||
├── schema.py # Database schema & migration
|
||||
├── templates/ # HTML templates
|
||||
├── static/
|
||||
│ ├── css/ # Stylesheets
|
||||
@ -94,8 +100,9 @@ GoalsBreakDown/
|
||||
## Tech Stack
|
||||
|
||||
- **Backend:** Python + Flask
|
||||
- **Database:** TinyDB
|
||||
- **Database:** SQLite
|
||||
- **Frontend:** Vanilla JS + HTML/CSS
|
||||
- **Drag-and-Drop:** SortableJS
|
||||
- **Markdown:** marked.js
|
||||
- **Authentication:** bcrypt + Flask sessions
|
||||
- **Environment:** uv
|
||||
|
||||
@ -107,7 +107,7 @@ async function openNote(noteId) {
|
||||
document.getElementById("note-modal").classList.add("active");
|
||||
}
|
||||
|
||||
function openNewNote() {
|
||||
async function openNewNote() {
|
||||
editingNoteId = null;
|
||||
document.getElementById("note-modal-title").textContent = "New Note";
|
||||
document.getElementById("note-id").value = "";
|
||||
@ -120,7 +120,11 @@ function openNewNote() {
|
||||
document.getElementById("note-modal").classList.add("active");
|
||||
|
||||
if (savedGoalId) {
|
||||
populateTasks(savedGoalId);
|
||||
await populateTasks(savedGoalId);
|
||||
const goal = goals.find(g => g.id === savedGoalId);
|
||||
if (goal && goal.selected_task_id) {
|
||||
document.getElementById("note-task").value = goal.selected_task_id;
|
||||
}
|
||||
} else {
|
||||
document.getElementById("note-task").innerHTML = '<option value="">None</option>';
|
||||
}
|
||||
@ -225,10 +229,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
populateTasks(goalId);
|
||||
});
|
||||
|
||||
document.getElementById("filter-goal").addEventListener("change", async () => {
|
||||
const goalId = parseInt(document.getElementById("filter-goal").value) || null;
|
||||
savedGoalId = goalId;
|
||||
await patch("/api/user/selected-goal", { goal_id: goalId });
|
||||
document.getElementById("filter-goal").addEventListener("change", () => {
|
||||
loadNotes();
|
||||
});
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user