Local-first tender ingestion, deterministic sector classification, optional LLM filtering, and multi-channel notification.
- Development Status
- Overview
- Technical Assessment
- Key Features
- Processing Pipeline
- Supported Sources
- System Architecture
- Installation
- Configuration
- Kullanım Kılavuzu ve Ekranlar
- Sorun Giderme (Troubleshooting)
- Testing And Build
- Current Limitations
- Project Documentation
- Contributing
- License
Tender Tracker is operational for local, self-managed use and can be used on your own machine with your own configuration and provider credentials. The project remains under active development.
Yatırımlar Dergisi, DMO, ilan.gov.tr, and EKAPv2 adapters provide the main ingestion paths. Reliability, security hardening, packaging, and source compatibility work continue between releases.
Kullanım notu: Uygulama mevcut çalışan kaynaklarla kendi bilgisayarınızda bağımsız olarak kullanılabilir. Geliştirme devam ettiği için iş açısından kritik sonuçların kaynak kayıtları ve uygulama logları üzerinden doğrulanması önerilir.
Tender Tracker is not a hosted procurement service and does not provide centrally managed API credentials. Users operate the application locally and are responsible for their own source access, provider keys, notification accounts, backups, and usage decisions.
Tender Tracker collects public tender listings from multiple Turkish procurement sources, normalizes the incoming records, removes irrelevant listings through deterministic rules, assigns relevant opportunities to user-defined sectors, and optionally evaluates them through user-defined Large Language Model filters.
The application is intended for technical sales, presales, engineering, business development, procurement, and market-intelligence workflows where users repeatedly inspect multiple tender portals and need a reusable local filtering process.
Core design goals:
- keep tender data and configuration on the user's computer;
- perform cheap deterministic filtering before optional LLM calls;
- allow sector and prompt rules to be changed without rewriting source adapters;
- preserve a searchable local tender history;
- deliver relevant records through dashboard, email, or Telegram;
- remain usable without an LLM provider.
Tender Tracker has evolved from a single-purpose scraping script into a modular local application with clear source, classification, persistence, API, frontend, and notification boundaries.
Each procurement source is represented by its own adapter. Source-specific request, parsing, and normalization behavior is kept outside the core classification and notification flow. A failure or markup change in one source can therefore be investigated without redesigning the entire application.
SQLite, YAML configuration, and event logs are stored locally. The project does not require a Tender Tracker cloud account or a centrally operated backend. Optional external calls are limited to enabled tender sources, the user's selected LLM provider, SMTP, and Telegram.
Global exclusion rules and sector keyword rules are evaluated before optional LLM work. This keeps common decisions fast, inspectable, and available when no API key is configured.
Gemini, OpenAI-compatible providers, and Anthropic Claude can be configured by the user. LLM use is optional and is used for user-defined semantic filters scoped to one sector or all sectors.
FastAPI, the local dashboard, SQLite storage, configuration files, and the Windows tray integration can be distributed as a portable executable. GitHub Actions provides automated tests and tag-based Windows release builds.
The project should be understood as an operational local application under active development, not as a finished enterprise procurement platform.
- The HTTP source adapters use normal synchronous request flows coordinated by application workers; this is not a fully asynchronous crawler fleet.
- The dashboard supports manual ingestion triggers. CLI utilities also expose one-shot and daemon-style execution; lifecycle unification between source execution and packaged desktop operation remains an engineering work item.
- Database re-evaluation currently re-runs custom LLM filters on stored, already classified tenders. It does not represent a complete re-ingestion or universal reclassification of every rule layer.
- SQLite WAL mode improves local read/write concurrency but does not eliminate every possible locking or transaction failure.
- Source portals remain external dependencies. A portal can change its HTML, API route, TLS policy, rate limits, or availability without notice.
Critical hardening work is tracked in business/BOARD.md; deferred productization and infrastructure work is preserved in business/NOTES.md rather than hidden behind a production-ready claim.
- Yatırımlar Dergisi HTML listings;
- DMO active tender listings;
- ilan.gov.tr public JSON requests;
- EKAPv2 public connection adapter using signed API headers;
- duplicate detection before repeated processing;
- normalized source, title, summary, link, and classification fields.
- global exclusion keywords;
- sector-specific positive and negative keywords;
- local deterministic sector assignment;
- custom LLM filters targeted to selected sectors;
- stored-tender re-evaluation for custom LLM prompt changes.
Supported provider families:
- Google Gemini;
- OpenAI and compatible chat-completions endpoints;
- Anthropic Claude.
Provider use is optional. The application remains functional with local rules only.
- first-run administrator setup;
- local login and protected API routes;
- tender, source, sector, and custom-filter views;
- general, LLM, sector, notification, and security settings;
- operational log viewer;
- eight persisted interface themes;
- lightweight notification dots for new tenders and warnings.
- sector-grouped HTML email reports over SMTP;
- Telegram Bot API notifications;
- automatic splitting of long Telegram messages;
- local delivery-state fields for stored tenders.
- PyInstaller Windows executable;
- Windows system-tray integration;
- automated test workflow;
- tag-based Windows build and GitHub Release upload.
flowchart TD
A[Public Tender Sources] --> B[Source Adapters]
B --> C{Already Stored?}
C -->|Yes| X[Skip Duplicate]
C -->|No| D{Global Exclusion Match?}
D -->|Yes| E[(Store as Excluded)]
D -->|No| F[Local Sector Rules]
F -->|Matched| H[Sector Assigned]
F -->|No Match| J[Unclassified]
H --> K[Sector-Scoped Custom LLM Filters]
K --> L[(SQLite)]
J --> L
L --> M[Dashboard (All Tenders)]
L --> N{Has Sector & Not Excluded?}
N -->|Yes| O[Optional Notifications<br/>(Email & Telegram)]
N -->|No| P[Dashboard Only]
The processing contract follows these rules:
- Unclassified Tenders: Tenders that do not match any positive local sector rules are stored in the database and shown on the dashboard only. They do not trigger LLM calls or send notifications.
- Custom LLM Filters: User-defined semantic filters run only on tenders that have been successfully mapped to a sector via local rules.
- Notifications: Email and Telegram notifications are dispatched only for records that are mapped to a valid sector and are not marked as
Excluded(no notifications are sent for unclassified or excluded tenders).
The practical execution order is:
source ingestion
→ normalization and duplicate check
→ global exclusions
→ deterministic sector classification
→ optional sector-scoped custom LLM filters
→ SQLite persistence
→ dashboard / email / Telegram (filtered by sector presence)
No fixed token-saving percentage is claimed. Actual savings depend on source volume, rule coverage, selected sectors, prompt design, and provider behavior.
| Source | Integration | Sync Strategy | Current Status |
|---|---|---|---|
| Yatırımlar Dergisi | HTML parsing | Snapshot of current homepage | Operational |
| Devlet Malzeme Ofisi (DMO) | HTML parsing | Current active listings parser | Operational |
| ilan.gov.tr | JSON API | Paged request of current listings | Operational |
| EKAPv2 | Signed JSON API | Initial crawl of open tenders, then stateful incremental sync | Operational |
The intended EKAP scope is limited to publicly accessible tender listings that can be read without account login, e-signature, or private-session automation.
The current adapter extracts public tender records by querying the public search API of EKAP v2 with custom signed security headers.
Authenticated pages, e-signature flows, CAPTCHA bypass, private account automation, and restricted procurement data are outside the project scope.
flowchart TD
subgraph UI["🖥️ Presentation Layer"]
Dashboard["Local SPA Dashboard<br/>(Setup / Login / Logs / Configuration)"]
end
subgraph API["🔌 API Layer"]
FastAPI["FastAPI App<br/>(Local Auth & REST Endpoints)"]
end
subgraph Core["⚙️ Application Services"]
Orchestrator["Scheduler & Orchestrator"]
Classifier["Deterministic Sector Classifier<br/>& Custom LLM Filters"]
LLMClient["LLM Provider Client"]
end
subgraph Adapters["🔌 Adapters"]
Sources["Source Adapters<br/>(Yatırımlar, DMO, ilan.gov.tr, EKAPv2)"]
Notifiers["Output Adapters<br/>(Dashboard, SMTP Email, Telegram)"]
end
subgraph Data["💾 Data Layer"]
DB["SQLite Database (SQLAlchemy ORM)"]
YAML["YAML Settings (config.yaml, sectors.yaml)"]
Logs["Local Logs (events.log)"]
end
Dashboard -->|HTTP Requests / JSON| FastAPI
FastAPI -->|Direct Invocation| Orchestrator
Orchestrator -->|Evaluate Rules| Classifier
Classifier -->|API Requests| LLMClient
Orchestrator -->|Fetch Feeds| Sources
Orchestrator -->|Push Alerts| Notifiers
Orchestrator & FastAPI & Classifier -->|Read/Write| DB
Orchestrator & FastAPI & Classifier -->|Read/Write| YAML
Orchestrator & FastAPI & Classifier -->|Append| Logs
tender-tracker/
├── .github/workflows/ # Test and tagged release workflows
├── business/ # Active board, decisions, and history
├── screenshots/ # Dashboard and configuration captures
├── src/
│ ├── scraper/ # Source-specific adapters
│ ├── notifier/ # Email and Telegram adapters
│ ├── classifier.py # Local sector rules and custom LLM filter evaluation
│ ├── database.py # SQLite and SQLAlchemy models
│ ├── filter.py # Exclusion and sector rules
│ ├── llm_client.py # Provider abstraction
│ ├── scheduler.py # Ingestion orchestration
│ └── tray.py # Windows tray integration
├── static/ # Local single-page dashboard
├── app.py # FastAPI application and desktop web entry
├── run.py # CLI ingestion utilities
├── build.py # PyInstaller build script
├── config.yaml # Local runtime configuration
├── sectors.yaml # Sector definitions and keyword rules
├── AGENTS.md # Agent and contributor working rules
└── README.md
| Layer | Technology | Purpose |
|---|---|---|
| Backend | Python 3.12, FastAPI | Local API and application server |
| Persistence | SQLite, SQLAlchemy | Tender, user, and delivery state |
| Scraping | Requests, BeautifulSoup | Public HTML and JSON ingestion |
| Classification | Local rules, optional LLM APIs | Sector and semantic filtering |
| Frontend | HTML, CSS, vanilla JavaScript | Local single-page dashboard |
| Notifications | SMTP, Telegram Bot API | Optional tender delivery |
| Packaging | PyInstaller, PyStray | Portable Windows application |
| CI/CD | GitHub Actions | Tests, Windows build, release asset |
- Open the repository's Releases page.
- Download the latest
tender-tracker.exerelease asset. - Place the executable in a folder where your Windows user has write permission.
- Run the executable.
- If Windows SmartScreen displays a warning, review the publisher information and use More info → Run anyway only when you downloaded the file from the expected repository release.
- Complete the first-run administrator setup in the browser.
Portable runtime files are created beside the executable. Keep tenders.db, config.yaml, sectors.yaml, and events.log when replacing or moving the executable.
# Clone the repository
git clone https://github.com/isikmuhamm/tender-tracker.git
cd tender-tracker
# Create a virtual environment
python -m venv .venv
# Windows
.venv\Scripts\activate
# Linux/macOS
source .venv/bin/activate
# Install dependencies
python -m pip install --upgrade pip
pip install -r requirements.txt
# Start the local dashboard
python app.pyOpen http://127.0.0.1:8000 if the browser does not open automatically.
The compiled executable tender-tracker.exe (or the Python script run.py) can be executed directly as a command-line tool. This allows headless execution, perfect for setting up a daily automated task in Windows Task Scheduler.
--once: Runs a single ingestion cycle (fetches new tenders, saves them, sends notifications) and exits.- Exit Codes:
0on complete success,2on partial success (some scrapers or notifiers failed), and1on exceptions or critical failures.
- Exit Codes:
--stats: Prints the current local database statistics (total scanned, excluded, classified, unclassified, and distribution per sector/source) and exits immediately with code0(or1on error).--daemon: Runs continuously as a background process, sleeping and running scans at the configured interval (for Python execution).
To set up a daily automatic scan task using the Windows Task Scheduler:
- Create a new Basic Task and set the trigger to daily (e.g., 9:00 AM).
- Set the action to Start a Program.
- In Program/script, specify the absolute path to the compiled executable:
C:\path\to\tender-tracker.exe - In Add arguments (optional), enter:
--once - In Start in (optional), enter the directory containing the executable (e.g.,
C:\path\to\). ÖNERİLEN:Start inalanına EXE klasörünü yazmak önerilir ancak paketlenmiş uygulama runtime dosyalarını (config.yaml,sectors.yaml,tenders.db) her zaman EXE’nin bulunduğu klasörde arar.
To compile the single portable Windows executable yourself, run:
python build.pyThe generated file is written to:
dist/tender-tracker.exe
Tip
Yedekleme ve Güncelleme Önerisi (Backup Advice): Yeni bir sürüme geçmeden önce runtime dosyalarını (tenders.db, config.yaml, sectors.yaml) yedeklemeniz önerilir. Projede henüz sürümlendirilmiş otomatik bir veritabanı migrasyon sistemi bulunmadığından, özellikle şema/yapı değişikliği getiren ana güncellemelerde release notlarını ve uyumluluk yönergelerini kontrol etmeniz faydalı olacaktır.
The dashboard writes application settings to local YAML files after authentication.
- local server port;
- enabled source adapters;
- scan interval value;
- active LLM provider;
- selected visual theme.
- global exclusion keywords;
- enabled sectors;
- sector positive keywords;
- sector negative keywords;
- custom LLM filters;
- target sector for each custom filter.
Users provide their own credentials locally. Tender Tracker does not operate a shared provider account or hosted key vault.
Recommended practice:
- use a dedicated provider key with an appropriate usage limit;
- do not commit populated configuration files;
- do not include API keys in screenshots, logs, or bug reports;
- revoke and replace a key if it is accidentally exposed.
- SMTP server, port, sender, username/password, and recipients;
- Telegram bot token and target chat ID.
| Service | URL | Description |
|---|---|---|
| Dashboard | http://127.0.0.1:8000/ |
Local application interface |
| API Docs | http://127.0.0.1:8000/docs |
Interactive FastAPI documentation |
| OpenAPI | http://127.0.0.1:8000/openapi.json |
Machine-readable API schema |
POST /api/auth/setup Create the first local administrator
POST /api/auth/login Obtain a local access token
POST /api/auth/change-password Change administrator credentials
GET /api/tenders List and filter stored tenders
POST /api/tenders/trigger Start a manual ingestion cycle
POST /api/tenders/re-evaluate Re-run custom LLM filters on stored tenders
GET /api/config Read local configuration
POST /api/config Save local configuration
GET /api/models List available provider models
GET /api/logs Read recent local event logs
Bu bölüm uygulamayı ilk kez çalıştıran kullanıcılar için temel kullanım sırasını ve arayüz panellerini açıklar.
- Uygulamayı yazma izniniz olan bir klasörde çalıştırın.
- İlk yönetici hesabını oluşturun.
- Genel Ayarlar bölümünden kullanılacak kaynakları seçin.
- Sektörler ve Filtreler bölümünde kendi ilgi alanlarınızı tanımlayın.
- LLM kullanacaksanız sağlayıcı ve model ayarını yapın; kullanmayacaksanız
none/pasif durumda bırakın. - İhtiyaç varsa özel LLM süzgeçleri oluşturun.
- E-posta veya Telegram bildirimlerini yapılandırın.
- Otomatik Tarama: Uygulama açıldığında otomatik tarama arka planda kendiliğinden başlatılır.
- Manuel Tarama: İhtiyaç duyduğunuzda, Aktif İhaleler ekranından manuel tarama butonunu kullanarak anlık ek tarama tetikleyebilirsiniz.
- Beklenmeyen sonuç veya kaynak hatalarında Sistem Logları ekranını kontrol edin.
Uygulama ilk çalıştırıldığında yerel yönetici hesabı oluşturulur. Girilen şifre düz metin olarak saklanmaz; uygulamanın kimlik doğrulama mekanizması için parola özeti kaydedilir.
- kullanıcı adını ve şifreyi güvenli bir yerde saklayın;
- uygulama varsayılan olarak yalnız yerel
127.0.0.1adresinde kullanılmalıdır; - veritabanını silmek kullanıcı ve tender kayıtlarını da etkileyebilir; işlem öncesinde yedek alın.
Bu panel yerel veritabanına kaydedilen ihale kayıtlarının ana görünümüdür.
Buradan:
- kaynak, sektör ve özel filtre sonuçlarını görebilir;
- kayıtları filtreleyebilir;
- yeni bir manuel tarama başlatabilir;
- yeni ihale bildirim noktasını takip edebilirsiniz.
Bir kaynakta ihale görülmesine rağmen panelde görünmüyorsa önce küresel yasaklı kelimeleri, sektör kurallarını ve sistem loglarını kontrol edin.
Bu bölüm uygulamanın çalışma ve sağlayıcı ayarlarını içerir.
Başlıca ayarlar:
- sunucu portu;
- etkin kaynak adaptörleri;
- tarama aralığı;
- etkin LLM sağlayıcısı;
- sağlayıcı modeli ve API anahtarı;
- arayüz teması.
LLM anahtarı girmeden de küresel ve sektörel yerel filtreler kullanılabilir. LLM devre dışı olduğunda özel semantik süzgeçler çalıştırılmaz; yerel sektör sınıflandırması çalışmaya devam eder.
Arayüz sekiz farklı renk paleti sunar. Tema tercihi yerel yapılandırmaya kaydedilir ve sonraki açılışlarda korunur.
Tema seçimi yalnız sunumu etkiler; ihale toplama, sınıflandırma veya bildirim davranışını değiştirmez.
Özel süzgeçler, sektör sınıflandırmasından sonra daha dar bir iş ihtiyacını semantik olarak değerlendirmek için kullanılır.
Örnek kullanım alanları:
- yalnız sinyalizasyon veya raylı sistem projelerini ayırma;
- belirli ürün, hizmet veya teknoloji ihtiyacını arama;
- genel bir sektörde satış açısından uygun fırsatları işaretleme;
- bir süzgeci yalnız seçilen sektörde çalıştırarak gereksiz provider çağrılarını azaltma.
Yeniden Değerlendir işlemi mevcut veritabanındaki uygun kayıtlar üzerinde özel LLM süzgeçlerini tekrar çalıştırır. Bu işlem web sitelerini yeniden taramakla veya tüm sektör sınıflandırmasını sıfırdan yapmakla aynı değildir.
Yerel sınıflandırmanın ana yönetim ekranıdır.
- Küresel yasaklı kelimeler: bütün sektörlerden önce değerlendirilir ve istenmeyen kayıtları eler.
- Pozitif sektör kelimeleri: bir ihalenin ilgili sektöre atanmasına katkı sağlar.
- Negatif sektör kelimeleri: yanlış pozitif eşleşmeleri azaltır.
- Etkin/pasif sektörler: kullanılmayan sınıfların işlem hattından çıkarılmasını sağlar.
Kurallar çok geniş yazılırsa ilgisiz sonuçlar; çok dar yazılırsa kaçırılan fırsatlar oluşabilir. İlk kullanımda küçük bir kelime kümesiyle başlayıp gerçek sonuçlara göre ayarlamak daha güvenlidir.
Bu ekranda isteğe bağlı bildirim kanalları yapılandırılır.
- SMTP sunucusu ve portu;
- gönderici hesabı;
- kimlik doğrulama bilgileri;
- alıcı adresleri.
Bazı e-posta sağlayıcıları normal hesap şifresi yerine uygulama parolası ister.
- BotFather üzerinden alınan bot token;
- mesaj gönderilecek kullanıcı, grup veya kanalın chat ID değeri;
- grup/kanal kullanımında botun gönderim izni.
Bildirim ayarları eksik olduğunda ihale toplama işlemi yine çalışabilir; ayrıntı için sistem loglarını kontrol edin.
Yerel yönetici kimlik bilgileri bu bölümden değiştirilir.
- mevcut bilgileri doğrulayın;
- yeni parolayı güvenli biçimde saklayın;
- değişiklik sonrası tekrar giriş yapmanız gerekebilir;
- doğrudan veritabanı dosyasını değiştirmeyin.
Log ekranı kaynak istekleri, parser sonuçları, sınıflandırma adımları, LLM hataları, bildirim sonuçları ve uygulama uyarıları için ilk kontrol noktasıdır.
Bir hata bildirirken mümkünse:
- ilgili zaman aralığını;
- kullanılan kaynak adını;
- hata mesajını;
- uygulama sürümünü;
- kişisel anahtarları ve parolaları çıkardığınız log kesitini
paylaşın.
PyInstaller ile üretilen ve ticari kod imzalama sertifikası taşımayan bağımsız executable dosyalarında Windows uyarı gösterebilir.
- dosyayı yalnız beklediğiniz GitHub Release sayfasından indirdiğinizi doğrulayın;
- release checksum yayımlanmışsa karşılaştırın;
- More info / Daha fazla bilgi → Run anyway / Yine de çalıştır kararını yalnız kaynağa güveniyorsanız verin;
- üçüncü taraf sitelerden alınan executable dosyalarını kullanmayın.
Tarayıcıyı manuel açın:
http://127.0.0.1:8000
Port değiştirilmişse yeni portu kullanın. Uygulamanın terminal veya events.log çıktısında başlatma hatası olup olmadığını kontrol edin.
Varsayılan port 8000 başka bir uygulama tarafından kullanılıyorsa:
- uygulamayı kapatın;
- dashboard üzerinden daha önce kaydettiğiniz portu veya
config.yamliçindekisettings.server_portdeğerini değiştirin; - örneğin
8085gibi boş bir port seçin; - uygulamayı yeniden başlatın.
Yeni adres örneği:
http://127.0.0.1:8085
Şunları sırayla kontrol edin:
- Kaynak adaptörü etkin mi?
- İnternet bağlantısı ve kaynak sitesi erişilebilir mi?
- Manuel tarama gerçekten başlatıldı mı?
- Küresel yasaklı kelimeler çok geniş mi?
- Sektör pozitif kelimeleri aşırı dar mı?
events.logveya Sistem Logları kaynak/parsing hatası gösteriyor mu?- Test edilen kaynak EKAP mı? İlk EKAP taraması mevcut açık ihaleleri topladığı için sonraki taramalardan daha uzun sürebilir. Sonraki taramalar son başarılı tarama tarihinden itibaren artımlı (incremental) çalışır.
Bu çoğunlukla kaynak portalın HTML/API yapısının değiştiğini veya geçici erişim problemi olduğunu gösterir. Adapter'lar bağımsız olduğu için çalışan kaynakların sonuçları devam edebilir.
Hata bildirirken kaynak adını ve kişisel veri içermeyen log satırlarını ekleyin.
- aktif sağlayıcının doğru seçildiğini;
- API anahtarının geçerli olduğunu;
- seçilen modelin sağlayıcı hesabınızda kullanılabildiğini;
- kota veya rate-limit hatası bulunmadığını;
- custom filter hedef sektörünün doğru olduğunu;
- ihalenin yerel kurallarla bir sektöre atanmış olduğunu (süzgeçler yalnız sektöre atanmış ihalelerde çalışır)
kontrol edin.
Özel LLM süzgeci veya bağlantısı başarısız olsa veya devre dışı bırakılsa bile yerel kural tabanlı sınıflandırma ve dashboard kayıtları çalışmaya devam eder.
- SMTP host ve portu;
- TLS/SSL beklentisini;
- kullanıcı adı ve gönderici adresini;
- uygulama parolası gereksinimini;
- alıcı adreslerini;
- spam klasörünü;
- loglardaki authentication veya connection hatalarını
kontrol edin.
- bot token değerini;
- chat ID değerini;
- botun gruba/kanala eklenmiş olduğunu;
- gönderim iznini;
- botun engellenmediğini;
- Telegram API hata kodlarını
kontrol edin.
Portable kullanımda aşağıdaki runtime dosyalarını birlikte taşıyın:
tender-tracker.exe
tenders.db
config.yaml
sectors.yaml
events.log
Taşıma öncesinde uygulamayı kapatın. Özellikle tenders.db dosyasını çalışan süreç sırasında kopyalamak tutarsız yedek oluşturabilir.
- Uygulamayı kapatın.
- Runtime dosyalarının yedeğini alın.
- Eski executable dosyasını yeni sürümle değiştirin.
tenders.db,config.yamlvesectors.yamldosyalarını koruyun.- Uygulamayı açıp logları ve temel ekranları kontrol edin.
Database schema değişen sürümlerde release notlarını okuyun. Otomatik migration ve auto-update desteği proje geliştirme planında ayrıca izlenmektedir.
# Run the complete test suite
python -m pytest -q
# Build the portable executable
python build.pyThe GitHub Actions workflow runs automated tests on repository changes. Tags matching v* trigger a Windows build and upload dist/tender-tracker.exe to the corresponding GitHub Release.
External procurement sites should not be required for the default deterministic unit-test suite. Parser tests should use stored fixtures, while live-source smoke checks should remain explicit and opt-in.
- The product targets one local administrator rather than multi-user collaboration.
- The executable does not update itself automatically.
- Dashboard updates use REST polling rather than WebSocket delivery.
- Source HTML, JSON endpoints, and access policies may change without notice.
- The current scheduler and desktop lifecycle still require further unification and hardening.
- Local YAML credentials are a deliberate BYO-provider design; users are responsible for file access and backups.
- Log rotation, schema migration, notification retry state, and release smoke testing remain active engineering items.
The repository separates public product documentation from active engineering memory:
AGENTS.md— working rules and engineering boundaries;business/BOARD.md— active priorities and acceptance criteria;business/NOTES.md— product and architecture decisions;business/HISTORY.md— completed implementation history.
README claims should follow the verified runtime state documented by these files.
- Fork the repository.
- Create a focused branch:
git checkout -b feature/your-change. - Read the relevant item in
business/BOARD.mdand matching decision inbusiness/NOTES.md. - Keep changes limited to one reviewable work item.
- Add or update behavior tests.
- Run
python -m pytest -q. - Update documentation when runtime behavior changes.
- Open a pull request.
Tender Tracker is available under the MIT License.
The software is provided without a hosted-service warranty. Review the source, release notes, configuration, and local operating environment before using it in a business-critical workflow.
Muhammet Işık