Designing a Reliable Application Model: Why I Chose Snapshot Fields Over Full Duplication
When I started building the Application model for my Placement Portal, I thought it would be one of the simplest models in the project.
All I needed was:
- A reference to the student
- A reference to the job
- Application status
created_atupdated_at
It looked complete.
Then I started building the Application Details page, and I realized something important.
The model wasn't representing the application—it was representing the current state of the database.
The Real Problem
Suppose a student applies for a Software Engineer role today.
A week later, the recruiter updates the job description, changes the salary, or edits the location.
If the Application page simply follows the foreign key to the Job model, the student no longer sees the job they applied for.
They see the job as it exists today.
The same issue applies to student information.
If a student changes their phone number or email address, the application suddenly reflects information that wasn't part of the original submission.
That made me rethink the entire design.
An application should be a historical record.
Three Possible Approaches
Option 1: Never Allow Job Updates
One possible solution is to make job posts immutable after publication.
This would preserve the original job details.
However, it doesn't solve the student side of the problem. Students can still update their profile, and recruiters may legitimately need to edit details such as application deadlines or correct mistakes in a posting.
Option 2: Duplicate Everything
The second option is to copy every field from both the Job and Student models into the Application model.
This guarantees historical accuracy.
The downside is maintainability.
Every time the Job or Student model changes, the Application model also needs to be reviewed and potentially updated.
Over time, the duplication becomes difficult to manage.
Option 3: Store Only the Required Snapshot
This is the approach I chose.
Instead of copying every field, I store only the information required to represent the application accurately.
For example, I snapshot values such as:
- Job title
- Job description
- Job location
- Salary
- Student email
- Student phone number
- Student WhatsApp number
The Application model still keeps foreign keys to the current Job and Student records, allowing the system to navigate to the latest entities when appropriate, while preserving the essential information that existed when the application was submitted.
For the current MVP, this provides a practical balance between historical accuracy and maintainability.
Recognizing the Trade-Offs
I don't consider this solution perfect.
There are still trade-offs.
In my experience using platforms such as Internshala, job postings are rarely edited after publication. More commonly, only application deadlines change.
That means snapshot fields may never be needed for many applications.
However, software architecture should also consider edge cases, especially those that could affect historical records.
Thinking About Deletion
Another consideration is deletion behavior.
At the moment, my relationships use CASCADE.
If a Student or Job record is deleted, the corresponding applications would also be removed.
In practice, I don't expect users to be permanently deleted.
Instead, I plan to follow the approach used by many enterprise systems and social platforms: deactivate accounts instead of deleting them.
Keeping historical user records preserves recruitment history, simplifies future reactivation, and avoids unnecessary data loss.
If permanent deletion ever becomes a requirement, I may revisit this decision and evaluate alternatives such as soft deletion or changing the foreign key behavior to PROTECT or SET_NULL, depending on the business rules.
Final Thoughts
This experience reminded me that database design isn't just about defining relationships.
It's about preserving the meaning of data over time.
Sometimes a model that looks perfectly normalized doesn't capture the business reality.
For my Placement Portal MVP, storing a carefully selected snapshot alongside foreign keys gives me a good balance between historical accuracy, storage efficiency, and maintainability.
I'm documenting every architectural decision while building this Placement Portal in public.
I'd love to hear how you would approach this problem. Would you rely solely on foreign keys, store complete snapshots, or choose a different strategy altogether?