diff --git a/sk1/Dockerfile b/sk1/Dockerfile
new file mode 100644
index 0000000..5437e7e
--- /dev/null
+++ b/sk1/Dockerfile
@@ -0,0 +1,9 @@
+FROM python:3.11-slim
+WORKDIR /app
+COPY requirements.txt .
+RUN pip install --no-cache-dir -r requirements.txt
+COPY . .
+RUN useradd -m appuser && chown -R appuser /app
+USER appuser
+EXPOSE 5000
+CMD ["gunicorn", "--workers", "2", "--bind", "0.0.0.0:5000", "--timeout", "60", "--access-logfile", "-", "app:app"]
diff --git a/sk1/app.py b/sk1/app.py
new file mode 100644
index 0000000..9b3d7f2
--- /dev/null
+++ b/sk1/app.py
@@ -0,0 +1,329 @@
+"""TaskFlow — Flask task management application."""
+import os
+import psycopg2
+import psycopg2.extras
+from flask import Flask, request, redirect, url_for, render_template_string, jsonify
+
+app = Flask(__name__)
+
+def get_db():
+ return psycopg2.connect(
+ host=os.environ.get("POSTGRES_HOST"),
+ port=int(os.environ.get("POSTGRES_PORT", 5432)),
+ user=os.environ["POSTGRES_USER"],
+ password=os.environ["POSTGRES_PASSWORD"],
+ dbname=os.environ["POSTGRES_DB"],
+ sslmode="require"
+ )
+
+@app.route("/health")
+def health():
+ try:
+ conn = get_db(); conn.close()
+ return jsonify({"status": "ok"}), 200
+ except Exception as e:
+ return jsonify({"status": "error", "detail": str(e)}), 500
+
+TEMPLATE = """
+
+
+
+
+ TaskFlow
+
+
+
+
+
+
+
+
+
+
+
+
+ {% for col,label,css,icon in [
+ ('todo','To Do','col-todo','◯'),
+ ('in_progress','In Progress','col-progress','▶'),
+ ('done','Done','col-done','✓')] %}
+
+
+
+ {% if tasks[col] %}
+ {% for t in tasks[col] %}
+
+
{{t.title}}
+ {% if t.description %}
{{t.description}}
{% endif %}
+
+
+ {% endfor %}
+ {% else %}
+
+ {% endif %}
+
+
+ {% endfor %}
+
+
+
+"""
+NEXT_STATUS = {"todo": "in_progress", "in_progress": "done"}
+
+@app.route("/")
+def index():
+ conn = get_db()
+ cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
+ cur.execute("SELECT * FROM tasks ORDER BY created_at")
+ rows = cur.fetchall()
+ cur.close(); conn.close()
+ tasks = {"todo": [], "in_progress": [], "done": []}
+ for row in rows:
+ tasks[row["status"]].append(row)
+ return render_template_string(TEMPLATE, tasks=tasks)
+
+@app.route("/create", methods=["POST"])
+def create():
+ title = request.form.get("title", "").strip()
+ desc = request.form.get("description", "").strip()
+ if title:
+ conn = get_db(); cur = conn.cursor()
+ cur.execute(
+ "INSERT INTO tasks (title, description, status) VALUES (%s, %s, 'todo')",
+ (title, desc or None))
+ conn.commit(); cur.close(); conn.close()
+ return redirect(url_for("index"))
+
+@app.route("/advance/", methods=["POST"])
+def advance(task_id):
+ conn = get_db(); cur = conn.cursor()
+ cur.execute("SELECT status FROM tasks WHERE id = %s", (task_id,))
+ row = cur.fetchone()
+ if row and row[0] in NEXT_STATUS:
+ cur.execute("UPDATE tasks SET status = %s WHERE id = %s",
+ (NEXT_STATUS[row[0]], task_id))
+ conn.commit()
+ cur.close(); conn.close()
+ return redirect(url_for("index"))
+
+@app.route("/delete/", methods=["POST"])
+def delete(task_id):
+ conn = get_db(); cur = conn.cursor()
+ cur.execute("DELETE FROM tasks WHERE id = %s", (task_id,))
+ conn.commit(); cur.close(); conn.close()
+ return redirect(url_for("index"))
+
+if __name__ == "__main__":
+ app.run(host="0.0.0.0", port=5000, debug=False)
\ No newline at end of file
diff --git a/sk1/init.sql b/sk1/init.sql
new file mode 100644
index 0000000..2543620
--- /dev/null
+++ b/sk1/init.sql
@@ -0,0 +1,27 @@
+CREATE TABLE IF NOT EXISTS tasks (
+ id SERIAL PRIMARY KEY,
+ title VARCHAR(200) NOT NULL,
+ description TEXT,
+ status VARCHAR(20) NOT NULL DEFAULT 'todo'
+ CHECK (status IN ('todo', 'in_progress', 'done')),
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
+);
+
+CREATE OR REPLACE FUNCTION update_updated_at()
+RETURNS TRIGGER AS $$
+BEGIN NEW.updated_at = NOW(); RETURN NEW; END;
+$$ LANGUAGE plpgsql;
+
+DROP TRIGGER IF EXISTS set_updated_at ON tasks;
+CREATE TRIGGER set_updated_at
+ BEFORE UPDATE ON tasks
+ FOR EACH ROW EXECUTE FUNCTION update_updated_at();
+
+INSERT INTO tasks (title, description, status) VALUES
+ ('Set up Azure resources', 'Create App Service and PostgreSQL Flexible Server', 'done'),
+ ('Build Docker image', 'Push image to Azure Container Registry', 'done'),
+ ('Configure App Service', 'Set environment variables and container settings', 'in_progress'),
+ ('Enable HTTPS', 'Built-in on azurewebsites.net — automatic', 'todo'),
+ ('Write README', 'Document deployment and cost analysis', 'todo')
+ON CONFLICT DO NOTHING;
diff --git a/sk1/requirements.txt b/sk1/requirements.txt
new file mode 100644
index 0000000..14f28ad
--- /dev/null
+++ b/sk1/requirements.txt
@@ -0,0 +1,3 @@
+flask==3.0.3
+gunicorn==21.2.0
+psycopg2-binary==2.9.9