An application logger tool to track job applications using a simple interface with filtering, status updates, and email notifications. Can be upgraded to scrape job listings and automate the workflow.
- Design & Layout
- Modern, minimal interface in beige/white color palette with dark grey text
- Full dark mode support with theme-aware colors (light/dark modes fully functional)
- Main layout with search bar (fully functional)
- Job list/cards display with hover effects
- Total applications counter displayed on main page
- Sort jobs by latest/newest first on main screen (by application_date DESC)
- Search & Filtering
- Search field (main field, across the screen)
- Filter sidebar with dropdowns (company, status, location)
- Hide inactive job statuses (Rejected, Withdrawn, No Response) by default from main screen
- Display filtered count in applications counter (shows "X of Y applications")
- Add option to filter by location in the search bar
- Forms & Input
- Add job form (separate page at /add-job with all fields)
- Vertically expandable text fields for description and notes
- Job detail page with "View Details" navigation
- Status editing from job detail page (click "Edit" button next to status badge)
- Delete job from job detail page with confirmation dialog
- Edit/delete buttons on job cards
- Optional field to store apartment offer links (multiple links with '+ Add link' UI)
- Edit job details functionality (Issue #3)
- Auto-populate application date to today by default (Issue #4)
- Reset edit mode when exiting job details page (Issue #5)
- Add "Clear Fields" button in job creation form (Issue #6)
- Auto-suggest/auto-fill for location, job title, and company fields (Issue #7)
- Note History & Timeline
- Vertical timeline display showing timestamped notes
- Notes sorted in reverse chronological order (newest first)
- Timestamps formatted as DD/MM/YYYY HH:mm for readability
- "Add Note" form on job detail page
- Note count indicator on job cards
- Automatic timestamp capture for each note
- Date & Value Formatting
- Application dates displayed as DD/MM/YYYY on main page and detail page
- Note timestamps displayed as DD/MM/YYYY HH:mm
- Salary values formatted with K suffix (e.g., "120K" instead of "120000")
- Note Templates
- Templates Management page (
/templatesroute) - Create, edit, and delete reusable note templates
- Real-time search by template name or content
- Template selector in job detail page with search
- Hover tooltips showing full template content
- Click to insert template into note textarea (non-destructive)
- "View All Templates" dialog
- Auto-clear success messages after 3 seconds
- Settings icon link to Templates Management page
- Handle note templates in job creation form (Issue #2)
- Decision needed: Add template selector to creation form OR remove notes field from creation entirely
- Templates Management page (
- CRUD Operations - job_service.py
- Create job applications
- Read by ID and URL
- Update with partial or full field changes
- Delete job applications
- Add timestamped notes to existing applications
- Validation & Data Integrity
- Field validation (empty dict, invalid field names)
- Atomic updates (all-or-nothing, no partial updates)
- Transaction rollback on failures
- Notes field migrated to JSON with automatic timestamp capture
- Explicitly track job_url field presence (not just rely on SQLAlchemy NOT NULL)
- Exact Duplicate Detection
- Check for existing job_url (reject if already exists)
- Similar Job Detection
- Detect same job from different sources (LinkedIn, Indeed, company site)
- Match criteria: company_name + job_title + location + different URL domain
- Prompt user confirmation via UI layer before creating similar entry
- Search Functionality
- Full-text search across company, title, and description
- Filtering System
- Filter by company, status, and location
- Automatic Data Capture
- Capture created date (created_at timestamp)
- Automatically assign "Applied" status on creation
- Track updated date (updated_at timestamp)
- Location-Based Tracking
- Track region of each job listing to align with apartment renting search
- Template CRUD Operations - template_service.py
- Create reusable note templates
- Read templates by ID
- Get all templates ordered by name
- Search templates by name or content (case-insensitive)
- Update existing templates
- Delete templates
- Template Validation
- Require name and content fields
- Field validation (empty dict, invalid field names)
- Transaction rollback on failures
- Implementation
- SQLite database (single-user, local storage)
- SQLAlchemy ORM models and configuration
- Notes field as JSON column storing timestamped note entries
- Schema Enhancements
- Convert salary_range field from string to tuple(int, int) or separate min/max columns
- Extract and store keywords, company name, source website metadata
- Optional: Create separate Company database table with relationships
- Unit Tests (49 tests with comprehensive coverage - all passing)
- Job Service Tests (31 tests)
- Create: duplicate detection, validation, empty data, rollback handling
- Read: by ID and URL, valid/invalid cases, edge cases
- Update: field validation, partial updates, nonexistent IDs, rollback
- Delete: success/failure scenarios, rollback
- Notes: add_note functionality, append to existing notes, edge cases
- Template Service Tests (18 tests)
- Create: validation, missing fields, empty data, rollback
- Read: by ID, get all templates, search by name/content
- Update: field validation, empty dict, nonexistent IDs
- Delete: success/failure scenarios
- Job Service Tests (31 tests)
- Integration Tests
- Search/filter functionality tests
- Form submission end-to-end tests
- Documentation
- Usage documentation
- Component Organization (✅ Complete - Branch:
refactor/component-extraction)- Create
applog/components/directory structure-
components/jobs/- Job-related components -
components/shared/- Shared/reusable components -
components/main/- Main page components -
components/templates/- Template management components
-
- Extract reusable UI components from
applog.py(✅ 100% complete - App runs successfully!)- Job card component →
jobs/job_card.py(with visual docstrings) - Job detail page →
jobs/job_detail.py(877 lines, ~50 functions, with visual docstrings) - Add job form →
jobs/add_job.py(with visual docstrings) - Note timeline →
jobs/notes.py(with visual docstrings) - Filter sidebar →
shared/sidebar.py(with visual docstrings) - Status badge →
shared/status_badge.py(with visual docstrings) - Search bar →
shared/search_bar.py(with visual docstrings) - Formatters →
shared/formatters.py(date formatting utilities) - Job list wrapper →
jobs/job_list.py(with visual docstrings) - Main index page →
main/index_page.py(with visual docstrings) - Templates page →
templates/template_form.py+templates/template_list.py(with visual docstrings)
- Job card component →
- Code Quality Improvements
- Naming convention:
_button_*prefix for all buttons (type-first organization) - Naming convention:
_formatting_*prefix for all styling dictionaries - Visual docstrings added to all component functions (emoji + description + visual example)
- Component organization documented in LESSONS.md (type vs. domain strategies)
- Naming convention:
- Module Integration (✅ Complete)
- Configured
__init__.pyfiles for proper module exports - Fixed import patterns (direct function calls vs. module.function access)
- Created page wrapper functions in
applog.pyfor state injection - Cleared stale bytecode cache and resolved import errors
- Configured
- Refactoring Complete!
- All pages extracted into component modules
- Visual docstrings added to all functions
- Proper module exports via
__init__.pyfiles - Consistent naming conventions throughout
- Full integration testing of all features (recommended before merge)
- Optional: Split large files into sub-modules if needed (only if files exceed 500 lines)
- Create
- Email Notifications
- Create email notifications after a certain period of time
- Email response parsing to update job status automatically
- Batch check on next run if service was offline
- URL Scraping
- Auto-extract job details from posting URLs
- Advanced Features
- Authentication (if multi-user support needed)
- Web hosting deployment
- Company database with historical tracking
- Security
- SQL injection protection (SQLAlchemy parameterized queries handle automatically)
- Input validation for URL formats
- Rate limiting (if deployed publicly)
- Frontend: Reflex (pure Python framework that compiles to React)
- Backend: Python with SQLAlchemy ORM
- Database: SQLite (single-user, local storage)
- Testing: pytest with 49 comprehensive tests (all passing)
- Deployment: Local development server only
JobApplication Table:
id- Primary keycompany_name- Company name (indexed)job_title- Position titlejob_url- Job posting URL (unique, for duplicate detection)location- Job location (indexed)description- Job description textstatus- Application status (indexed)- Options: Applied, Screening, Interview, Offer, Rejected, Accepted, Withdrawn, No Response
application_date- Date appliedsalary_range- Salary range (optional, string format)notes- JSON array of timestamped note entries:[{"timestamp": "ISO-8601", "note": "text"}, ...]created_at- Record creation timestampupdated_at- Record update timestamp
NoteTemplate Table:
id- Primary keyname- Template name (indexed)content- Template text contentcreated_at- Template creation timestampupdated_at- Template update timestamp
The project uses a hybrid naming convention that balances type-based and domain-based organization for components in single files:
Type-First Prefixes (for component kind):
_button_*- All button components (e.g.,_button_save,_button_cancel)_formatting_*- All styling dictionaries (e.g.,_formatting_card,_formatting_dialog)_grid_*- Grid row components_section_*- Major page sections
Domain-First Prefixes (for features):
_template_*- Template system components_note_*- Note management components_job_*- Job-related components
Why This Works:
- Enables both access patterns: "find all buttons" (
_button_*) AND "find all template components" (_template_*) - Works well with IDE search (Cmd+T / Cmd+Shift+O in VSCode)
- Scales up to ~100 components per file
- No tooling overhead required
Example:
# Type-based grouping
_button_save # Easy to find all buttons
_button_cancel
_button_template_insert
# Domain-based grouping
_template_selector_list # Easy to find all template components
_template_search_input
_template_settings_tooltipapplog/
├── components/
│ ├── jobs/
│ │ ├── __init__.py # Module exports
│ │ ├── job_card.py # Job card display (~120 lines)
│ │ ├── job_detail.py # Job detail page (~877 lines, 50+ functions)
│ │ ├── add_job.py # Add job form (~340 lines)
│ │ ├── job_list.py # Job list wrapper component (~30 lines)
│ │ └── notes.py # Note timeline components
│ ├── shared/
│ │ ├── __init__.py # Module exports
│ │ ├── sidebar.py # Filter sidebar
│ │ ├── search_bar.py # Search bar component
│ │ ├── status_badge.py # Status badge component
│ │ └── formatters.py # Date/currency formatting utilities
│ ├── main/
│ │ ├── __init__.py # Module exports
│ │ └── index_page.py # Main index page layout (~160 lines)
│ └── templates/
│ ├── __init__.py # Module exports
│ ├── template_form.py # Template form components (~220 lines)
│ └── template_list.py # Template list display (~252 lines)
├── applog.py # Main app (State + page assembly, ~530 lines)
├── models/ # Database models
│ ├── job_application.py
│ └── note_template.py
├── services/ # Business logic layer
│ ├── job_service.py
│ └── template_service.py
└── database.py # Database initialization
When the project grows beyond ~100 components, the plan is to reorganize into:
components/
├── jobs/
│ ├── detail/
│ │ ├── buttons.py # All detail page buttons
│ │ ├── forms.py # All form components
│ │ ├── dialogs.py # Dialog components
│ │ └── __init__.py # Barrel exports (dual access patterns)
│ ├── list/
│ │ ├── cards.py
│ │ └── filters.py
│ └── __init__.py
├── shared/
│ ├── buttons.py # Shared button components
│ ├── inputs.py
│ └── status_badge.py
└── templates/
├── form.py
└── list.py
Barrel Export Pattern (in __init__.py):
# Feature-domain exports (primary)
from .buttons import button_save, button_cancel, button_edit
# Component-type grouped exports (for refactoring)
__all_buttons__ = [button_save, button_cancel, button_edit]
__all_forms__ = [...]This provides:
- Feature-domain imports:
from components.jobs.detail import button_save - Type-based refactoring:
from components.jobs.detail import __all_buttons__
The Trade-off: You cannot optimize for both type-based AND domain-based access with a single hierarchy. The hybrid naming convention is a pragmatic compromise that works well for small-to-medium projects.
Scaling Path:
- < 100 components: Hybrid naming in flat files ✅ (current)
- 100-500 components: Directory structure + barrel exports (planned)
- 500+ components: Add component catalog + Storybook (future)
Key Principle: Don't over-engineer early. The current approach is optimal for the project's scale.
Full Details: See LESSONS_LEARNED.md "Component Organization" section for the complete analysis of type vs. domain trade-offs, barrel export examples, and production best practices.
- Add Job: User navigates to
/add-joband fills out the form with job details - Data Storage: Job application is saved to SQLite database with automatic timestamp and "Applied" status
- View Jobs: Main page displays all applications with search/filter capabilities
- Total applications counter displayed under "Add Job" button
- "Templates" button for quick access to template management
- Dates formatted as DD/MM/YYYY for easy reading
- Salary values formatted with K suffix
- Filter by company, status, or location
- View Details: Click "View Details" on any job card to see full information
- Edit Status: From job detail page, click "Edit" next to status badge to update application status
- Track Progress: Add timestamped notes to track application progress (emails, interviews, etc.)
- Use template selector to quickly insert common note text
- Search templates by name or content
- Hover over templates to preview full content
- Click template to insert into note textarea (non-destructive)
- "View All" button to see all templates in a dialog
- Settings icon to manage templates
- Note History: View vertical timeline of all notes with automatic timestamps
- Notes displayed newest first (reverse chronological)
- Timestamps formatted as DD/MM/YYYY HH:mm
- Delete Job: From job detail page, click "Delete Job Application" button at bottom with confirmation dialog
- Manage Templates: Navigate to
/templatesto create, edit, search, and delete note templates- Create reusable note templates with name and content
- Real-time search across template names and content
- Edit existing templates
- Delete templates with confirmation
- Success messages auto-clear after 3 seconds
/- Main dashboard with job list, search, filters, application counter, and Templates navigation button/add-job- Add new job application form (wired to database)/job/[id]- Job detail page with note history, status editing, add note with template selector, and delete job functionality/templates- Templates Management page for creating, editing, searching, and deleting note templates
See ROADMAP.md for detailed upcoming features and implementation plan.
Phase 1: Complete ✅
- ✅ Reset edit mode on page exit
- ✅ Smart cancel with confirmation dialog
- ✅ Auto-populate application date to today
Phase 2: Complete ✅
- ✅ Sort jobs by application date (newest first)
- ✅ Hide inactive job statuses by default
- ✅ Filter-aware application counter (shows "X of Y")
- ✅ Remove notes field from job creation (commented out for potential future re-add)
Coming Soon:
- Location autocomplete with type-ahead
- Full job editing capability