A multi-phase educational project for managing personal notes with structured metadata.
It is also the first time we consider the idea of future-proof software.
Personal Notes Manager is a text-based note-taking system that stores notes as UTF-8 text files with YAML headers for metadata. This project serves as an educational tool for students to learn file manipulation, parsing, and progressively more advanced application architectures.
https://zcw.guru/kristofer/javapygitignore
"Future-proof" software is code designed to remain useful, maintainable, and adaptable as technology evolves and requirements change over time. Think of it like building a house with a strong foundation that can support renovations and additions years later.
Why future-proofing matters: When you write software, you're not just solving today's problem - you're creating something that will likely need to change. User needs evolve, new technologies emerge, and business requirements shift. Future-proof code makes these inevitable changes easier and less expensive.
Key principles for future-proof software:
Modularity and separation of concerns - Break your code into distinct, focused pieces that do one thing well. If you need to change how data is stored, you shouldn't have to rewrite your user interface code too. If you store your notes in text files now, but a database in the next version, how do you make sure you can move amongst different storage tech?
Use established standards and conventions - Following widely-adopted patterns means other developers can understand your code, and it's more likely to work well with future tools and libraries. And text files, based on UNICODE, is one of the most well-respected storage modalities. (So is Sqlite3, see Library of Congress; Recommended Formats Statement)
Avoid hard-coding values - Instead of writing if (users.length > 100), use a configurable constant like if (users.length > MAX_USERS). This makes it easy to adjust limits without hunting through code. These items can be kept together, so that they can be reviewed and changed as needed in Future YEARS.
Choose stable, well-supported technologies - While it's tempting to use the newest framework, mature technologies with strong communities tend to have better long-term support.
Write clear documentation and tests - Future you (or other developers) will thank you when they need to modify code written months or years ago. So, unit tests and test-driven development is a critical part of this project. Test early and often. And make sure your Future You knows how to run the test and read the comments and PLAN and SPEC documents.
The goal isn't to predict the future perfectly, but to write code that bends rather than breaks when change inevitably comes. It's about making smart trade-offs between solving immediate needs and maintaining flexibility for tomorrow's challenges.
This project is designed to be implemented in three distinct phases:
- Basic note creation, reading, updating, and deletion via command line
- YAML header parsing and manipulation
- Note searching and filtering capabilities
- Simple formatting options
- Desktop application with intuitive UI
- Rich text editing features
- Visual organization of notes (folders/tags)
- Enhanced search functionality with highlighting
- Export options (PDF, HTML, etc.)
- Web-based access to notes
- Multi-user support with authentication
- Real-time collaborative editing
- Mobile-responsive design
- API documentation for potential extensions
Notes are stored as plain text files with a .note extension (or any extension you prefer). Each note follows this structure:
---
title: My Example Note
created: 2025-05-20T10:30:00Z
modified: 2025-05-20T10:45:00Z
tags: [example, documentation]
---
This is the content of my note.
It can contain multiple paragraphs and basic formatting.
You can include lists:
- Item 1
- Item 2
- Item 3
And other simple markdown markup as needed.
The YAML header is delimited by triple dashes (---) and contains metadata about the note:
| Field | Description | Type | Required |
|---|---|---|---|
| title | The title of the note | String | Yes |
| created | Creation timestamp (ISO 8601) | DateTime | Yes |
| modified | Last modification timestamp (ISO 8601) | DateTime | Yes |
| tags | Categories or labels for the note | Array of Strings | No |
| author | Creator of the note | String | No |
| status | Completion or review status | String | No |
| priority | Importance level | Integer (1-5) | No |
Additional custom fields can be added as needed.
There a few sample note files in test-notes/
notes --help # Display help information
notes create # Create a new note (opens in default editor)
notes list # List all notes
notes list --tag "coursework" # List notes with specific tag
notes read <note-id> # Display a specific note
notes edit <note-id> # Edit a specific note
notes delete <note-id> # Delete a specific note
notes search "query" # Search notes for text (title, tags, content)
notes stats # Display statistics about your notes
- Java 11+ or Python 3.11+
- YAML parser library
- Filesystem access & manipulation
- Text editor integration (nano?)
- Extra Credit: github integration for the notes storage
- Extra Credit: note encryption (and key management)
Maybe this week, maybe next time we come back around to this project.
- Note browser panel (folder structure or tag-based)
- Rich text editor with markdown support
- Real-time preview
- Drag and drop organization
- Dark/light theme options
- Backup and restore functionality
- Java Swing or TKinter
- HTML/CSS for UI (if using web technologies)
- Local storage management
- Cross-platform compatibility
Maybe instead of Phase 2? Maybe this week, maybe in the future.
What is this stuff anyway? Well, Ask your friendly, globe-girdling AI.
GET /api/notes # List all notes
POST /api/notes # Create a new note
GET /api/notes/:id # Retrieve a specific note
PUT /api/notes/:id # Update a specific note
DELETE /api/notes/:id # Delete a specific note
GET /api/tags # List all tags
GET /api/notes/tag/:tagid # List all notes with tag tagid
GET /api/search?q=query # Search notes
- Express.js/Flask/Django REST framework (python)
- Spring/Springboot
- Frontend: VanillaJS (first)
- Frontend: React/Vue/Angular?
- Authentication system (don't want just anyone reading your notes)
- Database integration (optional, should still use file system)
- API documentation (Swagger/OpenAPI)
Students will gain experience with:
- File I/O operations
- Data parsing and validation
- Command-line argument processing
- User interface design principles
- Client-server architecture
- REST API development
- Frontend-backend integration
- Project planning and progressive enhancement
- [List required software/libraries]
- Basic understanding of Java or Python
- Knowledge of [relevant concepts]
# Clone the repository
# CHOOSE your Project's Name NOW.... _don't use future-proof_.
git clone https://github.com/yourusername/future-proof.git
# Navigate to the project directory or whatever you named it in the clone.
cd `yournotesnamehere`
# Install dependencies
(if you need them)
# Run the application
run.shThis project is designed for educational purposes. Students are encouraged to:
- Fork the repository
- Create a feature branch
- Implement their assigned component
- Submit a pull request for review
[MIT license]
- Every amazing personal notes project out there.
- Unix file system. Without it, we'd be sunk.
- Markdown: the way techies write.
Possible Names for your version of this project (or make up your own!)
NoteNexus MindScribe ThoughtVault StudyStream MemoPad Pro BrainWave Notes Scholarly Jotter InsightKeeper Knowledge Capsule NoteCraft MindMapper StudyPulse ThoughtHub NoteWorthy IdeaTracker StudySync RecallPro ClassCompass MindfulNotes LearnLogger
Why Build Your Note-Taking App with the Filesystem?
Using the filesystem instead of a database or cloud service for your note-taking app isn't just a simpler starting point—it's a masterclass in fundamental programming concepts that every developer needs to understand.
You're learning the foundation underneath everything
Every piece of software ultimately interacts with files. Databases? They store data in files. Web servers? They serve files. Cloud applications? They manage files across distributed systems. By working directly with the filesystem, you're learning the bedrock skills that power everything else.
Essential skills you'll develop:
File I/O operations - You'll master reading from and writing to files, which is core to virtually every application. Whether you're processing configuration files, importing data, or generating reports, these skills transfer everywhere.
Data serialization and parsing - Converting your note objects into text (JSON, Markdown, XML) and back again teaches you how data moves between memory and storage. This same concept applies when sending data over networks or saving user preferences.
Directory structure and organization - Deciding how to organize notes (by date? by topic? in nested folders?) teaches you about data modeling and hierarchical thinking. These concepts directly apply to database design, URL routing in web apps, and organizing any complex system.
Error handling and edge cases - What happens when a file is corrupted? When the disk is full? When two processes try to write the same file? Filesystem programming forces you to think about real-world failure scenarios.
Performance considerations - You'll discover why reading one large file might be faster than many small ones, or why scanning hundreds of files can be slow. These insights apply to database queries, API calls, and system optimization everywhere.
Practical examples from your note-taking app:
File naming and collision handling - When a user creates two notes with the same title, how do you handle it? Do you append timestamps? Create numbered versions? This teaches you about unique identifiers and conflict resolution.
Incremental loading - If you have thousands of notes, you can't load them all into memory. You'll learn to read file lists, load metadata first, and fetch full content on demand—the same patterns used in web pagination and lazy loading.
Search without databases - Building search functionality by scanning files teaches you about indexing, text processing, and performance trade-offs. Later, when you use a database, you'll understand what it's doing behind the scenes.
Backup and versioning - How do you prevent data loss? How do you track changes? You might implement simple versioning by copying files or creating timestamps, learning the concepts behind version control systems.
Cross-platform compatibility - Different operating systems handle file paths differently. Learning to work with / vs \ separators and absolute vs relative paths teaches you about portability and system-level programming.
The learning progression:
You'll start simple—just saving text to a file. Then you'll want better organization, so you'll create folders. Then you'll want metadata, so you'll learn JSON. Then you'll want search, so you'll read multiple files efficiently. Each step builds naturally on the last.
Why this beats starting with a database:
Databases hide complexity behind convenient APIs. While that's great for building applications quickly, it means you miss fundamental concepts about how data is actually stored and retrieved. When you eventually use databases (and you will), you'll understand the problems they're solving because you've faced those problems yourself.
Real-world relevance:
Many successful applications started as filesystem-based tools. Git manages millions of files efficiently. Static site generators like Jekyll process thousands of markdown files. Log analysis tools parse massive text files. Configuration management systems organize files across servers.
Skills that transfer everywhere:
The file handling patterns you learn will apply when you're processing CSV data, managing configuration files, building deployment scripts, or working with any system that stores and retrieves information. You're not just building a note-taking app—you're learning to think like a systems programmer.
Starting with the filesystem gives you a deep understanding of how computers actually work with data. It's messier and more complex than using a database, but that complexity teaches you invaluable problem-solving skills. Every challenge you solve—from handling concurrent access to organizing large amounts of data—prepares you for the real-world complexities you'll face as a professional developer.
What is Test-Driven Development (TDD)?
Test-Driven Development is a programming approach where you write tests before writing the actual code. It follows a simple cycle called "Red-Green-Refactor":
- Red: Write a failing test that describes what you want your code to do
- Green: Write the minimal code needed to make that test pass
- Refactor: Clean up and improve the code while keeping tests passing
Think of it like writing a recipe backwards - you first describe what the finished dish should taste like, then figure out how to cook it.
Why beginners should embrace TDD:
Clarifies your thinking - Writing tests first forces you to think through exactly what your function should do before you get lost in implementation details. It's like sketching before painting.
Catches bugs early - Tests act as a safety net. When you change code later, your tests immediately tell you if you broke something that was previously working.
Improves code design - Code that's easy to test tends to be well-organized and modular. TDD naturally pushes you toward better architecture.
Builds confidence - You can refactor and improve your code fearlessly, knowing your tests will catch any mistakes.
Serves as documentation - Good tests show other developers (including future you) how your code is supposed to work.
Need to Make Sure - There are 3-4 test For Every Method!!! Lots o'tests, many, many tests. So Many Tests!!
How to do TDD:
These test examples are in JavaScript, so use them only as conceptual examples. You will write this app in either Java or Python, and use the standard filesystem (using text files as your data format) for your storage infrastructure. Someday soon, you may get the chance (or motivation) to store the notes in a database of some kind, but for now, text files.
Let's say you're building a function to validate note titles. Here's the TDD process:
Step 1 (Red): Write a failing test
test('should reject empty note titles', () => {
expect(validateNoteTitle('')).toBe(false);
});Step 2 (Green): Write minimal code to pass
function validateNoteTitle(title) {
return title !== '';
}Step 3 (Refactor): Improve while keeping tests green
function validateNoteTitle(title) {
return typeof title === 'string' && title.trim().length > 0;
}Then repeat: add more tests for edge cases, implement features incrementally. Start small, with a tiny core of functionality. And then build outwards, add capabilities (and TESTs Tests tests) as you go!
TDD in your note-taking CLI application:
Here are specific areas where TDD would be valuable:
Note creation and validation
- Test that notes require titles
- Test that notes can have optional tags
- Test that duplicate titles are handled appropriately
- Test that special characters in titles are escaped properly
Search functionality
- Test searching by keywords finds correct notes
- Test case-insensitive search works
- Test searching with multiple tags
- Test handling of search terms with special characters
File operations
- Test that notes are saved to the correct file format
- Test that corrupted files are handled gracefully
- Test that backup creation works
- Test that notes can be exported to different formats
Command parsing
- Test that CLI commands are parsed correctly (
add,search,delete) - Test that invalid commands show helpful error messages
- Test that command flags work as expected (
--tag,--date)
Example TDD workflow for your CLI app:
// Test first
test('should create note with title and content', () => {
const note = createNote('My First Note', 'This is the content');
expect(note.title).toBe('My First Note');
expect(note.content).toBe('This is the content');
expect(note.createdAt).toBeInstanceOf(Date);
});
// Then implement
function createNote(title, content) {
return {
title: title,
content: content,
createdAt: new Date(),
id: generateId()
};
}Getting started:
- Choose a testing framework (
junitfor Java,pytestand/orunittestfor Python, etc.) - Start with simple, pure functions (like validation, method correctness or formatting)
- Write one test, make it pass, then add another
- Don't try to test everything at once - build up gradually
TDD might feel slow initially, but it pays huge dividends as your application grows. You'll spend less time debugging mysterious bugs and more time confidently adding new features. For a personal project like this note-taking app, it also helps you think through the user experience before getting caught up in implementation details.
Why does choosing to use text files in a standard directory structure using Markdown as a note format, make the project "future proof"?
Using text files in a standard directory structure with Markdown as a note format makes a project "future proof" for several compelling reasons:
Universal Compatibility
- Plain text files (.txt, .md) are readable by virtually any operating system and text editor, eliminating dependency on proprietary software
- UTF-8 encoding ensures support for multiple languages and special characters across all modern systems
Longevity and Stability
- Text files have remained a stable format for decades and will likely be readable for decades to come
- Unlike proprietary formats that can become obsolete when companies discontinue support
Version Control Friendly
- Text files integrate seamlessly with version control systems like Git
- Changes can be tracked line by line, enabling precise collaboration and history tracking
Portable and Accessible
- Files can be easily transferred between devices and platforms
- Low storage requirements compared to binary formats
Human Readable
- Content remains accessible without specialized software
- Even if the application becomes obsolete, notes remain directly readable
Open Standards
- Markdown is an open specification with wide industry support
- Not controlled by a single entity that could change or abandon the format
Flexibility and Extensibility
- Directory structures can be organized according to user preference
- Metadata in YAML headers can evolve over time without breaking backward compatibility
- New features can be added without rendering old files unusable
Searchable
- Plain text is easily searchable using standard system tools or simple scripts
- No need for specialized databases that might become obsolete
Data Sovereignty
- Users maintain complete control over their data
- No dependence on cloud services that may change terms or shut down
Resilient Against Software Evolution
- Even as the application evolves through its three phases (CLI → GUI → web), the underlying data format remains consistent
- Allows for migration to newer systems without data loss
This approach creates a foundation that can withstand technological change, ensuring that notes remain accessible regardless of future software and hardware developments.