add app specification
This commit is contained in:
@@ -0,0 +1,282 @@
|
||||
# Specification: Translation Dictionary for Living Christianity
|
||||
|
||||
## Overview
|
||||
|
||||
"Sanasto Wiki" is a web-based dictionary application for simultaneous translators in the living Christianity. The application provides publicly accessible translations while restricting editing and commenting to invited contributors.
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### Supported languages
|
||||
We currently support the following languages:
|
||||
* Finnish
|
||||
* English
|
||||
* Swedish
|
||||
* Norwegian
|
||||
* Russian
|
||||
* German
|
||||
|
||||
### Entry
|
||||
An entry represents a translatable unit which may be:
|
||||
|
||||
- `word` — Single word
|
||||
- `phrase` — Multi-word expression or idiom, sentence
|
||||
- `name` — Person's name (for consistent transliteration)
|
||||
- `title` — Book, publication, or hymn title
|
||||
- `reference` — Biblical or doctrinal term
|
||||
- `other` — Any other translatable text unit
|
||||
|
||||
Each entry has translations in multiple languages.
|
||||
|
||||
### Suggested Meaning
|
||||
When translators disagree on a translation or want to suggest alternatives (regional variations, contextual meanings, etc.), they can submit a suggested meaning for community review.
|
||||
|
||||
## Technical Stack
|
||||
|
||||
* Framework: Rails 8
|
||||
* Database: SQLite with FTS5
|
||||
* Authentication: Rails 8 built-in authentication
|
||||
* Authorization: Invitation-only for contributors
|
||||
* Deployment: Kamal
|
||||
|
||||
---
|
||||
|
||||
## Database Schema
|
||||
```
|
||||
# db/schema.rb
|
||||
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_01_22_100000) do
|
||||
create_table "entries", force: :cascade do |t|
|
||||
t.integer "category", null: false # word, phrase, name, title, reference, other
|
||||
|
||||
# Language columns
|
||||
t.string "fi" # Finnish
|
||||
t.string "en" # English
|
||||
t.string "sv" # Swedish
|
||||
t.string "no" # Norwegian
|
||||
t.string "ru" # Russian
|
||||
t.string "de" # German
|
||||
|
||||
t.text "notes"
|
||||
t.boolean "verified", default: false
|
||||
t.integer "created_by_id"
|
||||
t.integer "updated_by_id"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
|
||||
t.index ["category"], name: "index_entries_on_category"
|
||||
end
|
||||
|
||||
create_table "suggested_meanings", force: :cascade do |t|
|
||||
t.integer "entry_id", null: false
|
||||
t.string "language_code", null: false
|
||||
t.string "alternative_translation", null: false
|
||||
t.text "context"
|
||||
t.text "reasoning"
|
||||
t.string "source"
|
||||
t.string "region"
|
||||
t.integer "status", default: 0 # pending, accepted, rejected
|
||||
t.integer "submitted_by_id"
|
||||
t.integer "reviewed_by_id"
|
||||
t.datetime "reviewed_at"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
|
||||
t.index ["entry_id"], name: "index_suggested_meanings_on_entry_id"
|
||||
t.index ["language_code"], name: "index_suggested_meanings_on_language_code"
|
||||
t.index ["status"], name: "index_suggested_meanings_on_status"
|
||||
end
|
||||
|
||||
create_table "comments", force: :cascade do |t|
|
||||
t.integer "user_id", null: false
|
||||
t.string "commentable_type", null: false
|
||||
t.integer "commentable_id", null: false
|
||||
t.text "body", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
|
||||
t.index ["commentable_type", "commentable_id"], name: "index_comments_on_commentable"
|
||||
end
|
||||
|
||||
create_table "users", force: :cascade do |t|
|
||||
t.string "email", null: false
|
||||
t.string "password_digest", null: false
|
||||
t.string "name"
|
||||
t.integer "role", default: 0 # contributor, reviewer, admin
|
||||
t.string "primary_language"
|
||||
t.string "invitation_token"
|
||||
t.datetime "invitation_sent_at"
|
||||
t.datetime "invitation_accepted_at"
|
||||
t.integer "invited_by_id"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
|
||||
t.index ["email"], name: "index_users_on_email", unique: true
|
||||
t.index ["invitation_token"], name: "index_users_on_invitation_token", unique: true
|
||||
end
|
||||
|
||||
create_table "entry_versions", force: :cascade do |t|
|
||||
t.integer "entry_id", null: false
|
||||
t.integer "user_id", null: false
|
||||
t.json "changes_made", null: false
|
||||
t.string "change_type" # create, update, verify
|
||||
t.datetime "created_at", null: false
|
||||
|
||||
t.index ["entry_id"], name: "index_entry_versions_on_entry_id"
|
||||
end
|
||||
|
||||
create_table "supported_languages", force: :cascade do |t|
|
||||
t.string "code", null: false
|
||||
t.string "name", null: false
|
||||
t.string "native_name", null: false
|
||||
t.integer "sort_order", default: 0
|
||||
t.boolean "active", default: true
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
|
||||
t.index ["code"], name: "index_supported_languages_on_code", unique: true
|
||||
end
|
||||
|
||||
add_foreign_key "suggested_meanings", "entries"
|
||||
add_foreign_key "suggested_meanings", "supported_languages", column: "language_code", primary_key: "code"
|
||||
add_foreign_key "suggested_meanings", "users", column: "submitted_by_id"
|
||||
add_foreign_key "suggested_meanings", "users", column: "reviewed_by_id"
|
||||
add_foreign_key "comments", "users"
|
||||
add_foreign_key "entries", "users", column: "created_by_id"
|
||||
add_foreign_key "entries", "users", column: "updated_by_id"
|
||||
add_foreign_key "entry_versions", "entries"
|
||||
add_foreign_key "entry_versions", "users"
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Initial Data
|
||||
|
||||
Found in 'Kristillisyyden sanasto ver 23.5.2013.xlsx'
|
||||
|
||||
---
|
||||
|
||||
## User Roles & Permissions
|
||||
|
||||
| Action | Public | Contributor | Reviewer | Admin |
|
||||
|--------|--------|-------------|----------|-------|
|
||||
| View entries | ✓ | ✓ | ✓ | ✓ |
|
||||
| Search entries | ✓ | ✓ | ✓ | ✓ |
|
||||
| Create entry | | ✓ | ✓ | ✓ |
|
||||
| Edit entry | | ✓ | ✓ | ✓ |
|
||||
| Add comment | | ✓ | ✓ | ✓ |
|
||||
| Submit suggested meaning | | ✓ | ✓ | ✓ |
|
||||
| Review suggested meanings | | | ✓ | ✓ |
|
||||
| Mark entry as verified | | | ✓ | ✓ |
|
||||
| Invite new users | | | | ✓ |
|
||||
| Manage users | | | | ✓ |
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
### Public Features
|
||||
|
||||
**Search & Browse**
|
||||
- Full-text search across all languages
|
||||
- Filter by category
|
||||
- Alphabetical browsing per language
|
||||
- View entry with all translations
|
||||
- Download the entries table as an XLSX file, without :id attribute
|
||||
|
||||
### Contributor Features
|
||||
|
||||
**Entry Management**
|
||||
- Create new entries with translations in known languages
|
||||
- Edit existing translations
|
||||
- Leave empty translations for others to fill in
|
||||
- Add notes/context to entries
|
||||
- View edit history
|
||||
|
||||
**Discussion**
|
||||
- Add comments to entries
|
||||
- Submit alternative translations as suggested meanings
|
||||
- Participate in translation discussions
|
||||
|
||||
### Reviewer Features
|
||||
|
||||
**Quality Control**
|
||||
- Review and approve/reject suggested meanings
|
||||
- Mark entries as verified
|
||||
- Merge duplicate entries
|
||||
|
||||
### Admin Features
|
||||
|
||||
**User Management**
|
||||
- Send invitations via email
|
||||
- Assign/change user roles
|
||||
- Deactivate users
|
||||
|
||||
**System Management**
|
||||
- Bulk import/export (CSV)
|
||||
- Database backup
|
||||
|
||||
---
|
||||
|
||||
## Supported Languages
|
||||
|
||||
Initial seed data:
|
||||
|
||||
| Code | Name | Native Name | Sort Order |
|
||||
|------|------|-------------|------------|
|
||||
| fi | Finnish | Suomi | 1 |
|
||||
| en | English | English | 2 |
|
||||
| sv | Swedish | Svenska | 3 |
|
||||
| no | Norwegian | Norsk | 4 |
|
||||
| de | German | Deutsch | 5 |
|
||||
| ru | Russian | Русский | 6 |
|
||||
|
||||
---
|
||||
|
||||
## User Interface
|
||||
|
||||
### Pages
|
||||
|
||||
1. **Home/Search** — Search box, quick stats, recent entries
|
||||
2. **Browse** — Alphabetical listing with language tabs
|
||||
3. **Entry View** — Single entry with all translations, comments, suggested meanings
|
||||
4. **Entry Edit** — Form for editing translations (contributors only)
|
||||
5. **New Entry** — Form for creating entries (contributors only)
|
||||
6. **Suggested Meanings Queue** — List for reviewers
|
||||
7. **User Profile** — Personal settings, contribution history
|
||||
8. **Admin Dashboard** — User management, invitations, stats
|
||||
|
||||
### Design Principles
|
||||
- Clean, readable typography (translations must be easy to read quickly)
|
||||
- Mobile-friendly (translators may use during services)
|
||||
- Fast search (primary use case)
|
||||
- Clear visual distinction between verified and unverified entries
|
||||
|
||||
---
|
||||
|
||||
## API (Optional Future)
|
||||
|
||||
REST API for potential mobile app or integration:
|
||||
```
|
||||
GET /api/entries
|
||||
GET /api/entries/:id
|
||||
GET /api/entries/search?q=:query&lang=:code
|
||||
POST /api/entries (authenticated)
|
||||
PATCH /api/entries/:id (authenticated)
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
Server: Single VPS with Kamal
|
||||
Database: SQLite with Litestream for replication/backup
|
||||
Assets: Propshaft (Rails 8 default)
|
||||
Background Jobs: Solid Queue (for invitation emails)
|
||||
|
||||
|
||||
## Future Considerations
|
||||
|
||||
Export to PDF/print format for offline use
|
||||
Audio pronunciation recordings
|
||||
Mobile app
|
||||
Offline mode with sync
|
||||
Additional languages via migration
|
||||
Reference in New Issue
Block a user